新建测试类BeanAutoAssembleConfigTest,增加方法isSameBean()判断PersonService中使用@Autowire装配的PersonDao和从容器中获取的PersonDao对象是否为同一个对象,
public class BeanAutoAssembleConfitTest { @Test public void isSameBean(){ ApplicationContext context = new AnnotationConfigApplicationContext(BeanAutoAssembleConfig.class); System.out.println("IoC容器初始化完成"); String[] beanDefinitionNames = context.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { System.out.println(beanDefinitionName); } PersonDao personDaoFromCon = (PersonDao) context.getBean("personDao"); PersonService personService = (PersonService) context.getBean("personService"); PersonDao personDaoFromAuto = personService.getBeanByAutowire(); if (personDaoFromCon == personDaoFromAuto){ System.out.println("@Autowire自动装配的Bean和从容器中获取的Bean是同一个Bean"); } else { System.out.println("@Autowire自动装配的Bean和从容器中获取的Bean 不是 同一个Bean"); } } } 复制代码
控制台打印如下,说明@Autowire装配的Bean和容器中的Bean是同一个Bean
在BeanAutoAssembleConfig中使用@Bean标签再注入一个PersonDao
@ComponentScan(basePackages = {"com.citi.dao","com.citi.service","com.citi.controller"}) public class BeanAutoAssembleConfig { @Bean("personDao2") public PersonDao personDao(){ return new PersonDao(); } } 复制代码
在测试方法中,用从容器中获取bean 的name为personDao2的Bean,与PersonService的@Autowire的Bean进行比较
public class BeanAutoAssembleConfitTest { @Test public void isSameBean(){ ApplicationContext context = new AnnotationConfigApplicationContext(BeanAutoAssembleConfig.class); System.out.println("IoC容器初始化完成"); String[] beanDefinitionNames = context.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { System.out.println(beanDefinitionName); } PersonDao personDaoFromCon = (PersonDao) context.getBean("personDao2"); PersonService personService = (PersonService) context.getBean("personService"); PersonDao personDaoFromAuto = personService.getBeanByAutowire(); System.out.println(personDaoFromCon); System.out.println(personDaoFromAuto); if (personDaoFromCon == personDaoFromAuto){ System.out.println("@Autowire自动装配的Bean和从容器中获取的Bean是同一个Bean"); } else { System.out.println("@Autowire自动装配的Bean和从容器中获取的Bean 不是 同一个Bean"); } } } 复制代码
执行测试方法,控制台打印出不是同一个Bean,即persongDao2与personDao不是同一个Bean
@Autowire默认装配的Bean的类型装配的,如果需要指定的Bean进行自动装配则要使用@Qualifier("personDao2")指定Bean的name,修改PersonService类
@Service public class PersonService { // 自动装配的Bean personDao @Qualifier("personDao2") @Autowired private PersonDao personDao; public PersonDao getBeanByAutowire(){ return personDao; } } 复制代码
再次执行测试类,控制台打印出是同一个Bean
@Resource与@Autowire可以起到相同的作用,不同的是@Resource默认是按照Bean的name导入的 修改PersonService,使用@Resource注入,这里PersonDao的bean name为personDao2
@Service public class PersonService { // 自动装配的Bean personDao //@Qualifier("personDao") //@Autowired @Resource private PersonDao personDao2; public PersonDao getBeanByAutowire(){ return personDao2; } } 复制代码
执行测试类,控制台打印如下
因为测试方法中从容器中获取的是bean name为personDao2的Bean,与PersonService装配的Bean为同一个Bean,可以确定@Resource是按照Bean的name来装配的,@Resource不支持@Primary, 当容器中不存在Bean时,使用@Autowire注解可以声明request=false,这时不会报错,而@Resource不支持request=false
@Resource装配顺序:
- 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
- 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
- 如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
- 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
@Primary注解是作用在配置类上的,在注入Bean的方法上增加@Primary注解,当@Qualifier()与@Primary同时存在时,@Qulifier注解的功能不受影响 修改配置类如下,优先注入personDao2这个Bean
@ComponentScan(basePackages = {"com.citi.dao","com.citi.service","com.citi.controller"}) public class BeanAutoAssembleConfig { @Primary @Bean("personDao2") public PersonDao personDao(){ return new PersonDao(); } } 复制代码
PersonService类代码修改如下,指定装配的Bean name为personDao
@Service public class PersonService { // 自动装配的Bean personDao @Qualifier("personDao") @Autowired //@Resource private PersonDao personDao2; public PersonDao getBeanByAutowire(){ return personDao2; } } 复制代码
测试类代码如下,增加从容器中根据类型获取Bean的方法
public class BeanAutoAssembleConfitTest { @Test public void isSameBean(){ ApplicationContext context = new AnnotationConfigApplicationContext(BeanAutoAssembleConfig.class); System.out.println("IoC容器初始化完成"); String[] beanDefinitionNames = context.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { System.out.println(beanDefinitionName); } PersonDao personDaoFromCon = (PersonDao) context.getBean("personDao2"); PersonService personService = (PersonService) context.getBean("personService"); PersonDao personDaoFromAuto = personService.getBeanByAutowire(); System.out.println(personDaoFromCon); System.out.println(personDaoFromAuto); if (personDaoFromCon == personDaoFromAuto){ System.out.println("@Autowire自动装配的Bean和从容器中获取的Bean是同一个Bean"); } else { System.out.println("@Autowire自动装配的Bean和从容器中获取的Bean 不是 同一个Bean"); } PersonDao bean = context.getBean(PersonDao.class); System.out.println(bean.getClass().getName()); } } 复制代码
控制台正常打印,连个注解没有冲突@Qualifier执行装配的Bean的name
如果此时将@Primary注释,再次执行测试类,控制台报错
No qualifying bean of type 'com.citi.dao.PersonDao' available: expected single matching bean but found 2: personDao,personDao2,没有@Primary注解,根据类型获取Bean的时候就会报错,因为有两个Bean,容器并不知道你要的是哪一个
Section 03 - @Inject
使用@Inject注解要导入相应的maven依赖
<dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency> 复制代码
将PersonService中的@Autowire注解注释,使用@Inject注解,注释掉测试方法中注释掉根据类型获取PersonDao对象的代码,然后执行测试,同样可以装配Bean
@Resource和@Inject都是JSR250规范,@Autowire是属于Spring的注解。