Bootstrap

Springy源码第二讲

1.DefaultListableBeanFactory

 beanFactory 可以通过 registerBeanDefinition 注册一个 bean definition 对象
   我们平时使用的配置类、xml、组件扫描等方式都是生成 bean definition 对象注册到 beanFactory 当中
   bean definition 描述了这个 bean 的创建蓝图:scope 是什么、用构造还是工厂创建、初始化销毁方法是什么,等等
 beanFactory 需要手动调用 beanFactory 后处理器对它做增强
   例如通过解析 @Bean、@ComponentScan 等注解,来补充一些 bean definition
 beanFactory 需要手动添加 bean 后处理器,以便对后续 bean 的创建过程提供增强
   例如 @Autowired,@Resource 等注解的解析都是 bean 后处理器完成的
   bean 后处理的添加顺序会对解析结果有影响,
 beanFactory 需要手动调用方法来初始化单例
 beanFactory 需要额外设置才能解析 ${} 与 #{}

public class TestBeanFactory {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
        //bean的定义(class,scope单例还是多例,初始化,销毁) (控制反转bean对象由beanFactory创建)


        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
                .genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        beanFactory.registerBeanDefinition("config",beanDefinition);

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


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

    static class Bean2 {
        private static final Logger log = LoggerFactory.getLogger(Bean2.class);

        public Bean2() {
            log.debug("构造 Bean2()");
        }
    }
}

此时只输出

说明Bean1、Bean2还未 注册进去,因为@Configuration、@Bean还未被注解,beanfactory功能还未完整。这些功能不由beanfactory提供。

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

加了AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);后输出

ConfigurationAnnotationProcessor可以解析@Configuration、@Bean等注解,但这一步只是添加了这些后处理器,处理器并未运行。要让这些处理器工作还需要进行调用。

// BeanFactory 后处理器主要功能,补充了一些 bean 定义
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }

此时

说明Bean被解析了。Spring的beanfactory的功能并不丰富,很多是由后处理器提供的。

for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
System.out.println(beanFactory.getBean(Bean1.class).getBean2());

可以看到Bean2仍为null。这是因为@Autowired注入的bean2,而@Autowired是由其他bean后处理器负责。增加代码后

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

// 给 BeanFactory 添加一些常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);这句是将后处理器加入BeanFactory,而这句beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values()是建立后处理器与BeanFactory的联系。beanFactory.addBeanPostProcessor(beanPostProcessor);

beanfactory默认调用时再构造bean,属于延时创建

可设置beanFactory.preInstantiateSingletons(); // 准备好所有单例

构造提到了分隔符之前。

总结

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

这对开发人员并不友好,还是用applicationcontext好

若一个bean同时添加@Autowired,@Resource,添加比较器后按谁的优先级高先使用,数字越大优先级越低。设计的真垃圾。

2.ApplicationContext

第一种实现 // ⬇️较为经典的容器, 基于 classpath 下 xml 格式的配置文件来创建

private static void testClassPathXmlApplicationContext() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("a02copy.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Bean2.class).getBean1());
    }

    static class Bean1 {
    }

    static class Bean2 {

        private Bean1 bean1;

        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
        }

        public Bean1 getBean1() {
            return bean1;
        }
    }
<?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">

    <!-- 控制反转, 让 bean1 被 Spring 容器管理 -->
    <bean id="bean1" class="com.itheima.a02copy.A02copy.Bean1"/>

    <!-- 控制反转, 让 bean2 被 Spring 容器管理 -->
    <bean id="bean2" class="com.itheima.a02copy.A02copy.Bean2">
        <!-- 依赖注入, 建立与 bean1 的依赖关系 -->
        <property name="bean1" ref="bean1"/>
    </bean>
</beans>

可以实现注入bean的功能但太过于古老,了解即可。原理还是用beanfactory。

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 FileSystemResource("src\\main\\resources\\a02.xml"));
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }

第二种实现 基于java 配置类

// ⬇️较为经典的容器, 基于 java 配置类来创建
    private static void testAnnotationConfigApplicationContext() {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(Config.class);

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Bean2.class).getBean1());
    }

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

第三种 基于 java 配置类来创建, 用于 web 环境

// ⬇️较为经典的容器, 基于 java 配置类来创建, 用于 web 环境
    private static void testAnnotationConfigServletWebServerApplicationContext() {
        AnnotationConfigServletWebServerApplicationContext context =
                new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }

    @Configuration
    static 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("hellotest04");
                return null;
            };
        }
    }

总结 学习了常见的 ApplicationContext 容器实现
以及内嵌容器、DispatcherServlet 的创建方法、作用

;