解决自动装配问题
如果Spring容器中拥有多个匹配UserService类型的Bean,由于Spring没有足够的信息做出取舍决策,因此会抛出 UnsatisfiedDependencyException异常。假设我们采用以下传统的事务管理的配置方式对UserService进行配置,按类 型匹配的自动装配机制就会引发问题:
①用于被代理的目标Bean,按类型匹配于UserService
调整配置文件,使按类型匹配于UserService的Bean仅有一个,具体有以下两个方法:
将①处的Bean作为②处的内部Bean进行装配;
使用基于注解驱动的事务管理配置机制,这样就无需在配置文件中定义两个UserService的Bean了。关于注解驱动事务管理配置的详细信息,请参见9.6小节的内容。
改变DependencyInjectionCtxTest的自动装配机制:Spring默认使用byType类型的自动装配机制,但它允许你通过 setAutowireMode()的方法改变默认自动装配的机制,比如你可以调用setAutowireMode(AUTOWIRE_BY_NAME) 方法启用按名称匹配的自动装配机制。AbstractDependencyInjectionSpringContextTests定义了三个代表自动装 配机制类型的常量,分别说明如下:
AUTOWIRE_BY_TYPE:按类型匹配的方式进行自动装配,这个默认的机制;
AUTOWIRE_BY_NAME:按名字匹配的方式进行自动装配
AUTOWIRE_NO:不使用自动装配机制,这意味着你需要手工调用getBean()进行装配。
现在我们解决了在自动装配时,因Spring容器中存在多个匹配Bean而导致的问题,接下来让我们考察另一个自动装配的问题。
依赖检查
假设我们在DependencyInjectionCtxTest添加一个User类型的属性并提供Setter方法,而Spring容器中没有匹配该属性的Bean:
仔细思考一下,这种运行机制并非没有道理,因为既然你已经提供了Setter方法,就相当于给出了这样的暗示信息: “这个属性测试类自身创建不了,必须由外部提供”。而在使用自动装配机制的情况下,测试类属性自动从Spring容器中注入匹配的属性,一般情况下不会手 工去调用Setter方法准备属性。
如果你出于一些特殊的理由,希望在采用自动装配的情况下,如果有属性未得到装配也不在乎,那么你可以在测试类构造函数中调用setDependencyCheck(false)方法达到目的:
如果Spring容器中拥有多个匹配UserService类型的Bean,由于Spring没有足够的信息做出取舍决策,因此会抛出 UnsatisfiedDependencyException异常。假设我们采用以下传统的事务管理的配置方式对UserService进行配置,按类 型匹配的自动装配机制就会引发问题:
①用于被代理的目标Bean,按类型匹配于UserService
<bean id="userServiceTarget" class="com.baobaotao.service.UserServiceImpl">②通过事务代理工厂为UserServiceImpl创建的代理Bean,也按匹配于UserService
<property name="userDao" ref="userDao" />
<property name="loginLogDao" ref="loginLogDao">property>
bean>
<bean id="userService"由于①处和②处的Bean都按类型匹配于UserService,在对DependencyInjectionCtxTest的userService属性进行自动装配将会引发问题。有两种针对该问题的解决办法:
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="userServiceTarget" />
<property name="transactionAttributes">
…
property>
bean>
调整配置文件,使按类型匹配于UserService的Bean仅有一个,具体有以下两个方法:
将①处的Bean作为②处的内部Bean进行装配;
使用基于注解驱动的事务管理配置机制,这样就无需在配置文件中定义两个UserService的Bean了。关于注解驱动事务管理配置的详细信息,请参见9.6小节的内容。
改变DependencyInjectionCtxTest的自动装配机制:Spring默认使用byType类型的自动装配机制,但它允许你通过 setAutowireMode()的方法改变默认自动装配的机制,比如你可以调用setAutowireMode(AUTOWIRE_BY_NAME) 方法启用按名称匹配的自动装配机制。AbstractDependencyInjectionSpringContextTests定义了三个代表自动装 配机制类型的常量,分别说明如下:
AUTOWIRE_BY_TYPE:按类型匹配的方式进行自动装配,这个默认的机制;
AUTOWIRE_BY_NAME:按名字匹配的方式进行自动装配
AUTOWIRE_NO:不使用自动装配机制,这意味着你需要手工调用getBean()进行装配。
现在我们解决了在自动装配时,因Spring容器中存在多个匹配Bean而导致的问题,接下来让我们考察另一个自动装配的问题。
依赖检查
假设我们在DependencyInjectionCtxTest添加一个User类型的属性并提供Setter方法,而Spring容器中没有匹配该属性的Bean:
package com.baobaotao.test;猜想一下重新运行DependencyInjectionCtxTest将会发生什么情况呢?答案可能让你失望: UnsatisfiedDependencyException再次象黑幕一样降临。在默认情况下, AbstractDependencyInjectionSpringContextTests要求所有属性都能在Spring容器中找到对应Bean, 否则抛出异常。
…
import com.baobaotao.domain.User;
public class DependencyInjectionCtxTest extends AbstractDependencyInjectionSpringContextTests {
private User user;
public void setUser(User user) {
this.user = user;
}
…
}
仔细思考一下,这种运行机制并非没有道理,因为既然你已经提供了Setter方法,就相当于给出了这样的暗示信息: “这个属性测试类自身创建不了,必须由外部提供”。而在使用自动装配机制的情况下,测试类属性自动从Spring容器中注入匹配的属性,一般情况下不会手 工去调用Setter方法准备属性。
如果你出于一些特殊的理由,希望在采用自动装配的情况下,如果有属性未得到装配也不在乎,那么你可以在测试类构造函数中调用setDependencyCheck(false)方法达到目的:
package com.baobaotao.test;这个AbstractDependencyInjectionSpringContextTests就不会对测试类有些属性找不到匹配Bean而抛出异常了。
…
public class DependencyInjectionCtxTest extends AbstractDependencyInjectionSpringContextTests {
public DependencyInjectionCtxTest(){
setDependencyCheck(false); ①告知不进行属性依赖性检查
}
…
}