• 【spring-02】容器实现


    第二讲 容器实现

    1. BeanFactory实现的特点
    2. ApplicationContext 的常见实现和用法
    3. 内嵌容器、注册DispatcherServlet

    [007]-BeanFactory实现

    在002中ConfigurableApplicationContext 类内部组合的BeanFactory实际类型为DefaultListableBeanFactory,使用这个类,模拟spring 使用DefaultListableBeanFactory 类创建其他实体类对象的过程

    ConfigurableApplicationContext context = SpringApplication.run(Spring01Application.class, args);
    // ----class org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
    System.out.println("----"+context.getClass());
    
    // class org.springframework.beans.factory.support.DefaultListableBeanFactory
    System.out.println(context.getBeanFactory().getClass());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    public class TestBeaFactory {
        public static void main(String[] args) {
            DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
            // bean 的定义(即bean的一些描述信息,包含class:bean是哪个类,scope:单例还是多例,初始化、销毁方法等)
            AbstractBeanDefinition beanDefinition =
                BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
            beanFactory.registerBeanDefinition("config", beanDefinition);
    
            // 打印BeanFactory中Bean
            for (String name : beanFactory.getBeanDefinitionNames()) {
                System.out.println(name);
            }
        }
    
        @Configuration
        static class Config {
            @Bean
            public Bean1 bean1() {
                return new Bean1();
            }
    
            @Bean
            public Bean2 bean2() {
                return new Bean2();
            }
        }
    
        @Slf4j
        static class Bean1 {
    
            public Bean1() {
                log.info("构造 Bean1()");
            }
            @Autowired
            private Bean2 bean2;
    
            public Bean2 getBean2() {
                return bean2;
            }
        }
    
        @Slf4j
        static class Bean2 {
            public Bean2() {
                log.info("构造 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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    将 config 注册进入了 beanDefinition 容器,但是bean1,和 bean2 没有注册到容器中

    在这里插入图片描述

    给BeanFactory 添加一些常用的后处理器

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // bean 的定义(即bean的一些描述信息,包含class:bean是哪个类,scope:单例还是多例,初始化、销毁方法等)
        AbstractBeanDefinition beanDefinition =
       BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        beanFactory.registerBeanDefinition("config", beanDefinition);
    
           // 给 BeanFactory 添加一些常用的后处理器
            AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
    
            // 给 BeanFactory添加一些常用的后处理器,让它具备解析@Configuration、@Bean等注解的能力
            beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
                System.out.println("--------"+ beanFactoryPostProcessor);
                beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
            });
    
        // 打印BeanFactory中Bean
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    此时打印 bean2 是为空的,因为 @Autowired 没有起作用

    // 从BeanFactory中取出Bean1,然后再从Bean1中取出它依赖的Bean2
    //  可以看到结果为null,所以@Autowired注解并没有被解析
    Bean1 bean1 = beanFactory.getBean(Bean1.class);
    System.out.println(bean1.getBean2());
    
    -------
     null      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    添加

     // 要想@Autowired、@Resource等注解被解析,还要添加Bean的后处理器,可以针对Bean的生命周期的各个阶段提供扩展
            // 从bean工厂中取出Bean的后处理器,并且执行这些后处理器
            // BeanFactory 后处理器主要功能,补充了一些 bean 的定义
             beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    此时是 调用了 getBean 才创建对象

    System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
    Bean1 bean1 = beanFactory.getBean(Bean1.class);
    System.out.println("bean2--" + bean1.getBean2());
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    使用 beanFactory.preInstantiateSingletons()后

    // 准备好所有单例,get()前就把对象初始化好
    beanFactory.preInstantiateSingletons();
    // 从BeanFactory中取出Bean1,然后再从Bean1中取出它依赖的Bean2
    //  可以看到结果为null,所以@Autowired注解并没有被解析
    System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
    Bean1 bean1 = beanFactory.getBean(Bean1.class);
    System.out.println("bean2--" + bean1.getBean2());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    学到了什么

    A. beanFactory 不会做的事

    1. 不会主动调用 BeanFactory 的后处理器
    2. 不会主动添加Bean的后处理器
    3. 不会主动初始化单例
    4. 不会解析 BeanFactory,还不会解析 ${}, #{}

    B. Bean 后处理器会有排序的逻辑

    整理代码

    public class TestBeaFactory {
        public static void main(String[] args) {
            DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
            // bean 的定义(即bean的一些描述信息,包含class:bean是哪个类,scope:单例还是多例,初始化、销毁方法等)
            AbstractBeanDefinition beanDefinition =
                BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
            beanFactory.registerBeanDefinition("config", beanDefinition);
    
            // 给 BeanFactory 添加一些常用的后处理器
            AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
    
            // 给 BeanFactory添加一些常用的后处理器,让它具备解析@Configuration、@Bean等注解的能力
            beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
                System.out.println("--------"+ beanFactoryPostProcessor);
                beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
            });
    
            // Bean 后处理器,针对 bean 的生命周期的各个阶段提供扩展,例如 @Autowired @Resource
            beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
    
    
            // 打印BeanFactory中Bean
            for (String name : beanFactory.getBeanDefinitionNames()) {
                System.out.println(name);
            }
    
            // 准备好所有单例,get()前就把对象初始化好
            beanFactory.preInstantiateSingletons();
            // 从BeanFactory中取出Bean1,然后再从Bean1中取出它依赖的Bean2
            //  可以看到结果为null,所以@Autowired注解并没有被解析
            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            Bean1 bean1 = beanFactory.getBean(Bean1.class);
            System.out.println("bean2--" + bean1.getBean2());
    
        }
    
    
    
        @Configuration
        static class Config {
            @Bean
            public Bean1 bean1() {
                return new Bean1();
            }
    
            @Bean
            public Bean2 bean2() {
                return new Bean2();
            }
        }
    
        @Slf4j
        static class Bean1 {
            @Autowired
            private Bean2 bean2;
            public Bean1() {
                log.info("构造 Bean1()");
            }
            public Bean2 getBean2() {
                return bean2;
            }
        }
    
        @Slf4j
        static class Bean2 {
            public Bean2() {
                log.info("构造 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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    bean 后处理器排序逻辑

    问题:同时加@Autowired 和 @ Resource 那一段会生效

    先加载的 AutowiredAnnotationBeanPostProcessor 后加载 CommonAnnotationBeanPostProcessor,所以 @Autowired 生效

    @Autowired
    @Resource(name = "bean4")
    private Inter bean3;
    
    • 1
    • 2
    • 3
    // Bean 后处理器,针对 bean 的生命周期的各个阶段提供扩展,例如 @Autowired @Resource
             beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor ->  {
                     System.out.println("----beanFactory----"+ beanPostProcessor);
                     beanFactory.addBeanPostProcessor(beanPostProcessor);
             });
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    我们可以通过代码控制 生效的顺序

    // Bean 后处理器,针对 bean 的生命周期的各个阶段提供扩展,例如 @Autowired @Resource
    beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().sorted(beanFactory.getDependencyComparator())
    .forEach(beanPostProcessor ->  {
    System.out.println("----beanFactory----"+ beanPostProcessor);
    beanFactory.addBeanPostProcessor(beanPostProcessor);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    增加比较器后,顺序发生了变化

    在这里插入图片描述

    通过AnnotationConfigUtils给beanFactory添加一些后处理的时候会默认设置比较器,可以对BeanPostProcessor进行排序,排序的依据是BeanPostProcessor内部的order属性,其中internalAutowiredAnnotationProcessor的order属性的值为Ordered.LOWEST_PRECEDENCE - 2,internalCommonAnnotationProcessor的order属性的值为Ordered.LOWEST_PRECEDENCE - 3。

    打印结果

    internalAutowiredAnnotationProcessor:2147483645,internalCommonAnnotationProcessor:2147483644,internalCommonAnnotationProcessororder值更小,所以排序的时候会排在前面

    在这里插入图片描述

    [010] ApplicationContext 实现

    • 四个重要的ApplicationContext接口的实现类

    在这里插入图片描述

    • ClassPathXmlApplicationContext
    • FileSystemXmlApplicationContext
    • AnnnotationConfigApplicationContext
    • AnnotationConfigServletWebServerApplication

    ClassPathXmlApplicationContext

    public class TestApplication {
    
        public static void main(String[] args) {
            testClassPathXmlApplicationContext();
        }
    
        // 较为经典的容器,基于classPath 下 xml 格式的配置文件来创建
        private static void testClassPathXmlApplicationContext(){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("Spring_bean.xml");
            for( String name:context.getBeanDefinitionNames()){
                System.out.println("--testClassPathXmlApplicationContext:" + name);
            }
    
            System.out.println("----bean2:" + context.getBean(Bean2.class).getBean1());
    
        }
    
        static class Bean1 {
    
        }
    
    
       static class Bean2 {
            private Bean1 bean1;
    
            public Bean1 getBean1() {
                return bean1;
            }
    
            public void setBean1(Bean1 bean1) {
                this.bean1 = bean1;
            }
        }
    }
    
    
    • 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
    • spring配置
    
    <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.example.spring01.com.TestApplication.Bean1"/>
    
        <bean id="bean2" class="com.example.spring01.com.TestApplication.Bean2">
            <property name="bean1" ref="bean1"/>
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 输出

    在这里插入图片描述

    FileSystemXmlApplicationContext

    / 基于硬盘路径下 xml 格式的配置文件来创建
        private static void testFileSystemXmlApplicationContext(){
            FileSystemXmlApplicationContext context =
                    new FileSystemXmlApplicationContext("D:\\2022-04-22-program\\spring_heima\\spring-01\\src\\main\\resources\\Spring_bean.xml");
            for( String name:context.getBeanDefinitionNames()){
                System.out.println("--testFileSystemXmlApplicationContext:" + name);
            }
    
            System.out.println("----bean2:" + context.getBean(Bean2.class).getBean1());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    也可以为相对路径

    new FileSystemXmlApplicationContext("src\\main\\resources\\Spring_bean.xml");
    
    • 1

    在这里插入图片描述

    模拟底层原理

    public static void testMockClassPathAndFileSystemXmlApplicationContext() {
        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("spring_bean.xml");
        // reader.loadBeanDefinitions(new ClassPathResource("spring_bean.xml"));
        reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\spring_bean.xml"));
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    AnnotationConfigApplicationContext

    //较为经典的容器,基于java配置类来创建
        private static void testAnnotationConfigApplicationContext(){
            // 会自动加上5个后处理器
            // 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
            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
    • 11
    • 12
    • 13
    • 14
    • 15

    config

     @Configuration
       static 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
    • 14
    
    <context:annotation-config />
    
     // 会自动加上5个后处理器
            // 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
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    AnnotationConfigServletWebServerAppliactionContext

     // 较为经典的容器,基于java配置类来创建,并且还可以用于web环境
        // 模拟了 springboot web项目内嵌Tomcat的工作原理
        public static void testAnnotationConfigServletWebServerApplicationContext() throws Exception {
            AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
            // 防止程序终止
            System.in.read();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
      @Configuration
       static class WebConfig {
            @Bean
            // 1. WebServer工厂
            public ServletWebServerFactory servletWebServerFactory() {
                return new TomcatServletWebServerFactory();
            }
    
            @Bean
            // 2. web项目必备的DispatcherServlet
            public DispatcherServlet dispatcherServlet() {
                return new DispatcherServlet();
            }
    
            @Bean
            // 3. 将DispatcherServlet注册到WebServer上
            public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {
                return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
            }
    
            @Bean("/hello")
            public Controller controller1() {
                return (request, response) -> {
                    response.getWriter().println("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
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述

  • 相关阅读:
    对于补码的个人理解
    从政府工作报告探云计算、大数据与人工智能的应用与推动作用
    Technology strategy Pattern 学习笔记1-Context: Architecture and Strategy
    119文章解读与程序——电网技术EI\CSCD\北大核心《含分布式电源的配电网日前两阶段优化调度模型》已提供下载资源
    golang rabbitmq客户端连接及重连
    Springboot整合Flowable6.x导出bpmn20
    mysql创建自定义函数报错
    ssh连win10报错:Permission denied (publickey,keyboard-interactive).
    小鹏汽车在滴滴上眺望远方
    Linux -- 进程间通信之匿名管道
  • 原文地址:https://blog.csdn.net/qq_25614773/article/details/126219096