Spring IoC 的依赖注入过程,也就是从容器中找到依赖对象、注入到以后对象的过程,叫拆卸。
咱们后面看到的通过 xml 文件的 <constructor-arg> 和 <property> 中的 ref 设置依赖对象的形式,是手动拆卸,因为每一个依赖对象都须要咱们手动配置、通过 ref 指定须要拆卸的具体 bean,而后 Spring 依据咱们的指定来实现拆卸。拆卸好的残缺对象最终能力放入 Spring IoC 容器中供后续应用。
这种形式其实也比较简单实用 — 在类比拟少、依赖关系比较简单的状况下。如果类比拟多、依赖关系比较复杂的话,配置起来就很烦很啰嗦。
为了解决这个问题,Spring 提供了主动拆卸性能。主动拆卸的意思就是,Spring 依据某种拆卸规定主动实现拆卸,不再须要咱们手工配置了。
主动拆卸可能防止臃肿的配置文件,进步开发效率。
主动拆卸应用起来也十分不便。还是应用咱们后面的例子:
<bean id="dependencyB" class="springTest.DependencyB" autowire="byName">
</bean>
<bean id="dependencyA" class="springTest.DependencyA">
</bean>
不须要为 DependencyB 设置指向 dependencyA 的 ref,减少 autowire=byname 的配置,Spring 主动就能够实现拆卸。
应用 xml 的启动类:
public class AppByXML {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("mySpring.xml");
System.out.println("Now start to getbean...");
DependencyB dependencyB = applicationContext.getBean(DependencyB.class);
dependencyB.testB();}
}
执行启动类:
here you call set method...
Now start to getbean...
This is DependencyB's test and ...I am DependencyA test...
配置文件中并没有指定 ref,Spring 能够主动依照规定实现拆卸。
主动拆卸规定
Spring 提供如下 4 种主动拆卸规定:
- no:不执行主动拆卸。这个时候只能手动拆卸了。
- byName:依据属性名实现主动拆卸。Spring 依据以后属性的名字,查找容器中 id 或 name 等于该名字的 Bean 进行拆卸。找不到则不拆卸。
- byType:依据属性的类型实现拆卸。Spring Ioc 容器中该类型的 Bean 多于一个的话,抛异样。
- constructor: 相似 byType,只不过是用在构造方法参数中,为构造方法的参数进行拆卸。
上例中咱们如果把拆卸规定批改为 byType:
<bean id="dependencyB" class="springTest.DependencyB" autowire="byType">
</bean>
<bean id="dependencyA" class="springTest.DependencyA">
</bean>
执行启动类:
here you call set method...
Now start to getbean...
This is DependencyB's test and ...I am DependencyA test...
主动拆卸胜利。
然而如果咱们批改配置,再退出一个 dependencyA 之后:
<bean id="dependencyB" class="springTest.DependencyB" autowire="byType">
</bean>
<bean id="dependencyA" class="springTest.DependencyA">
</bean>
<bean id="dependencyA1" class="springTest.DependencyA">
</bean>
再次执行启动类:
抛出异样 UnsatisfiedDependencyException...
expected single matching bean but found 2: dependencyA,dependencyA1
所以 byType 的状况下,Spring IoC 容器中只能有一个该类型的 Bean 存在,多于一个则抛异样。
主动拆卸的益处和弊病
主动拆卸的益处就是能够简化配置,瘦身臃肿的配置文件,在设计变动后,比方减少或缩小依赖关系的时候不须要执行繁琐的配置文件同步批改工作,极大进步开发人员的效率。
然而主动拆卸也还是存在一些弊病或应用限度,包含:主动拆卸优先级低于手动拆卸,也不能对根底数据类型、Strings、Arrays 等执行主动拆卸。以 byType 进行拆卸的时候,如果容器中存在多个该类型的 Bean 则会抛出异样等等。
然而这些弊病和限度其实是能够无效防止的,根底数据类型只能通过手动的形式进行拆卸,而且理论我的项目开发过程中须要拆卸根底数据类型的场景应该非常少。对于同一个类型存在多个 Bean 的状况,咱们其实在理论利用中应该尽可能通过设置 primary 或 qulifier 指定在拆卸过程中优先拆卸哪一个 Bean,比方下面那个例子:
<bean id="dependencyB" class="springTest.DependencyB" autowire="byType">
</bean>
<bean id="dependencyA" class="springTest.DependencyA">
</bean>
<bean id="dependencyA1" primary="true" class="springTest.DependencyA">
</bean>
指定 primary 之后就没有问题了,最终 dependencyA1 会拆卸到 DependencyB 中。
所有我的项目中其实还是优先应用主动拆卸,因为益处显著多于弊病。
通过注解实现主动拆卸
@Autowired 注解实现主动拆卸,能够作用在属性、办法、结构器上。
作用在属性上实现对该属性的主动拆卸,作用在结构器上、办法上,可主动拆卸结构器或办法参数。
@Autowired 主动拆卸规定:(源码地位 DefaultListableBeanFactory#doResolveDependency)
首先按类型(byType)匹配,匹配过程中会解决 @Quarlifier:查看有 @Quarlifier 设置并且有匹配的 Bean 则返回,否则如果设置了 @Quarlifier 然而没有匹配的 Bean 则抛异样。
匹配后有以下几种状况:
- 没匹配到:@Autowired 注解的参数 required 设置为 true(默认为 true)则抛异样,否则返回 null
- 只匹配到一个 Bean:间接注入
-
匹配到多个:须要进一步判断:
优先查看 @Primary 的 Bean。没有 @Primary 则查看优先级的设置,返回最高优先级的 Bean。
最初查看如果有与以后属性名称匹配的 Bean 则返回,没有的话就表明无奈胜利注入,依据 required 的设置抛异样 (如果设置为 true)或者返回 null( 如果设置为 true)。
@Qulifier 注解针对属性设置:
@Component
public class DependencyB implements IDependencyB{
@Autowired
@Qualifier(value="dependencyA")
private IDependencyA d;
@Primary 注解则针对 Bean 设置,同类型的 Bean 只有一个能够设置为 @Primary,否则在 DI 过程中会报错:
@Service
@Primary
public class DependencyA implements IDependencyA {
@Override
public void test(){System.out.println("I am DependencyA test...");
}
}
上一篇 Spring FrameWork 从入门到 NB – Bean