何为Ioc(Inversion of Control,控制反转)
控制反转是软件工程中面向对象编程的一种设计原则,通过该原理,对象或程序的各部分的控制被转移到容器或框架,可以降低计算机代码的耦合度。
在传统编程中,在需要使用类库或者某个类的时候通常是直接调用;IoC提供了一个框架能够控制程序流并在编程过程中供我们程序自定义调用。为了实现这样一种机制,通过抽象行为构建了这个框架,如果我们想新增自定义行为,我们只需要扩展框架的类或者通过插件的形式来实现自定义行为。
IoC架构的优点
- 将程序的执行与其实现分离
- 可以在不同的实现之间灵活切换
- 使程序更加模块化
- 通过隔离组件使得测试,依赖模拟,组件之间的通信等更加简单
常见的IoC实现机制有:策略设计模式(Strategy design pattern)、服务定位模式(Service Locator pattern)、工厂模式(Factory pattern)、依赖注入(Dependency Injection,DI)
何为DI(Dependency Injection,依赖注入)
依赖注入是实现控制反转思想的一种设计模式,通过对对象依赖的控制实现"反转"。
将对象与其他对象连接或将对象“注入”其他对象的行为由调控系统控制而不是对象本身完成。
Spring的IoC容器
Ioc容器是实现IoC机制的通用特征。
在Spring框架中,ApplicationContext
接口表示的就是Ioc容器,该容器主要负责:实例化,配置,Bean的装载以及它们的声明周期
Spring对ApplicationContext
接口提供了多种实现
ClassPathXmlApplicationContext
FileSystemXmlApplicationContext
WebApplicationContext
为了能够实现了的装载,容器可以通过XML或注解的形式来配置
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Spring的依赖注入
Spring IoC容器会在运行期间读取配置元,然后通过配置组装Bean,Spring的依赖注入可以通过构造函数、Setter方法、实体域来实现
基于构造函数的依赖注入(Constructor-Based Dependency Injection)
容器在实例化bean的时候将调用带有参数的构造函数,每个参数表示我们要设置的依赖项
Spring会解析每个参数,先按类型解析,但有不确定的时候再根据参数名称来解析(通过ParameterNameDiscoverer获取参数名,由ASM实现)
@Service
public class UserService {
private final UserDAO userDAO;
@Autowired
public UserService(UserDAO userDAO) {
this.userDAO = userDAO;
}
基于Setter的依赖注入(Setter-Based Dependency Injection)
Spring先实例化Bean之后调用需要注入的Setter方法,实现注入
@Service
public class UserService {
private UserDAO userDAO;
@Autowired
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
}
基于域的依赖注入(Field-Based Dependency Injection)
Spring在组装Bean的时候,通过构造器和Setter方式之后还会通过Java的方式机制通过写实体域实现注入。
@Service
public class UserService {
@Autowired
private UserDAO userDAO;
}
通过这种方式实现注入看起来更加简单,更加清晰;但是这种方法却不值得提倡,有以下几点原因:
- 这种方法通过方式机制实现依赖注入,相比构造器和Setter的方式需要花费更大的代价(反射性能比较差)
- 通过这种确实很容易实现对多个依赖的注入,但这就相当于你正在使用具有多个参数的构造函数注入,那么该类则违反单一责任原则
依赖自动注入模型
- NO
默认就是NO
,表示不自动装载Bean,必须明确指明依赖
- BY_NAME
基于属性名称自动装载Bean,Spring会根据属性名找到相同Bean注入到需要自动注入的属性
- BY_TYPE
基于属性类型自动装载Bean,和BY_NAME
类似,Spring会根据属性的类型找到合适的Bean注入,如果相同类型的Bean存在多个则会抛出异常
- CONSTRUCTOR
基于构造函数自动自动注入,Spring会更具构造函数的参数找到系相同类型的Bean作为参数实现注入
延时加载Bean
Spring默认在初始过程中对多有的单例Bean进行创建和配置,但是你可以通过lazy-init
属性来阻止这种行为
- XML配置方式
<bean id="foo" class="com.xxx.Foo" lazy-init="true" />
- Annotation配置方式
@Bean
@Lazy
public Foo foo(){
return new Foo();
}
通过延时加载可以在Bean被需要的时候才对其进行实例化,可以加快应用的初始化,但是如果Bean配置有错误的时候只有在使用该Bean的时候才会发现,这时候应用可能已经发布上线,有一定的风险
网友评论