- 首先解释下什么是自动装配?
基于XML配置元数据,bean中可以使用<constructor-arg/>和<property/>属性来实现Spring的依赖注入。
非自动装配时的spring文件配置如下:
<bean id="HelloWorld" class="test.spring.HelloWord">
<property name="name" value="peter"></property>
<property name="user">
<ref bean="User"/>
</property>
</bean>
类文件如下:
public class HelloWord {
private User user;
private String name;
}
自动装配,对于属性是对象引用的变量,可以采用注解的方式实现,代码如下
public class HelloWord {
@Autowired
private User user;
private String name;
public void setUser(User user) {
this.user = user;
}
}
经测试,setUser方法必需的,否则注入失败,为什么有的网友项目里没有该方法一样注入成功,今后再研究。
更新:spring配置文件中增加如下代码,可以不用setter方法
<context:annotation-config/>
或者
<context:component-scan base-package="test.spring"/>
即:在没有上述context配置项,需要setter方法,且在byType方式下,@Qualifier需要写在setter方法上面,写引用变量上会报错
Error creating bean with name 'distest' defined in class path resource [applicationcontext.xml]: Unsatisfied dependency expressed through bean property 'dislog': : No unique bean of type [test.spring.DiscountLogic] is defined: expected single matching bean but found 3: [lazydis, simdis, dislog]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [test.spring.DiscountLogic] is defined: expected single matching bean but found 3: [lazydis, simdis, dislog]
添加上述context配置项后,setter可要可不要,建议去掉,且在不写setter的byType模式下,即使matching bean大于一个能正常运行,经测试优先通过type匹配,如果匹配数大于1,在通过name匹配。经过对比,其实自动装配只是减少了XML文件配置。把配置都注解到了JAVA代码里。spring3.2官方文档里对此有说法为
“(Default) No autowiring. Bean references must be defined via a ref element.Changing the default setting is not recommended for larger deployments, because specifying collaborators explicitly gives greater control and clarity. To some extent,it documents the structure of a system.”
我的理解,对于大型应用,还是建议使用非自动装配,这样可以更好的理解对象引用关系。
- 什么是byName和byType?
spring3.2官方文档列出5种装配方式:no、byName、byType、constructor和autodetect。
byName,顾名思义就是通过bean的id或name查找类:
XML:
<bean id="dislog" class="test.spring.TimedDiscount"/>
<bean id="distest" class="test.spring.DiscountTest" autowire="byName"/>
JAVA:
public class DiscountTest {
@Autowired
private DiscountLogic dislog;
public void setDislog(DiscountLogic dislog) {
this.dislog = dislog;
}
}
如上代码,spring容器就会去配置文件找name或者id为dislog的bean。
byTpye,顾名思义就是通过bean的class属性或class的父类查找,如果多个bean是相同class或是具有同一父类,就要使用@Qualifier指定具体实现类,其实还是归到了byName查找:
XML: 如下前三个类都实现DiscountLogic接口
<bean id="lazydis" class="test.spring.LazyDiscount"/>
<bean id="simdis" class="test.spring.SimpleDiscount"/>
<bean id="timeddis" class="test.spring.TimedDiscount"/>
<bean id="distest" class="test.spring.DiscountTest" autowire="byType">
JAVA:
public class DiscountTest {
@Autowired
private DiscountLogic dislog;
@Qualifier("simdis")
public void setDislog(DiscountLogic dislog) {
this.dislog = dislog;
}
}
注意,一开始Qualifier注解放在@Autowired下面,运行总是报错,后移动现在位置,运行正常,具体原因后面研究
解决byType匹配多个类报错问题,还有种解决方法,利用Resource注解。Resource是JDK6后支持的方法,需要引入annotations-api包,且配置文件含有上述context配置项。
- Autowire和resource区别
@Autowire 默认按照类型装配,默认情况下它要求依赖对象必须存在如果允许为null,可以设置它required属性为false,如果我们想使用按照名称装配,可 以结合@Qualifier注解一起使用;
@Resource默认按照名称装配,当找不到与名称匹配的bean才会按照类型装配,可以通过name属性指定,如果没有指定name属 性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找 依赖对象.
注意:如果没有指定name属性,并且按照默认的名称仍然找不到依赖的对象时候,会回退到按照类型装配,但一旦指定了name属性,就只能按照名称 装配了.
作者:wuxinliulei
链接:https://www.zhihu.com/question/39356740/answer/80926247
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
附配置代码,粗体字为关键项目
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p">
<bean id="lazydis" class="test.spring.LazyDiscount"></bean>
<bean id="simdis" class="test.spring.SimpleDiscount">
<property name="discountrate" value="80"></property>
</bean>
<bean id="dislog" class="test.spring.TimedDiscount"></bean>
<bean id="distest" class="test.spring.DiscountTest" autowire="byType">
</bean>
<context:annotation-config/>
<context:component-scan base-package="test.spring"/>