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的注解。


相关文章
|
7天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
25 2
|
23天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
13天前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
39 9
|
1月前
|
前端开发 Java 数据库
SpringBoot学习
【10月更文挑战第7天】Spring学习
36 9
|
1月前
|
XML Java 数据格式
Spring学习
【10月更文挑战第6天】Spring学习
21 1
|
1月前
|
Java 测试技术 开发者
springboot学习四:Spring Boot profile多环境配置、devtools热部署
这篇文章主要介绍了如何在Spring Boot中进行多环境配置以及如何整合DevTools实现热部署,以提高开发效率。
62 2
|
1月前
|
前端开发 Java 程序员
springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j
这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。
102 1
|
1月前
|
Java API Spring
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中拦截器的入门教程和实战项目场景实现的详细指南。
26 0
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
|
1月前
|
Java API Spring
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中过滤器的基础知识和实战项目应用的教程。
24 0
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
|
1月前
|
Java 关系型数据库 MySQL
springboot学习五:springboot整合Mybatis 连接 mysql数据库
这篇文章是关于如何使用Spring Boot整合MyBatis来连接MySQL数据库,并进行基本的增删改查操作的教程。
80 0
springboot学习五:springboot整合Mybatis 连接 mysql数据库
下一篇
无影云桌面