【第二讲 】容器实现

第二讲 容器实现

  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());
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()");
        }
    }

}

将 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);
    }
}

在这里插入图片描述

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

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

-------
 null      

添加

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

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

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

在这里插入图片描述

使用 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());

在这里插入图片描述

学到了什么

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()");
        }
    }

}

bean 后处理器排序逻辑

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

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

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

在这里插入图片描述

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

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

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

在这里插入图片描述

通过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;
        }
    }
}

  • spring配置
<?xml version="1.0" encoding="UTF-8"?>
<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>
  • 输出

在这里插入图片描述

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());
    }

也可以为相对路径

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

在这里插入图片描述

模拟底层原理

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);
    }
}

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());

    }

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;
        }
    }
<!--
        把5个后处理器加进来
            等价于:AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
    -->
<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

AnnotationConfigServletWebServerAppliactionContext

 // 较为经典的容器,基于java配置类来创建,并且还可以用于web环境
    // 模拟了 springboot web项目内嵌Tomcat的工作原理
    public static void testAnnotationConfigServletWebServerApplicationContext() throws Exception {
        AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        // 防止程序终止
        System.in.read();
    }
  @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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值