到现在为止,已经学习了利用xml文件来配置javabean,对于只包含少量Bean的应用来说,这非常棒。但是随着应用的不断增大,我们将要编写越来越复制的XML配置,只就违反了 Spring 用来简化java开发的初衷。所幸,Spring提供了自动装配的机制。
ByName自动装配
在xml上下文中,查找与当前Bean属性具有相同名字(id)的其他Bean自动装配到当前bean的对应属性中,如果找不到,则不自动装配。
上面这段话可能难以理解,下面举个具体的例子。在这里,我们将第三篇博客里的GoodMorning的例子拿来修改下。
在这里,我们的GoodMorning类需要注入一个属性名为“hello”的bean,如果“恰好”在xml文件中已经配置好了一个同名的bean,那么可以同过Byname自动装配机制,实现自动装配。
我们只需要做的,就是将自动装配的类型声明为 “byName”。
如上图。如此,即使没有显式的声明 <property name="hello" ref="hello"/> ,在运行的时候,Spring在运行的时候,也会查找xml上下文的bean的id 与要被装配的bean的属性名是否匹配,从而实现自动装配。
尝试运行,
package Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Hello goodMorning =(Hello) context.getBean("goodMorning");
goodMorning.sayHi();
}
}
结果与没有使用自动装配前一致,说明已经成功实现了自动装配。
ByType自动装配
byType自动装配的工作方式和ByName自动装配很类似,只不过不同的是,当我们尝试使用ByType自动装配时,Spring会在XML上下文中寻找一个Bean的类型与属性类型相匹配的Bean,并自动自动装配。
我们先来看看,定义GoodMorning类的时候,hello属性的类型是 Hello
在前面的时候,我们已经知道 HelloSpring类 是实现了Hello接口的一个类,根据java多态的概念,HelloSpring类可以向上转型为Hello类,所以在XML文件查找Hello类型的时候,"helloSpring"是符合条件的,所以就被自动装配到hello属性里了。
下面是运行结果:
但是ByType自动装配有一个局限性:如果Spring在上下文中找到很多符合条件的Bean,它们的类型都与需要自动装配的属性的类型相匹配,自动匹配的是哪一个呢?
我们来试一下:
在这里,我配置了两个相同类型的Bean,然后尝试运行试试看。
没有选择其中一个符合条件的Bean,而且抛出一个异常,异常的说明说得很清楚,期望匹配到一个,却匹配到了很多个。
在这样的情况下,有什么解决的办法呢?有两种思路
1. 标识一个首选Bean, 即将<bean>元素的primary属性设置true,那么该Bean在多个符合条件的候选Bean中将会被首先选择
如: “helloSpring”将会被当成首选Bean
2. 排除某些Bean候选的资格。
如: “hello” 和 “spring” 在自动装配时将会被忽略
Constructor自动装配
上面介绍的两种自动装配的ByName和ByType,都是都通过setter方法注入的,如果要使用构造器注入来配置Bean,那么我们就可以通过Constructor自动装配来移除<constructor-arg>元素。
Constructor自动装配 具有和 ByType 一样的局限性,当在上下文中发现多个Bean匹配构造器的入参时,Spring也会抛出Bean匹配的异常,而不会自动选择。同时,如果一个类有多个构造器,几个构造器同时满足自动装配的条件时,Spring也会直接抛出异常。
最佳自动装配
如果想用自动装配又不确定该用哪一种类型的自动装配的时候,可以将 autowire属性设置成 “autodetect”,由Spring决定。Spring会首先尝试Constructor自动装配,如果没有发现与构造器相匹配的Bean时,Spring将尝试使用ByType自动装配。
默认自动装配
刚刚我们在 配置一个Bean的时候,设置的 autowire属性只对当前Bean有效,即只是当前Bean使用自动装配,如果想让该xml文件里的所有Bean 都使用自动装配,可以使用 default-autowire属性。如果针对某个Bean 显式的设置了其他的装配方式,则该Bean使用其他装配方式,否则默认情况下,使用default-autowire属性设置的自动装配方式