Spring 控制反转和依赖注入
控制反转的类型
控制反转(IOC)旨在提供一种更简单的机制,来设置组件的依赖项,并在整个生命周期管理这些依赖项。通常,控制反转可以分成两种子类型:依赖注入(DI)和依赖查找(DL),这些子类型各自又可以被进一步分解为 IOC 服务的具体实现
1. 依赖查找
1.1 依赖拉取
依赖拉取(Dependency Pull),即根据需要,从注册表中提取依赖项,以下代码显示了基于 Spring 的依赖拉取
public class DependencyPull {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring/app-context.xml");
ctx.getBean("renderer", MessageRenderer.class);
}
}
1.2 上下文依赖查找
上下文依赖查找(contextualized dependency lookup,CDL),同样属于依赖查找的子类型,和依赖拉取有点类似,但在 CDL 中,查找是针对管理资源的容器执行的,这个容器通常由应用程序服务器或框架(Tomcat、JBoss、Spring)提供,比如以下代码显示了一个提供依赖查找服务的容器接口
public interface Container {
// 根据key获取相应的依赖项
Object getDependency(String key);
}
CDL 通过让组件实现以下代码接口来进行工作
public interface ManagedComponent {
void performLookup(Container container);
}
组件需要实现该接口,当容器准备好将依赖项传递给组件时,会依次调用每个组件的 performLookup()
方法,然后组件就可以使用 Container
接口查找所需的依赖项
public class ContextualizedDependencyLookup implements ManagedComponent {
private Dependency dependency;
@Override
public void performLookup(Container container) {
this.dependency = (Dependency) container.getDependency("myDependency");
}
@Override
public String toString() {
return dependency.toString();
}
}
2. 依赖注入
2.1 构造函数注入
当在组件的构造函数中提供依赖项时,就会发生构造函数依赖注入
public class ConstructorInjection {
private Dependency dependency;
public ConstructorInjection(Dependency dependency) {
this.dependency = dependency;
}
@Override
public String toString() {
return dependency.toString();
}
}
2.2 setter 函数注入
Ioc 容器通过 JavaBean 样式的 setter 方法注入组件的依赖项
public class SetterInjection {
private Dependency dependency;
public void setDependency(Dependency dependency) {
this.dependency = dependency;
}
@Override
public String toString() {
return dependency.toString();
}
}
在 Spring 中,还支持另一种被称为字段注入(field injection)的注入类型,在后面学习使用 @Autowire 注解进行自动装配时将介绍该注入类型
Spring 中的控制反转
1. Bean 和 BeanFactory
Spring 的依赖注入容器的核心是 BeanFactory,它负责管理组件,包括依赖项以及它们的生命周期。如果我们想获得一个组件(Bean),就必须创建一个实现了 BeanFactory 接口的实例,并对其进行配置
虽然 BeanFactory 可以通过编程方式配置,但更常见的做法是使用某种配置文件在外部对其进行配置。Bean 配置可以由实现 BeanDefinition 接口的类的实例来表示,对于任何实现了 BeanDefinitionReader 接口的 BeanFactory 实现类来说,都可以使用 PropertiesBeanDefinitionReader 或 XmlBeanDefinitionReader 从配置文件读取 BeanDefinition 数据
定义一组接口:
public interface Oracle {
String output();
}
public class OracleImpl implements Oracle {
@Override
public String output() {
return "hello world";
}
}
接下来我们来看一看,Spring 的 BeanFactory 如何被初始化并用于获取 Bean 实例
public class XmlConfigWithBeanFactory {
public static void main(String[] args) {
// DefaultListableBeanFactory是Spring提供的两个主要BeanFactory实现之一
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader rdr = new XmlBeanDefinitionReader(factory);
// 使用XmlBeanDefinitionReader从XML文件读取BeanDefinition信息
rdr.loadBeanDefinitions(new ClassPathResource("spring/xml-bean-factory-config.xml"));
// 使用在XML配置文件中配置的名称oracle来获取bean
Oracle oracle = (Oracle) factory.getBean("oracle");
System.out.println(oracle.getInfo());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="oracle" name="oracle" class="com.example.OracleImpl"/>
</beans>
ApplicationContext 接口是 BeanFactory 的一个扩展,除了 DI 服务外,还提供其他如事务和 AOP 等服务。在开发基于 Spring 的应用程序时,建议通过 ApplicationContext 接口与 Spring 交互
2. 设置 Spring 配置
2.1 XML 配置
对于 XML 配置,需要声明应用程序需要的由 Spring 提供的名称空间基础信息,下面所示配置仅声明用于定义 bean 的名称空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="provider" class="com.example.HelloWorldMessageProvider"/>
<bean id="render" class="com.example.StandardOutMessageRender"
p:messageProvider-ref="provider"/>
</beans>
2.2 注解配置
要想在应用程序使用 Spring 的注解支持,需要在 XML 配置中声明
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example" />
</beans>
<context:component-scan>
标记告诉 Spring 扫描代码,从而找到 @Component
等注解注入的 bean,以及支持在指定包(及其所有子包)下使用 @Autowire
等注解的 bean
2.3 Java 配置
配置类使用 @Configuration
注解,并包含用 @Bean
注解的方法,这些方法由 IOC 容器直接调用来实例化 bean,bean 名称与用于创建它的方法的名称相同
@Configuration
public class HelloWorldConfiguration {
@Bean
public MessageProvider provider() {
return new HelloWorldMessageProvider();
}
@Bean
public MessageRender render() {
StandardOutMessageRender render = new StandardOutMessageRender();
render.setMessageProvider(provider());
return render;
}
}
如果想从该类中读取配置信息,需要一个不同的 ApplicationContext 实现
public class HelloWorldSpringAnnotated {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx
= new AnnotationConfigApplicationContext(HelloWorldConfiguration.class);
MessageRender render = ctx.getBean("render", MessageRender.class);
render.render();
}
}
3. setter 注入
使用 XML 配置来配置 setter 注入,需要在 <bean>
标记下指定 <property>
标记,为其注入一个依赖项
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="provider" class="com.example.HelloWorldMessageProvider"/>
<bean id="render" class="com.example.StandardOutMessageRender">
<property name="messageProvider" ref="provider"/>
</bean>
</beans>
如果使用注解,只需要向 setter 方法添加一个 @Autowired
注解
@Service("render")
public class StandardOutMessageRender implements MessageRender {
...
@Override
@Autowired
public void setMessageProvider(MessageProvider messageProvider) {
this.messageProvider = messageProvider;
}
}
4. 构造函数注入
public class ConfigurableMessageProvider implements MessageProvider {
private String message;
public ConfigurableMessageProvider(String message) {
this.message = message;
}
@Override
public String getMessage() {
return null;
}
}
使用 XML 方式注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="oracle" name="oracle" class="com.example.OracleImpl"/>
<!-- 使用 <constructor-arg> 标记 -->
<bean id="messageProvider" class="com.example.ConfigurableMessageProvider">
<constructor-arg value="hello world" />
</bean>
<!-- 使用c名称空间 -->
<bean id="provider" class="com.example.ConfigurableMessageProvider"
c:message="hello world"/>
</beans>
使用注解方式
@Service
public class ConfigurableMessageProvider implements MessageProvider {
private String message;
@Autowired
public ConfigurableMessageProvider(
@Value("hello world") String message) {
this.message = message;
}
@Override
public String getMessage() {
return null;
}
}
Spring 控制反转和依赖注入的更多相关文章
- spring 控制反转与依赖注入原理-学习笔记
在Spring中有两个非常重要的概念,控制反转和依赖注入:控制反转将依赖对象的创建和管理交由Spring容器,而依赖注入则是在控制反转的基础上将Spring容器管理的依赖对象注入到应用之中: 所谓依赖 ...
- Spring控制反转与依赖注入(IOC、DI)
IOC: 反转控制 Inverse Of Control DI:依赖注入 Dependency Injection 目的:完成程序的解耦合 解释:在应用系统的开发过程中,有spring负责对象的创 ...
- Spring控制反转(依赖注入)的最简单说明
1.常规方式实现实例化 1.1已有角色如下: 一个接口Interface,两个接口实现类InstatnceA.InstanceB,一个调用类User 1.2当前实例化InstanceA如下: Inte ...
- 对spring控制反转以及依赖注入的理解
一.说到依赖注入(控制反转),先要理解什么是依赖. Spring 把相互协作的关系称为依赖关系.假如 A组件调用了 B组件的方法,我们可称A组件依赖于 B组件. 二.什么是依赖注入. 在传统的程序设计 ...
- 轻松了解Spring中的控制反转和依赖注入(二)
紧接上一篇文章<轻松了解Spring中的控制反转和依赖注入>讲解了SpringIOC和DI的基本概念,这篇文章我们模拟一下SpringIOC的工作机制,使我们更加深刻的理解其中的工作. 类 ...
- 轻松了解Spring中的控制反转和依赖注入(一)
我们回顾一下计算机的发展史,从最初第一台计算机的占地面积达170平方米,重达30吨,到现如今的个人笔记本,事物更加轻量功能却更加丰富,这是事物发展过程中的一个趋势,在技术领域中同样也是如此,企业级Ja ...
- spring学习总结一----控制反转与依赖注入
spring作为java EE中使用最为广泛的框架,它的设计体现了很多设计模式中经典的原则和思想,所以,该框架的各种实现方法非常值得我们去研究,下面先对spring中最为重要的思想之一----控制反转 ...
- 简单了解Spring的控制反转和依赖注入
浅谈控制反转(Inversion of Control,IOC) 我们首先先来了解一下控制二字,也就是在控制"正"转的情况下,在任何一个有请求作用的系统当中,至少需要有两个类互相配 ...
- Spring的控制反转和依赖注入
Spring的官网:https://spring.io/ Struts与Hibernate可以做什么事? Struts, Mvc中控制层解决方案 可以进行请求数据自动封装.类型转换.文件上传.效验… ...
随机推荐
- Golang 常见设计模式之选项模式
熟悉 Python 开发的同学都知道,Python 有默认参数的存在,使得我们在实例化一个对象的时候,可以根据需要来选择性的覆盖某些默认参数,以此来决定如何实例化对象.当一个对象有多个默认参数时,这个 ...
- 微服务架构 | 3.1 Netflix Eureka 注册中心
目录 前言 1. Eureka 基础知识 1.1 Eureka 模型中的服务器与客户端 1.2 Eureka 的 30s 启动机制 1.3 Eureka 为什么注册服务的 IP ,而不是主机名 1.4 ...
- 使用Redis分布式锁控制请求串行处理
1.需求背景 在一些写接口的场景下,由于一些网络因素导致用户的表单重复提交,就会在相邻很短的时间内,发出多个数据一样的请求.后台接口的幂等性保证一般都是先检查数据的状态,然后决定是否进行执行写入操作, ...
- 2月2日 体温APP开发记录
1.阅读构建之法 现代软件工程(第三版) 2.观看Android开发视频教程最新版 Android Studio开发 3.Edit text使用学习
- 【代码分享】用redis+lua实现多个集合取交集并过滤,类似于: select key from set2 where key in (select key from set1) and value>=xxx
redis中的zset结构可以看成一个个包含数值的集合,或者认为是一个关系数据库中用列存储方式存储的一列. 需求 假设我有这样一个数据筛选需求,用SQL表示为: select key from set ...
- Cesium中级教程5 - Terrain 地形
Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ CesiumJS支持对与水流相关的海洋.湖泊和河流以及全球高分辨 ...
- FHQtreap(我有个绝妙的理解方法,但课的时间不够[doge])
FHQtreap板子(P1486 [NOI2004] 郁闷的出纳员) 会了FHQ,treap什么的就忘了吧...... #include<bits/stdc++.h> using name ...
- gorm中的删除
删除 删除一条记录 删除一条记录时,删除对象需要指定主键,否则会触发 批量 Delete,例如: db.Debug().Where("id = ?", 6).Delete(new( ...
- 【Vulnhub靶场】JANGOW: 1.0.1
时隔这么久,终于开始做题了 环境准备 下载靶机,导入到virtualBox里面,这应该不用教了吧 开机可以看到,他已经给出了靶机的IP地址,就不用我们自己去探测了 攻击机IP地址为:192.168.2 ...
- Nginx请求连接限制
目录 Nginx的请求限制 HTTP协议的连接与请求 连接限制 配置示例 做个演示: 请求限制 配置示例 基本指令 limit_req_zone limit_req zone 做个演示: Nginx的 ...