在研究自动装配@Resource和@Autowired的时候,@Autowired注解的装配方式有点疑惑,琢磨了下
首先@Resource是默认是byName,,而@Autowired是默认按byType
那么首先setter方法添加一个@Autowired注解
package com.lihuia.ioc;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Copyright (C), lihuia.com
* FileName: Demo
* Author: lihui
* Date: 2018/7/29
*/
public class Demo {
private Girl girl;
@Autowired
public void setGirl(Girl girl) {
this.girl = girl;
}
public void sayHello() {
System.out.println(girl.getName());
}
}
此时XML里配置如下
<?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="girl" class="com.lihuia.ioc.Girl"></bean>
<bean id="girl1" class="com.lihuia.ioc.Girl"></bean>
<bean id="demo" class="com.lihuia.ioc.Demo"></bean>
</beans>
由于@Autowired是byType的,但是我配置了两个同Type的bean,先以为会报错,因为装配的时候不清楚要选择哪个bean,但是结果却是正常执行,说明了还是能够正常选择某一个bean装配
这时可以做一个简单的测试,修改下@Autowired注解对应的Name
package com.lihuia.ioc;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Copyright (C), lihuia.com
* FileName: Demo
* Author: lihui
* Date: 2018/7/29
*/
public class Demo {
private Girl girl;
@Autowired
public void setGirl(Girl girl1) {
this.girl = girl1;
}
public void sayHello() {
System.out.println(girl.getName());
}
}
这时候还是能够正常执行,继续修改Name
@Autowired
public void setGirl(Girl girl2) {
this.girl = girl2;
}
此时IDEA里girl2变红了,说明有问题了,根据这种测试可以得出:默认@Autowired先匹配byType,假如匹配了多个bean id,那么还会继续匹配byName
这里可以继续做一个简单测试,加一个注解让@Autowired按byName来加载
package com.lihuia.ioc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
/**
* Copyright (C), lihuia.com
* FileName: Demo
* Author: lihui
* Date: 2018/7/29
*/
public class Demo {
private Girl girl;
@Autowired
@Qualifier(value = "girl")
public void setGirl(Girl girl2) {
this.girl = girl2;
}
public void sayHello() {
System.out.println(girl.getName());
}
}
此时运行时正常的,说明假如设置了匹配byName,那么只要Name匹配上了,就直接装配bean
如果将value修改为一个没法匹配上的Name,那么匹配byName无法匹配上,就直接报错不会继续匹配byType了
换成@Resource注解
package com.lihuia.ioc;
import javax.annotation.Resource;
/**
* Copyright (C), lihuia.com
* FileName: Demo
* Author: lihui
* Date: 2018/7/29
*/
public class Demo {
private Girl girl;
@Resource
public void setGirl(Girl girl) {
this.girl = girl;
}
public void sayHello() {
System.out.println(girl.getName());
}
}
由于它默认就是byName,因此直接可以找到bean id,匹配上对应的bean
下面一种情况就比较好玩了,修改Name,使得匹配不上
package com.lihuia.ioc;
import javax.annotation.Resource;
/**
* Copyright (C), lihuia.com
* FileName: Demo
* Author: lihui
* Date: 2018/7/29
*/
public class Demo {
private Girl girl;
@Resource
public void setGirl2(Girl girl2) {
this.girl = girl2;
}
public void sayHello() {
System.out.println(girl.getName());
}
}
此时是没有girl2这个Name的,因此byName是匹配不上的,执行的结果报了一个错误
七月 29, 2018 11:54:50 下午 org.springframework.test.context.support.AbstractTestContextBootstrapper getTestExecutionListeners
信息: Using TestExecutionListeners: [org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@551aa95a, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@35d176f7, org.springframework.test.context.support.DirtiesContextTestExecutionListener@1dfe2924]
七月 29, 2018 11:54:51 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [demo.xml]
七月 29, 2018 11:54:51 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.GenericApplicationContext@52f759d7: startup date [Sun Jul 29 23:54:51 CST 2018]; root of context hierarchy
七月 29, 2018 11:54:51 下午 org.springframework.context.support.AbstractApplicationContext refresh
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'demo': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.lihuia.ioc.Girl' available: expected single matching bean but found 2: girl,girl1
七月 29, 2018 11:54:51 下午 org.springframework.test.context.TestContextManager prepareTestInstance
严重: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@35d176f7] to prepare test instance [com.lihuia.ioc.DemoTest@64729b1e]
倒数第三行,错误信息,匹配byType=Girl的时候,发现了两个bean的类型是Girl导致不知道应该装配哪一个
也就是说默认@Resource注解,如果byName没匹配上,那么就byType来匹配,但是假如有多个bean是目标Type,还是会失败,只有唯一一个Type类型的bean存在,才能装配成功
如果在@Resource注解里指定了name
package com.lihuia.ioc;
import javax.annotation.Resource;
/**
* Copyright (C), lihuia.com
* FileName: Demo
* Author: lihui
* Date: 2018/7/29
*/
public class Demo {
private Girl girl;
@Resource(name = "girl")
public void setGirl(Girl girl) {
this.girl = girl;
}
public void sayHello() {
System.out.println(girl.getName());
}
}
只要是byName匹配上了,就直接根据该bean来装配;假如byName没有匹配上,就没法装配,也不会再按byType来匹配
如果在@Resource注解里指定了type
package com.lihuia.ioc;
import javax.annotation.Resource;
/**
* Copyright (C), lihuia.com
* FileName: Demo
* Author: lihui
* Date: 2018/7/29
*/
public class Demo {
private Girl girl;
@Resource(type = Girl.class)
public void setGirl(Girl girl) {
this.girl = girl;
}
public void sayHello() {
System.out.println(girl.getName());
}
}
如果只指定了Type,那么久只匹配byType,匹配上了就直接装配;假如指定的Type没有匹配上,就没法装配,不会再按byName来匹配
最后如果同时指定Name和Type
package com.lihuia.ioc;
import javax.annotation.Resource;
/**
* Copyright (C), lihuia.com
* FileName: Demo
* Author: lihui
* Date: 2018/7/29
*/
public class Demo {
private Girl girl;
@Resource(name = "girl", type = Girl.class)
public void setGirl(Girl girl) {
this.girl = girl;
}
public void sayHello() {
System.out.println(girl.getName());
}
}
根据上面的例子也能够知道逻辑
byName和byType会同时匹配,必须同时匹配上,才能装配bean,有一个没匹配上就会报错无法装配
综上所述,总结一下:
@Autowired:
默认注解,先匹配byType,如果匹配上了唯一的bean,直接装配;如果匹配上了多个bean,那么继续匹配byName,找到唯一的bean,装配
注解设置name,先匹配byName,如果匹配上了,直接装配;如果byName没匹配上,直接报错,不会继续匹配了
@Resource
默认注解,先匹配byName,如果匹配上了,直接装配;如果byName没匹配上,继续匹配byType,假如有唯一的bean,直接装配;如果byName没匹配上,继续匹配byType,假如有多个bean,失败报错
注解设置name,先匹配byName,如果匹配上了,直接装配;如果byName没匹配上,直接报错,不会继续匹配了
注解设置type,先匹配byType,如果匹配上了,直接装配;如果byType没匹配上,直接报错,不会继续匹配了
注解设置了name和type,同时匹配byName和byType,只有都匹配上了,才能装配;有任意一个没匹配上,直接报错,失败