• Spring5学习笔记02--BeanFactory 与 ApplicationContext 容器实现


    内容概要:

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

    BeanFactory 实现

    • DefaultListableBeanFactory 是 BeanFactory 最重要的实现
      • 新创建的BeanFactory里面什么也没有,需要手动进行后续的操作(如注册bean的定义)
    • BeanFactory 是根据bean的定义BeanDefinition 通过控制反转来创建bean
      • 想要BeanFactory容器添加某个Bean,就需要先BeanFactory中添加这个Bean的定义
      • BeanFactory并不会主动初始化Bean对象,通过BeanFactory获取Bean对象时,才会初始化
    • Bean的定义 BeanDefinition包括(class、Scope 单例/多例、初始化方法、销毁方法)
      • 通过BeanDefinitionBuilder创建bean的定义,设置Bean相关信息
      • 向BeanFactory中注册过Bean的定义,同时设置bean的名称
    • 向beanFactory注册一个@Configuration组件,并不会自动将里面@Bean标示的其他Bean自动注册到BeanFactory,需要一些后处理器来补充这些Bean的定义
    • BeanFactory后处理器BeanFactoryPostProcessor
      • BeanFactory后处理器BeanFactoryPostProcessor的主要功能: 补充一些Bean的定义到BeanFactory, 例如 @Bean 注解
      • 向BeanFactory中添加一些常用的后处理器BeanFactoryPostProcessor(Bean的定义),才会将@Bean等信息的Bean的定义注册到BeanFactory
    • Bean后处理器BeanPostProcessor
      • Bean后处理器BeanPostProcessor的主要功能: 针对bean的生命周期的各个阶段提供扩展,例如 @Autowired @Resurece…
    @Slf4j
    public class MainController {
    
        public static void main(String[] args) {
            // 1)创建BeanFactory,新创建的BeanFactory里面什么也没有
            DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    
            // 2)创建Bean的定义(class,scope,初始化,销毁),并向BeanFactory中注册bean的定义
            //BeanFactory是根据bean的定义`BeanDefinition`,通过控制反转来创建bean,想要BeanFactory容器添加某个Bean,就需要BeanFactory中添加Bean的定义(此时并不会主动初始化bean对象)
            BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope(BeanDefinition.SCOPE_SINGLETON).getBeanDefinition();
            beanFactory.registerBeanDefinition("config", beanDefinition);
    
            /*
            // 2.1)向beanFactory注册一个@Configuration组件,并不会自动将里面@Bean标示的其他Bean自动注册到BeanFactory
            for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
                // 输出只有config
                System.out.println(beanDefinitionName);
            }
            System.out.println("2.1>>>>>>>>>>>>>>>>>");
             */
    
            // 3)向BeanFactory中添加一些常用的后处理器(Bean的定义)
            AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
    
            // 3.1)打印后处理器Bean的定义
            for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
                // 输出多了5个后处理器
                System.out.println(beanDefinitionName + "--->" + beanFactory.getBeanDefinition(beanDefinitionName));
            }
            System.out.println("3.1>>>>>>>>>>>>>>>>>");
    
            // 4)BeanFactory后处理器的主要功能: 补充一些Bean的定义到BeanFactory, 例如 @Bean..
            beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor-> {
                System.out.println(beanFactoryPostProcessor);
                beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
            });
            System.out.println("4>>>>>>>>>>>>>>>>>");
    
            /*
            // 4.1)BeanFactory后处理器,将Bean1和Bean2的Bean的定义添加到BeanFactory
            for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
                // 输出多了 bean1 bean2
                System.out.println(beanDefinitionName);
            }
            System.out.println("4.1>>>>>>>>>>>>>>>>>");
            */
    
            /*
            // 4.2)BeanFactory并不会主动初始化Bean对象,通过BeanFactory获取Bean对象时,才会初始化
            // 获取Bean1对象,此时Bean1对象中通过@Autowired注入的Bean2对象并没有初始化
            System.out.println("bean1.getBean2():" + beanFactory.getBean(Bean1.class).getBean2()); // 打印bean1 create, 输出bean2为null
            System.out.println("4.2>>>>>>>>>>>>>>>>>");
            */
    
            // 5)Bean后处理器的主要功能: 针对bean的生命周期的各个阶段提供扩展,例如 @Autowired @Resurece..
            beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -> {
                System.out.println(beanPostProcessor);
                beanFactory.addBeanPostProcessor(beanPostProcessor);
            });
            System.out.println("5>>>>>>>>>>>>>>>>>");
    //        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor); // 使用方法引用代替lambda表达式
    
            // 5.1)Bean后处理器,将Bean1对象中的Bean2对象初始化注入进去
            System.out.println("bean1.getBean2():" + beanFactory.getBean(Bean1.class).getBean2());// 打印bean1 create, bean2 create,
            System.out.println("5.2>>>>>>>>>>>>>>>>>");
          
            // 6) 在使用Bean之前,先初始化单例对象
            beanFactory.preInstantiateSingletons();
        }
    
        @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() create");
            }
    
            public Bean2 getBean2() {
                return bean2;
            }
        }
    
        @Slf4j
        static class Bean2 {
    
            public Bean2() {
                log.info("Bean2() create");
            }
        }
    }
    
    • 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
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107

    Bean后处理器排序

    • @Autowired 注入规则:先根据class类型匹配,当class类型存在多个,再根据成员变量的名字匹配bean的名字

    • @Resource 注入规则:先根据class类型匹配,当class类型存在多个,如果注解中的变量name存在,则根据name匹配bean的名字,若不存在,则根据成员变量的名字匹配bean的名字

    • @Autowired 优先级低于 @Resource,当注入bean时同时加上了这两个注解,优先匹配 @Resource

    • 查看Bean后处理器优先级源码 AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);方法

      • AutowiredAnnotationBeanPostProcessor 后处理器作用:解析@Autowired注解,将注入的bean定义加入到BeanFactory
      • CommonAnnotationBeanPostProcessor后处理器作用:解析@Resource 注解,将注入的bean定义加入到BeanFactory
      • Bean后处理器的优先级是根据order排序的,值越小优先级越高
      // AutowiredAnnotationBeanPostProcessor 成员变量
      private int order = Ordered.LOWEST_PRECEDENCE - 2;
      
      // CommonAnnotationBeanPostProcessor 构造器
      public CommonAnnotationBeanPostProcessor() {
      		setOrder(Ordered.LOWEST_PRECEDENCE - 3);
          // ...
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    示例:

    interface Inter {}
    
    class Bean1 implements Inter {}
    
    class Bean2 implements Inter {}
    
    @Configuration
    class Config {
        @Bean
        public Inter bean3() {
            return new Bean3();
        }
    
        @Bean
        public Inter bean4() {
            return new Bean4();
        }
    }
    
    class TestComponent {
      	@Autowired
      	private Inter inter; // 找不到bean, 注入失败 (Could not autowire. There is more than one bean of 'Inter' type. Beans: bean1、bean2)
      
        @Autowired
        private Inter bean3; // 注入bean3, 根据成员变量的名字匹配
    
    
        @Resource
        private Inter bean3; // 注入bean3, 根据成员变量的名字匹配
    
    
        @Resource(name = "bean4")
        private Inter bean3; // 注入bean4, 根据name匹配
    
    
        @Autowired
        @Resource(name = "bean4")
        private Inter bean3; // 注入bean4, @Autowired 优先级低于 @Resource
    }
    
    • 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

    总结:

    • BeanFactory 不会做的事
      • 不会主动调用BeanFactory后处理器(用于解析@Bean)
      • 不会主动调用Bean后处理器(用于解析@Autowired、@Resource…)
      • 不会主动初始化单例
      • 不会解析 beanFactory, 还不会解析 ${}#{}

    ApplicationContext 实现

    ClassPathXmlApplicationContext

    • ClassPathXmlApplicationContext: 基于类路径(classpath)下读取 Spring 的 xml 配置文件创建ApplicationContext
    private static void testClassPathXmlApplicationContext() {
      ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean01.xml");
    
      // 注入了两个Bean, bean5 和 bean6
      for (String beanDefinitionName : context.getBeanDefinitionNames()) {
        System.out.println(beanDefinitionName);
      }
    
      // bean6中的bean5也自动注入成功
      System.out.println(context.getBean(Bean6.class).getBean5());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    <bean id="bean5" class="com.xxx.xxx.entity.Bean5" />
    
    <bean id="bean6" class="com.xxx.xxx.entity.Bean6">
    	<property name="bean5" ref="bean5" />
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    static class Bean5 {
      // 必须要有空构造方法
      public Bean5() {
      }
    }
    
    static class Bean6 {
      // 必须要有空构造方法
      public Bean6() {
      }
    
      private Bean5 bean5;
    
      public Bean5 getBean5() {
        return bean5;
      }
    
      public void setBean5(Bean5 bean5) {
        this.bean5 = bean5;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    FileSystemXmlApplicationContext

    • FileSystemXmlApplicationContext: 基于磁盘路径下读取 Spring 的 xml 配置文件创建ApplicationContext
      • 支持绝对路径,也支持传入从项目根目录开始的相对路径
    private static void testFileSystemXmlApplicationContext() {
      // 支持绝对路径,也支持传入从项目根目录开始的相对路径
    //  FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("/Users/wangli/idea-workspace/study-spring/src/main/resources/bean01.xml");
      FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src/main/resources/bean01.xml");
    
      // 注入了两个Bean, bean5 和 bean6
      for (String beanDefinitionName : context.getBeanDefinitionNames()) {
        System.out.println(beanDefinitionName);
      }
    
      // bean6中的bean5也自动注入成功
      System.out.println(context.getBean(Bean6.class).getBean5());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 基于 xml 配置文件初始化 ApplicationContext 容器的原理
      • ApplicationContext 内部依赖 BeanFactory (也就是 DefaultListableBeanFactory) 来进行 Bean 的管理
      • xml 配置文件是通过 XmlBeanDefinitionReader 读取的,xml 文件中配置的其实就是bean的定义
      • XmlBeanDefinitionReader 将读取到的内容转换成 BeanDefinition 注册到 BeanFactory 里
    private static void testXmlApplicationContext() {
      DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    
      // 新创建的BeanFactory 什么也没有
      System.out.println("before read..");
      for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
        System.out.println(beanDefinitionName);
      }
    
      // 初始化XmlBeanDefinitionReader, 设置将读取到的BeanDefinition注册到beanFactory
      XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
      // 设置读取xml文件资源
      reader.loadBeanDefinitions(new ClassPathResource("bean01.xml"));
    //   reader.loadBeanDefinitions(new FileSystemResource("src/main/resources/bean01.xml"));
    
      // 读取到两个bean, bean5 和 bean6
      System.out.println("after read..");
      for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
        System.out.println(beanDefinitionName);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 基于 xml 初始化 ApplicationContext 如何将BeanFactory注册的5个后处理器添加进去:使用下面这个标签
    <context:annotion-config />
    
    • 1

    AnnotationConfigApplicationContext

    • AnnotationConfigApplicationContext: 基于 Java 配置类来创建ApplicationContext
      • 会自动将5个BeanFactory注册的后处理器也注册到 BeanFactory 里
    private static void testAnnotationConfigApplicationContext() {
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
    
      // 读取到了8个bean, 除了 bean5 和 bean6 外,还有 Config 和 5个BeanFactory注册的后处理器
      for (String beanDefinitionName : context.getBeanDefinitionNames()) {
        System.out.println(beanDefinitionName);
      }
    
      // bean6中的bean5也自动注入成功
      System.out.println(context.getBean(Bean6.class).getBean5());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    @Configuration
    static class Config {
      @Bean
      public Bean5 bean5() {
        return new Bean5();
      }
    
      @Bean
      public Bean6 bean6(Bean5 bean5) {
        Bean6 bean6 = new Bean6();
        bean6.setBean5(bean5);
        return bean6;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    AnnotationConfigServletWebServerApplicationContext

    • AnnotationConfigServletWebServerApplicationContext: 基于 java 配置类来创建,用于 web 环境
    • 读取配置类,该配置类中需要注册三个特有的bean
      • ServletWebServerFactory: 提供ServletWebServer的工厂类,用于创建ServletWebServer
        • ServletWebServer是内嵌了一个基于servlet技术的web容器
        • 常见的内嵌容器:Tomcat内嵌容器
      • DispatcherServlet: 前控制器,作用是将请求分发到对应到控制器
      • DispatcherServletRegistrationBean: 用于注册DispatcherServlet到web容器
      • 另外提供一个控制器,来处理web请求,Controller 控制器,web请求入口点,由DispatcherServlet分发指定请求路径为的请求到这个控制器进行处理
    private static void testAnnotationInitApplicationContext() {
      AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
      
      // 读取到了10个bean, 5个BeanFactory注册的后处理器 + WebConfig + servletWebServerFactory + dispatcherServlet + registrationBean + /hi
      for (String beanDefinitionName : context.getBeanDefinitionNames()) {
        System.out.println(beanDefinitionName);
      }
    }
    
    
        @Configuration
        static class WebConfig {
    
            /**
             * ServletWebServer:内嵌了一个基于servlet技术的web容器,常见的内嵌容器:Tomcat内嵌容器
             * ServletWebServerFactory:提供ServletWebServer的工厂类,用于创建ServletWebServer
             * @return
             */
            @Bean
            public ServletWebServerFactory servletWebServerFactory() {
                return new TomcatServletWebServerFactory();
            }
    
            /**
             * DispatcherServlet:前控制器,作用是将请求分发到对应到控制器
             * @return
             */
            @Bean
            public DispatcherServlet dispatcherServlet() {
                return new DispatcherServlet();
            }
    
            /**
             * DispatcherServletRegistrationBean:用于注册DispatcherServlet到web容器
             * @param dispatcherServlet
             * @return
             */
            @Bean
            public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
                return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
            }
    
            /**
             * Controller: 控制器web请求入口点,由DispatcherServlet分发请求路径为 "/hi" 的请求到这个控制器进行处理
             * @return
             */
            @Bean("/hi")
            public Controller controller1() {
                return new Controller() {
                    @Override
                    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
                        response.getWriter().write("hi");
                        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
    • 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
  • 相关阅读:
    猿创征文 | 使用插槽解决组件内容传递问题(1)
    LVS负载均衡集群
    【VUE项目实战】56、商品添加功能(六)-提交添加的商品
    Python接口测试框架选择之pytest+yaml+Allure!
    两个全景vr网站 比百度要好
    SAP:增强中用commit和wait up会导致操作异常
    一种跳板机的实现思路
    猿创征文 | 【MyBatisPlus】再见了MyBatis我更喜欢Plus
    手写数字识别简化版——0和1的二分类问题
    typecho文档下的系统使用要求及文件结构说明
  • 原文地址:https://blog.csdn.net/qingqingxiangyang/article/details/126609985