在beans标签中,有一个配置,那他们有什么区别?
default-autowire="byName"
和
default-autowire="byType"
一、byName是什么
byName就是用我们定义的bean的id或name(可看上一篇id和name的区别)来匹配
bean的name有且只有一个,aliases可以有多个
并且bean的name不能重复
二、byType是什么
byType就是使用类的类类型来匹配
这个有些像通过ApplicationContext对象的getBean()方法,一种是传String name,一种是传Class<T> requiredType
三、测试byName
1、applicationContext.xml增加配置
beans标签增加default-autowire="byName"
声明两个测试bean,id为“id.student1”和“id.student2”
<?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: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/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd"
default-autowire="byName">
<!-- 注解bean扫描,spring扫描排除Controller -->
<context:annotation-config />
<context:component-scan base-package="com.study">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<!-- 下面可以导入其他spring配置文件 -->
<import resource="classpath:/spring-env.xml" />
<!-- 下面可以声明bean -->
<bean id="id.student1" name="name.student1" class="com.study.testBean.Student">
<property name="name" value="小明"></property>
<property name="age" value="12"></property>
</bean>
<bean id="id.student2" name="name.student2" class="com.study.testBean.Student">
<property name="name" value="小李"></property>
<property name="age" value="33"></property>
</bean>
</beans>
2、MyTest.java测试类增加注入对象和测试方法
package webapp;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import com.study.testBean.Student;
import com.study.util.ApplicationContextHolder;
import com.study.util.PropertiesUtil;
import com.study.util.ReflectInvokeUtil;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = {"classpath:applicationContext.xml","classpath:spring-mvc.xml"})
@ActiveProfiles("sit")
public class MyTest {
@Value("${flag}")
String flag;
@Autowired
Student stu;
@Test
public void testInvoke() throws Exception {
System.out.println("第一个测试方法*******");
ApplicationContext ac = ApplicationContextHolder.getApplicationContext();
ReflectInvokeUtil.invokeMethod("com.study.testBean.Student", "sayHello", null);
}
@Test
public void testById() {
System.out.println("第二个测试方法*******");
ApplicationContext ac = ApplicationContextHolder.getApplicationContext();
Student stu = (Student)ApplicationContextHolder.getBean("id.student1");
stu.sayHello();
System.out.println("**********");
}
@Test
public void testProperties() {
System.out.println("第三个测试方法*******");
System.out.println("flag is:" + flag);
System.out.println("appName is:" + PropertiesUtil.getProperties("appName"));
}
@Test
public void testAutowired() {
System.out.println("第四个测试方法*******");
stu.sayHello();
System.out.println("**********");
}
}
3、执行testAutowired方法
日志报错:
11:52:01.642 [main] ERROR org.springframework.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@55f3ddb1] to prepare test instance [webapp.MyTest@14bdbc74]
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webapp.MyTest': Unsatisfied dependency expressed through field 'stu'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.study.testBean.Student' available: expected single matching bean but found 2: id.student1,id.student2
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:586)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:364)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1269)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:384)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.study.testBean.Student' available: expected single matching bean but found 2: id.student1,id.student2
at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:173)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1114)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1064)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:583)
... 28 common frames omitted
错误信息为:
No qualifying bean of type 'com.study.testBean.Student' available: expected single matching bean but found 2: id.student1,id.student2
原因:没有匹配到类型com.study.testBean.Student,在spring的context里找到两个相同类型的bean:id.student1和id.student2
疑问:是否Autowired默认使用按类型装配?
4、将id.student2定义注释掉,再次执行testAutowired,这时执行成功:
相关日志:
...
15:52:54.230 [main] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected element of bean 'webapp.MyTest': AutowiredFieldElement for com.study.testBean.Student webapp.MyTest.stu
15:52:54.231 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'id.student1'
15:52:54.231 [main] DEBUG org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'webapp.MyTest' to bean named 'id.student1'
15:52:54.233 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - Before test method: context [DefaultTestContext@7cd62f43 testClass = MyTest, testInstance = webapp.MyTest@14bdbc74, testMethod = testAutowired@MyTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@6d4b1c02 testClass = MyTest, locations = '{classpath:applicationContext.xml, classpath:spring-mvc.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{sit}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.test.context.web.WebDelegatingSmartContextLoader', parent = [null]]], class annotated with @DirtiesContext [false] with mode [null], method annotated with @DirtiesContext [false] with mode [null].
第四个测试方法*******
student say hello. name=小明 age=12
**********
...
5、如何使用指定的名字注入
使用@Qualifier注解指定bean的名字
@Autowired
@Qualifier("id.student2")
Student stu;
再次执行testAutowired,这时执行成功:
相关日志:
...
16:19:57.195 [main] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected element of bean 'webapp.MyTest': AutowiredFieldElement for com.study.testBean.Student webapp.MyTest.stu
16:19:57.196 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'id.student2'
16:19:57.196 [main] DEBUG org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'webapp.MyTest' to bean named 'id.student2'
16:19:57.198 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - Before test method: context [DefaultTestContext@4883b407 testClass = MyTest, testInstance = webapp.MyTest@12591ac8, testMethod = testAutowired@MyTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@7d9d1a19 testClass = MyTest, locations = '{classpath:applicationContext.xml, classpath:spring-mvc.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{sit}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.test.context.web.WebDelegatingSmartContextLoader', parent = [null]]], class annotated with @DirtiesContext [false] with mode [null], method annotated with @DirtiesContext [false] with mode [null].
第四个测试方法*******
student say hello. name=小李 age=33
**********
...
四、测试byType
修改为default-autowire="byType"
重新测试2、3、4、5,结果和byName一致
疑问;是否default-autowire对@Autowired注解没有效果?
小结:
1)@Autowired注解默认按照byType类型装配
2)byType默认使用类的全限定名查找
3)如果需要指定byName,使用@Qualifier注解
五、例子程序
webapp_1.rar
链接: https://pan.baidu.com/s/15sJUYamn6qc8KcFEQXmiiA 提取码: xnjn
参考资料:
http://www.importnew.com/27815.html
https://www.cnblogs.com/think-in-java/p/5474740.html