Spring Framework 源码学习笔记(五)(下)

简介: Spring Framework 源码学习笔记(五)

新建测试类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

be3f16bdc9374f92a928109eeaf6b041_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

在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

56f7475e8c31418f825c0f45c6c68e57_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

@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

7e15a21171094165b6f625bf0ae8c43f_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

@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;
    }
}
复制代码

执行测试类,控制台打印如下

a4c9bc980183468d89f4b6764f3e64b9_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

因为测试方法中从容器中获取的是bean name为personDao2的Bean,与PersonService装配的Bean为同一个Bean,可以确定@Resource是按照Bean的name来装配的,@Resource不支持@Primary, 当容器中不存在Bean时,使用@Autowire注解可以声明request=false,这时不会报错,而@Resource不支持request=false

@Resource装配顺序:

  1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
  2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
  3. 如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
  4. 如果既没有指定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

33492ee8c8544d9aa2f1f307f0f1a43f_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

如果此时将@Primary注释,再次执行测试类,控制台报错

image.png

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

image.png

@Resource和@Inject都是JSR250规范,@Autowire是属于Spring的注解。


相关文章
|
4天前
|
前端开发 Java 数据库
SpringBoot学习
【10月更文挑战第7天】Spring学习
24 9
|
5天前
|
XML Java 数据格式
Spring学习
【10月更文挑战第6天】Spring学习
15 1
|
9天前
|
Java 测试技术 开发者
springboot学习四:Spring Boot profile多环境配置、devtools热部署
这篇文章主要介绍了如何在Spring Boot中进行多环境配置以及如何整合DevTools实现热部署,以提高开发效率。
28 2
|
9天前
|
前端开发 Java 程序员
springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j
这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。
25 1
|
9天前
|
Java API Spring
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中拦截器的入门教程和实战项目场景实现的详细指南。
13 0
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
|
9天前
|
Java API Spring
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中过滤器的基础知识和实战项目应用的教程。
13 0
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
|
9天前
|
Java 关系型数据库 MySQL
springboot学习五:springboot整合Mybatis 连接 mysql数据库
这篇文章是关于如何使用Spring Boot整合MyBatis来连接MySQL数据库,并进行基本的增删改查操作的教程。
15 0
springboot学习五:springboot整合Mybatis 连接 mysql数据库
|
9天前
|
Java 关系型数据库 MySQL
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql
这篇文章是关于如何使用Spring Boot框架通过JdbcTemplate操作MySQL数据库的教程。
11 0
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql
|
9天前
|
Java 测试技术 Spring
springboot学习三:Spring Boot 配置文件语法、静态工具类读取配置文件、静态工具类读取配置文件
这篇文章介绍了Spring Boot中配置文件的语法、如何读取配置文件以及如何通过静态工具类读取配置文件。
16 0
springboot学习三:Spring Boot 配置文件语法、静态工具类读取配置文件、静态工具类读取配置文件
|
9天前
|
Java Spring
springboot 学习十一:Spring Boot 优雅的集成 Lombok
这篇文章是关于如何在Spring Boot项目中集成Lombok,以简化JavaBean的编写,避免冗余代码,并提供了相关的配置步骤和常用注解的介绍。
44 0