• Spring源码之BeanFactory 与 ApplicationContext 的区别


    1、Spring容器接口介绍

    BeanFactory 接口

    • Spring 的核心容器,ApplicationContext 的父接口
    • 表面上只有 getBean,实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供

    ApplicationContext 接口

    • 主要的 ApplicationContext 实现都【组合】了它的功能,【组合】是指 ApplicationContext 的一个重要成员变量就是 BeanFactory
    • ApplicationContext 新增扩展功能:国际化、通配符方式获取多个Resource资源、事件发布与监听、整合 Environment 环境

    在这里插入图片描述

    2、容器接口功能实现

    2.1、BeanFactory单例bean的存储

    @SpringBootApplication
    public class A01 {
        public static void main(String[] args) {
            ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
            System.out.println(context);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • context下的beanFactory实现类DefaultListableBeanFactory对象下的singletonObje的Map成员变量下存储这单例bean对象

    在这里插入图片描述

    在这里插入图片描述

    2.2、ApplicationContext国际化资源获取

    在这里插入图片描述

    • 配置文件设置相同的key,不同的value
    • 如下,key都是"hi",通过匹配不同的语言获取不同的value
     ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
     System.out.println(context.getMessage("hi", null, Locale.CHINA));//你好
     System.out.println(context.getMessage("hi", null, Locale.ENGLISH));//Hello
     System.out.println(context.getMessage("hi", null, Locale.JAPANESE));//こんにちは
    
    • 1
    • 2
    • 3
    • 4

    2.3、ApplicationContext通配符获取多资源

     ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
     //classpath*:类路径+jar包类路径
     Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
     for (Resource resource : resources) {
         System.out.println(resource);
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出结果:

    URL [file:/F:/%e5%ad%a6%e4%b9%a0%e8%b5%84%e6%96%99/spring/%e4%bb%a3%e7%a0%81/show/target/classes/META-INF/spring.factories]
    URL [jar:file:/E:/java/maven/mvnrep/org/springframework/boot/spring-boot/2.5.5/spring-boot-2.5.5.jar!/META-INF/spring.factories]
    URL [jar:file:/E:/java/maven/mvnrep/org/springframework/boot/spring-boot-autoconfigure/2.5.5/spring-boot-autoconfigure-2.5.5.jar!/META-INF/spring.factories]
    URL [jar:file:/E:/java/maven/mvnrep/org/springframework/spring-beans/5.3.10/spring-beans-5.3.10.jar!/META-INF/spring.factories]
    URL [jar:file:/E:/java/maven/mvnrep/org/mybatis/spring/boot/mybatis-spring-boot-autoconfigure/2.2.0/mybatis-spring-boot-autoconfigure-2.2.0.jar!/META-INF/spring.factories]
    URL [jar:file:/E:/java/maven/mvnrep/com/alibaba/druid-spring-boot-starter/1.2.8/druid-spring-boot-starter-1.2.8.jar!/META-INF/spring.factories]
    URL [jar:file:/E:/java/maven/mvnrep/org/springframework/spring-test/5.3.10/spring-test-5.3.10.jar!/META-INF/spring.factories]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.4、ApplicationContext读取环境或配置文件信息

     ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
     //环境信息
     System.out.println(context.getEnvironment().getProperty("java_home"));
     //配置文件信息
     System.out.println(context.getEnvironment().getProperty("server.port"));
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出结果:

    E:\java\jdk\jdk8\tools
    8080
    
    • 1
    • 2

    2.5、ApplicationContext发布事件

    基本使用

    • 创建事件类,source为事件发布对象
    public class UserRegisteredEvent extends ApplicationEvent {
        public UserRegisteredEvent(Object source) {
            super(source);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 发布事件,发布者为context
    ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
    Object obj = new Object();
    context.publishEvent(new UserRegisteredEvent(obj));
    
    • 1
    • 2
    • 3
    • 设置监听方法
    @Component
    public class Component2 {
        private static final Logger log = LoggerFactory.getLogger(Component2.class);
        @EventListener
        public void aaa(UserRegisteredEvent event) {
            log.debug("{}", event);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    输出结果:发布事件为UserRegisteredEvent,发布对象为Object

    [DEBUG] 22:33:09.715 [main] com.itheima.a01.Component2          
    - com.itheima.a01.UserRegisteredEvent[source=java.lang.Object@5b051a5c] 
    
    • 1
    • 2

    实际应用

    • 事件类依然为UserRegisteredEvent
    • 发布事件对象this则为Register对象本身
    @Component
    public class Register {
        private static final Logger log = LoggerFactory.getLogger(Register.class);
        @Autowired
        private ApplicationContext context;
    
        public void register() {
            log.debug("用户注册");
            context.publishEvent(new UserRegisteredEvent(this));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 短信监听类
    @Component
    public class Message {
        private static final Logger log = LoggerFactory.getLogger(Message.class);
        @EventListener
        public void message(UserRegisteredEvent event) {
            log.debug("{}", event);
            log.debug("发送短信");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 邮件监听类
    @Component
    public class Mail {
        private static final Logger log = LoggerFactory.getLogger(Mail.class);
        @EventListener
        public void mail(UserRegisteredEvent event) {
            log.debug("{}", event);
            log.debug("发送邮件");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 发布事件
    @Autowired
    private  Register register; 
    ...
    //发布事件
    register.register();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出结果:

    [DEBUG] 22:50:34.276 [main] com.itheima.a01.Register            - 用户注册 
    [DEBUG] 22:50:34.277 [main] com.itheima.a01.Mail                - com.itheima.a01.UserRegisteredEvent[source=com.itheima.a01.Register@341672e] 
    [DEBUG] 22:50:34.282 [main] com.itheima.a01.Mail                - 发送邮件 
    [DEBUG] 22:50:34.282 [main] com.itheima.a01.Message             - com.itheima.a01.UserRegisteredEvent[source=com.itheima.a01.Register@341672e] 
    [DEBUG] 22:50:34.282 [main] com.itheima.a01.Message             - 发送短信 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    将用户注册后的后续不同的处理方式解耦,添加不同监听,则触发不同的事件操作

    3、BeanFactory核心实现类 DefaultListableBeanFactory

    • spring核心bean容器实现类
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    
    • 1
    • 这个会创建一个GenericBeanDefinition普通bean定义对象返回
    • bean definition 描述了这个bean 的创建蓝图:scope 是什么、用构造还是工厂创建、初始化销毁方法是什么,等等
    • 此时bean定义只是被创建出来,还没有加入到bean容器中
    BeanDefinition beanDefinition = 
    BeanDefinitionBuilder.genericBeanDefinition(Config.class)
    .setScope("singleton")
    .setLazyInit(false)
    .getBeanDefinition();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 被创建为bean definition的类:Config
    @Configuration
    class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }
    
        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }
    
    class Bean1 {
        private static final Logger log = LoggerFactory.getLogger(Bean1.class);
    
        public Bean1() {
            log.debug("构造 Bean1()");
        }
    
        @Autowired
        private Bean2 bean2;
    
        public Bean2 getBean2() {
            return bean2;
        }
    }
    
    class Bean2 {
        private static final Logger log = LoggerFactory.getLogger(Bean2.class);
    
        public Bean2() {
            log.debug("构造 Bean2()");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 将bean定义信息注册添加到容器中,并设置bean的名字
    beanFactory.registerBeanDefinition("config", beanDefinition);
    
    • 1
    • bean定义信息添加bean容器中

    在这里插入图片描述

    • singletonObjes为空,则表明bean定义对应的对象依然没有生成

    在这里插入图片描述

    • 给 BeanFactory 添加一些常用的后处理器
    AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
    for (String name : beanFactory.getBeanDefinitionNames()) {
        System.out.println(name);
    }
    
    • 1
    • 2
    • 3
    • 4

    输出结果:这里返回的只是bean定义的名字

    config
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • beanFactory 需要手动调用beanFactory后处理器对它做增强
    • ConfigurationClassPostProcessor通过解析 @Bean、@ComponentScan 等注解,来补充一些 bean definition。如:bean1、bean2
    beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
        System.out.println("BeanFactory后置处理器>>>>>>" + beanFactoryPostProcessor);
        beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
    });
    for (String name : beanFactory.getBeanDefinitionNames()) {
        System.out.println(name);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出结果:

    BeanFactory后置处理器>>>>>>org.springframework.context.annotation.ConfigurationClassPostProcessor@2a5c8d3f
    BeanFactory后置处理器>>>>>>org.springframework.context.event.EventListenerMethodProcessor@1be2019a
    config
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    bean1
    bean2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource
    • 如果只是添加到List beanPostProcessors,则是懒加载,获取对象时候才会执行
    beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -> {
        System.out.println("Bean后置处理器>>>>>>" + beanPostProcessor);
        beanFactory.addBeanPostProcessor(beanPostProcessor);
    });
    System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
    System.out.println(beanFactory.getBean(Bean1.class).getBean2());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    @Configuration
    class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }
    
        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }
    
    class Bean1 {
        private static final Logger log = LoggerFactory.getLogger(Bean1.class);
    
        public Bean1() {
            log.debug("构造 Bean1()");
        }
    
        @Autowired
        private Bean2 bean2;
    
        public Bean2 getBean2() {
            return bean2;
        }
    }
    
    class Bean2 {
        private static final Logger log = LoggerFactory.getLogger(Bean2.class);
    
        public Bean2() {
            log.debug("构造 Bean2()");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    输出结果:

    Bean后置处理器>>>>>>org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@6fe7aac8
    Bean后置处理器>>>>>>org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@1d119efb
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
    [DEBUG] 22:38:31.944 [main] c.itheima.a02.TestBeanFactory$Bean1 - 构造 Bean1() 
    [DEBUG] 22:38:31.981 [main] c.itheima.a02.TestBeanFactory$Bean2 - 构造 Bean2() 
    com.itheima.a02.TestBeanFactory$Bean2@15a04efb
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 修改以上代码,添加一行(准备好所有单例),由懒加载变为提前准备
    beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -> {
        System.out.println("Bean后置处理器>>>>>>" + beanPostProcessor);
        beanFactory.addBeanPostProcessor(beanPostProcessor);
    });
    beanFactory.preInstantiateSingletons();
    System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
    System.out.println(beanFactory.getBean(Bean1.class).getBean2());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出结果:

    Bean后置处理器>>>>>>org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@6fe7aac8
    Bean后置处理器>>>>>>org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@1d119efb
    [DEBUG] 22:43:38.108 [main] c.itheima.a02.TestBeanFactory$Bean1 - 构造 Bean1() 
    [DEBUG] 22:43:38.144 [main] c.itheima.a02.TestBeanFactory$Bean2 - 构造 Bean2() 
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
    com.itheima.a02.TestBeanFactory$Bean2@5e21e98f
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4、常见ApplicationContext实现

    4.1、基于classpath下xml格式的配置文件来创建

    配置文件bean.xml:

    
    <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="bean1" class="com.itheima.a02.A02.Bean1"/>
    
        
        <bean id="bean2" class="com.itheima.a02.A02.Bean2">
            
            <property name="bean1" ref="bean1"/>
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    对象实体:

    class Bean1 {
    }
    
    class Bean2 {
        private Bean1 bean1;
        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
        }
        public Bean1 getBean1() {
            return bean1;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    public class A01 {
        public static void main(String[] args) {
    		ClassPathXmlApplicationContext context =
    		       new ClassPathXmlApplicationContext("bean.xml");
    		for (String name : context.getBeanDefinitionNames()) {
    		   System.out.println(name);
    		}
    		System.out.println(context.getBean(Bean2.class).getBean1());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出结果:

    bean1
    bean2
    com.xc.Bean1@53ca01a2
    
    • 1
    • 2
    • 3

    ClassPathXmlApplicationContext工作流程

    //创建bean容器对象
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    System.out.println("读取之前...");
    for (String name : beanFactory.getBeanDefinitionNames()) {
        System.out.println(name);
    }
    System.out.println("读取之后...");
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
    //读取配置文件
    reader.loadBeanDefinitions(new ClassPathResource("bean.xml"));
    for (String name : beanFactory.getBeanDefinitionNames()) {
        System.out.println(name);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.2、基于磁盘路径下xml格式的配置文件来创建

    public class A02 {
        public static void main(String[] args) {
            FileSystemXmlApplicationContext context =
                    new FileSystemXmlApplicationContext(
                            "D:\\demo\\src\\main\\resources\\bean.xml");
            for (String name : context.getBeanDefinitionNames()) {
                System.out.println(name);
            }
            System.out.println(context.getBean(Bean2.class).getBean1());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4.3、较为经典的容器, 基于java配置类来创建

    配置类:

    @Configuration
    public class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }
        @Bean
        public Bean2 bean2(Bean1 bean1) {
            Bean2 bean2 = new Bean2();
            bean2.setBean1(bean1);
            return bean2;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    启动类:

    public class A03 {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context =
                    new AnnotationConfigApplicationContext(Config.class);
            for (String name : context.getBeanDefinitionNames()) {
                System.out.println(name);
            }
            System.out.println(context.getBean(Bean2.class).getBean1());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出结果:

    Connected to the target VM, address: '127.0.0.1:58835', transport: 'socket'
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    Config
    bean1
    bean2
    com.xc.Bean1@282cb7c7
    Disconnected from the target VM, address: '127.0.0.1:58835', transport: 'socket'
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.4、较为经典的容器, 基于java配置类来创建, 用于web环境

    配置类:

    @Configuration
    public class WebConfig {
        @Bean
        public ServletWebServerFactory servletWebServerFactory(){
            return new TomcatServletWebServerFactory();
        }
        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }
        @Bean
        public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        }
        @Bean("/hello")
        public Controller controller1() {
            return (request, response) -> {
                response.getWriter().print("hello");
                return null;
            };
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    启动类:

    public class A03 {
        public static void main(String[] args) {
            AnnotationConfigServletWebServerApplicationContext context =
                    new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
            for (String name : context.getBeanDefinitionNames()) {
                System.out.println(name);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出结果:

    在这里插入图片描述

    访问页面:

    在这里插入图片描述

  • 相关阅读:
    戏说领域驱动设计(十四)——补遗
    linux下安装向日葵
    java: 警告: 源发行版 17 需要目标发行版 17
    docker项目部署
    盘点6个主流的数据分析工具,及优缺点对比
    Qt开发工程师成系统性长体系教程
    Air Quality Index,简称AQI
    KUKA机器人后台控制程序(SPS)介绍
    php8.1-common : 依赖: libffi6 (>= 3.2) 但无法安装它(树莓派4B kali)
    android免root读写u盘最新方法,支持安卓Q+
  • 原文地址:https://blog.csdn.net/qq_35512802/article/details/125880198