spring为了方便我们完成bean注入相关的配置工作,提供了自动注入功能,我们只需要按照其规则来进行配置,就能够让spring注入我们需要的bean了。
public class State {
private String stateName;
...snip...
}
public class Country {
// generate setters...
private State state; // secondary type
public void setState(State state) {
this.state = state;
}
// print injected value on the console log
public void display() {
System.out.println("State name is: " + state.getStateName());
}
}
这也是默认的自动注入的方式,即不使用自动注入
,这种方式需要我们显示的在配置文件中通过<property>
标签然后通过ref
属性来设置,这也是默认的自动注入方式。
<?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="state" class="yudaosourcecode.autowiretest.State"/>
<bean id="country"
class="yudaosourcecode.autowiretest.Country"
autowire="no">
<property name="state" ref="state"/>
</bean>
</beans>
@Test
public void test_autowire_no() {
ClassPathXmlApplicationContext ac
= new ClassPathXmlApplicationContext("autowiretest/test-autowire-no.xml");
System.out.println(ac.getBean("country", Country.class).getState());
}
运行:
yudaosourcecode.autowiretest.State@42607a4f
Process finished with exit code 0
这种方式是通过属性的类型,来进行自动注入。
<?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="state" class="yudaosourcecode.autowiretest.State"/>
<bean id="country"
class="yudaosourcecode.autowiretest.Country"
autowire="byType">
</bean>
</beans>
可以看到此时就不需要通过<property>
标签来配置了。
@Test
public void test_autowire_bytype() {
ClassPathXmlApplicationContext ac
= new ClassPathXmlApplicationContext("autowiretest/test_autowire_bytype.xml");
System.out.println("autowire byType: ");
System.out.println(ac.getBean("country", Country.class).getState());
}
运行:
autowire byType:
yudaosourcecode.autowiretest.State@646007f4
Process finished with exit code 0
但是当相同类型的bean有多个的时候byType
的方式就不适用了,因为无法确定到底注入哪个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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="state" class="yudaosourcecode.autowiretest.State"/>
<bean id="state1" class="yudaosourcecode.autowiretest.State"/>
<bean id="country"
class="yudaosourcecode.autowiretest.Country"
autowire="byType"/>
</beans>
再次运行程序:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating
bean with name 'country' defined in class path resource
[autowiretest/test_autowire_bytype.xml]:
Unsatisfied dependency expressed through bean property 'state'; nested exception is
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying
bean of type 'yudaosourcecode.autowiretest.State' available:
expected single matching bean but found 2: state,state1
出现这个异常的原因就是,相同类型的bean有两个,无法确定是哪个,即候选者bean有多个,为了解决这个问题,spring提供了autowire-candidate
属性,代表在自动注入时是否作为候选bean,默认值是true,这里我们可以将其中一个设置为false,修改配置文件为如下:
<?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="state" class="yudaosourcecode.autowiretest.State"/>
<bean id="state1" class="yudaosourcecode.autowiretest.State" autowire-candidate="false"/>
<bean id="country"
class="yudaosourcecode.autowiretest.Country"
autowire="byType"/>
</beans>
再次运行程序,就可以正常完成注入了:
autowire byType:
yudaosourcecode.autowiretest.State@646007f4
Process finished with exit code 0
不使用autowire-candidate
的话也可以使用primary
来指定首选bean,即设置一个优先级最高的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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="state" class="yudaosourcecode.autowiretest.State" primary="true"/>
<bean id="state1" class="yudaosourcecode.autowiretest.State"/>
<bean id="anotherState"
class="yudaosourcecode.autowiretest.AnotherState"/>
<bean id="country"
class="yudaosourcecode.autowiretest.Country"
autowire="byType"
lazy-init="true"/>
</beans>
这种是通过属性的名称来作为目标bean的名称来完成自动注入,因为是通过名称,而spring的bean名称是不允许重复的,因此这种情况下相同类型的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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="state" class="yudaosourcecode.autowiretest.State"/>
<bean id="state1" class="yudaosourcecode.autowiretest.State"/>
<bean id="country"
class="yudaosourcecode.autowiretest.Country"
autowire="byName"/>
</beans>
@Test
public void test_autowire_byname() {
ClassPathXmlApplicationContext ac
= new ClassPathXmlApplicationContext("autowiretest/test_autowire_byname.xml");
System.out.println("autowiretest/autowire byname: ");
System.out.println(ac.getBean("country", Country.class).getState());
}
运行:
autowiretest/autowire byname:
yudaosourcecode.autowiretest.State@43a0cee9
Process finished with exit code 0
byType
,byName
都是自动完成属性的注入,这里的constructor
是自动完成构造函数的自动注入。
定义一个构造函数使用state作为参数。
public class Country {
private State state; // secondary type
public Country(State state) {
this.state = state;
}
// print injected value on the console log
public void display() {
System.out.println("State name is: " + state.getStateName());
}
}
<?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="state" class="yudaosourcecode.autowiretest.State"/>
<bean id="country"
class="yudaosourcecode.autowiretest.Country"
autowire="constructor"/>
</beans>
@Test
public void test_autowire_constructor() {
ClassPathXmlApplicationContext ac
= new ClassPathXmlApplicationContext("autowiretest/test_autowire_constructor.xml");
System.out.println("by constructor: ");
System.out.println(ac.getBean("country"));
}
构造函数的自动注入,在寻找目标bean的时候,默认使用的是byType
,因此当目标bean有多个时候,同样会出现异常,此时也是可以通过autowire-candidate
属性来解决,这里不再演示了,和4:autowire->byType
中的情况是一致的。
各种类型说明如下表:
autowire类型 | 注入方式 | 注入目标 |
---|---|---|
no | 不自持自动注入,需要通过标签 <property>或者<constructor>配置 | 依配置决定 |
byType | 根据类型注入 | bean属性 |
byName | 根据名称注入 | bean属性 |
constructor | 根据类型注入 | 构造函数参数 |