全面深度讲解spring5底层原理一(1-5讲)

3 篇文章 0 订阅

转载自:https://blog.csdn.net/qq_38505969/article/details/123739542

介绍

代码仓库地址:https://gitee.com/CandyWall/spring-source-study
跟着黑马满一航老师的spring高级49讲做的学习笔记,本笔记跟视频内容的项目名称和代码略有不同,我将49讲的代码每一讲的代码都拆成了独立的springboot项目,并且项目名称尽量做到了见名知意,都是基于我自己的考量,代码都已经过运行验证过的,仅供参考。

视频教程地址:https://www.bilibili.com/video/BV1P44y1N7QG

注:

1. 每一讲对应一个二级标题,每一个三级标题是使用子项目名称命名的,和我代码仓库的项目是一一对应的;
2. 代码里面用到了lombok插件来简化了Bean中的get()、set()方法,以及日志的记录的时候用了lombok的@Slf4j注解。

笔记中如有不正确的地方,欢迎在评论区指正,非常感谢!!!

每个子项目对应的视频链接以及一些重要内容的笔记

第一讲 BeanFactoryApplicationContext的区别与联系

spring_01_beanfactory_applicationcontext_differences_connections

p1 000-Spring高级49讲-导学

p2 001-第一讲-BeanFactory与ApplicationContext_1

测试代码:

@SpringBootApplication
@Slf4j
public class A01Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args);
        // class org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
        System.out.println(context.getClass());
    }
}

到底什么是BeanFactory

  • 它是ApplicationContext的父接口

    鼠标选中ConfigurableApplicationContext,按Ctrl + Shift + U或者Ctrl + Alt + U打开类图,可以看到ApplicationContext的有个父接口是BeanFactory

    image-20220323144102451

  • 它才是 Spring 的核心容器,主要的 ApplicationContext 实现都 [组合]了他的功能

    打印context.getClass(),可以看到SpringBoot的启动程序返回的ConfigurableApplicationContext的具体的实现类是AnnotationConfigServletWebServerApplicationContext

    ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args);
    // org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
    System.out.println(context.getClass());
    

    按图索骥,AnnotationConfigServletWebServerApplicationContext又间接继承了GenericApplicationContext,在这个类里面可以找到beanFactory作为成员变量出现。

    image-20220404140925587

    image-20220404141152288

p3 002-第一讲-BeanFactory功能

BeanFactory接口中的方法

image-20220323145908937

查看springboot默认的ConfigurableApplicationContext类中的BeanFactory的实际类型

ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args);
// org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 查看实际类型
// class org.springframework.beans.factory.support.DefaultListableBeanFactory
System.out.println(beanFactory.getClass());

从打印结果可以了解到实际类型为DefaultListableBeanFactory,所以这里以BeanFactory的一个实现类DefaultListableBeanFactory作为出发点,进行分析。

它的类图如下:

image-20220323150712761

这里我们暂且不细看DefaultListableBeanFactory,先看DefaultListableBeanFactory的父类DefaultSingletonBeanFactory,先选中它,然后按F12,可以跳转到对应的源码,可以看到有个私有的成员变量singletonObjects

image-20220323150929451

这里通过反射的方法来获取该成员变量,进行分析

先补充一下反射获取某个类的成员变量的步骤:

获取成员变量,步骤如下:

  1. 获取Class对象

  2. 获取构造方法

  3. 通过构造方法,创建对象

  4. 获取指定的成员变量(私有成员变量,通过setAccessible(boolean flag)方法暴力访问)

  5. 通过方法,给指定对象的指定成员变量赋值或者获取值

public void set(Object obj, Object value)

​ 在指定对象obj中,将此 Field 对象表示的成员变量设置为指定的新值

​ public Object get(Object obj)

​ 返回指定对象obj中,此 Field 对象表示的成员变量的值

代码如下:

Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
// 设置私有变量可以被访问
singletonObjects.setAccessible(true);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
// 查看实际类型
// class org.springframework.beans.factory.support.DefaultListableBeanFactory
System.out.println(beanFactory.getClass());
map.entrySet().stream().filter(entry -> entry.getKey().startsWith("component")).forEach(System.out::println);

这里singletonObjects.get(beanFactory)为什么要传一个ConfigurableListableBeanFactory的变量进去呢?打印了这个beanFactory的实际类型为DefaultListableBeanFactory,查看其类图,可以了解到该类也实现了DefaultSingletonBeanRegistry接口,所以这里反射获取某个类的成员变量的get()方法中可以作为参数传进来。

image-20220324003636506

p4 003-第一讲-ApplicationContext功能1

ApplicationContextBeanFactory 多点啥?

多实现了四个接口:

  • MessageSource: 国际化功能,支持多种语言
  • ResourcePatternResolver: 通配符匹配资源路径
  • EnvironmentCapable: 环境信息,系统环境变量,*.properties*.application.yml等配置文件中的值
  • ApplicationEventPublisher: 发布事件对象

image-20220324115647260

  1. MessageSource

    resources目录下创建四个文件messages.propertesmessages_en.propertiesmessages_ja.propertiesmessages_zh.properties,然后分别在四个文件里面定义同名的key,比如在message_en.properties中定义hi=hello,在messages_ja.propertes中定义hi=こんにちは,在messages_zh中定义hi=你好,这样在代码中就可以根据这个**key hi和不同的语言类型**获取不同的value了。

    System.out.println(context.getMessage("hi", null, Locale.CHINA));
    System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
    System.out.println(context.getMessage("hi", null, Locale.JAPANESE));
    

    运行结果如下:

    image-20220324181409040

p5 004-第一讲-ApplicationContext功能2,3

  1. ResourcePatternResolver

    例1:获取类路径下的messages开头的配置文件

    Resource[] resources = context.getResources("classpath:messages*.properties");
    for (Resource resource : resources) {
        System.out.println(resource);
    }
    

    image-20220324182456169

    例2:获取spring相关jar包中的spring.factories配置文件

    resources = context.getResources("classpath*:META-INF/spring.factories");
    for (Resource resource : resources) {
        System.out.println(resource);
    }
    

    image-20220324183236048

  2. EnvironmentCapable

    获取系统环境变量中的java_home和项目的application.yml中的server.port属性

    System.out.println(context.getEnvironment().getProperty("java_home"));
    System.out.println(context.getEnvironment().getProperty("server.port"));
    

    image-20220324191740825

p6 005-第一讲-ApplicationContext功能4

  1. ApplicationEventPublisher

    定义一个用户注册事件类,继承自ApplicationEvent

    public class UserRegisteredEvent extends ApplicationEvent {
        public UserRegisteredEvent(Object source) {
            super(source);
        }
    }
    

    再定义一个监听器类,用于监听用户注册事件,类头上需要加@Component注解,将该类交给spring管理,定义一个处理事件的方法,参数类型为用户注册事件类的对象,方法头上需要加上@EventListener注解

    @Component
    @Slf4j
    public class UserRegisteredListener {
        @EventListener
        public void userRegist(UserRegisteredEvent event) {
            System.out.println("UserRegisteredEvent...");
            log.debug("{}", event);
        }
    }
    

    接着再定义一个用户服务类,里面有个register(String username, String password)方法可以完成用户的注册,注册完毕后发布一下用户注册完毕事件

    @Component
    @Slf4j
    public class UserService {
        @Autowired
        private ApplicationEventPublisher context;
        public void register(String username, String password) {
            log.debug("新用户注册,账号:" + username + ",密码:" + password);
            context.publishEvent(new UserRegisteredEvent(this));
        }
    }
    

    最后在Springboot启动类中调用一下UserService里面的register()方法注册一个新用户,UserRegisteredListener中就能处理这个用户注册完毕的事件,实现了UserService类和UserRegisteredListener类的解耦。

    UserService userService = context.getBean(UserService.class);
    userService.register("张三", "123456");
    

    image-20220324210306704

p7 006-第一讲-小结

第二讲 BeanFactoryApplicationContext 类的重要实现类

spring_02_01_beanfactory_impl

p8 007-第二讲-BeanFactory实现

p9 008-第二讲-BeanFactory实现

p10 009-第二讲-BeanFactory实现-后处理器排序

DefaultListableBeanFactory

接着第一讲中的内容,执行以下代码,可以了解到

ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
// org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 查看实际类型
// class org.springframework.beans.factory.support.DefaultListableBeanFactory
System.out.println(beanFactory.getClass());

ConfigurableApplicationContext类内部组合的BeanFactory实际类型为DefaultListableBeanFactoryspring底层创建实体类就是依赖于这个类,所以它是BeanFactory接口最重要的一个实现类,下面使用这个类,模拟一下spring使用DefaultListableBeanFactory类创建其他实体类对象的过程。

测试代码如下:

package top.jacktgq.spring_02_beanfactory_impl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.stream.Collectors;
/**
 * @Author CandyWall
 * @Date 2022/3/24--21:20
 * @Description
 */
public class TestBeanFactory {
    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添加一些常用的后处理器,让它具备解析@Configuration、@Bean等注解的能力
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        // 从bean工厂中取出BeanFactory的后处理器,并且执行这些后处理器
        // BeanFactory 后处理器主要功能,补充了一些 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);
        }
        // 从BeanFactory中取出Bean1,然后再从Bean1中取出它依赖的Bean2
        // 可以看到结果为null,所以@Autowired注解并没有被解析
        // Bean1 bean1 = beanFactory.getBean(Bean1.class);
        // System.out.println(bean1.getBean2());
        // 要想@Autowired、@Resource等注解被解析,还要添加Bean的后处理器,可以针对Bean的生命周期的各个阶段提供扩展
        // 从bean工厂中取出Bean的后处理器,并且执行这些后处理器
        // BeanFactory 后处理器主要功能,补充了一些 bean 的定义
        // beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
        // beanFactory.addBeanPostProcessors(beanFactory.getBeansOfType(BeanPostProcessor.class).values());
        // 改变Bean后处理器加入BeanFactory的顺序
        // 写法1:
        // ArrayList<BeanPostProcessor> list = new ArrayList<>(beanFactory.getBeansOfType(BeanPostProcessor.class).values());
        // Collections.reverse(list);
        // beanFactory.addBeanPostProcessors(list);
        // 写法2:
        beanFactory.addBeanPostProcessors(beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().sorted(beanFactory.getDependencyComparator()).collect(Collectors.toCollection(ArrayList::new)));
        // 准备好所有单例,get()前就把对象初始化好
        beanFactory.preInstantiateSingletons();
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        Bean1 bean1 = beanFactory.getBean(Bean1.class);
        System.out.println(bean1.getBean2());
        /**
         * 学到了什么:
         *      a. beanFactory 不会做的事
         *         1. 不会主动调用BeanFactory的后处理器
         *         2. 不会主动添加Bean的后处理器
         *         3. 不会主动初始化单例
         *         4. 不会解析BeanFactory,还不会解析 ${}, #{}
         *
         *      b. Bean后处理器会有排序的逻辑
         */
        System.out.println(bean1.getInter());
    }
    @Configuration
    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }
        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
        @Bean
        public Bean3 bean3() {
            return new Bean3();
        }
        @Bean
        public Bean4 bean4() {
            return new Bean4();
        }
    }
    @Slf4j
    static class Bean1 {
        @Autowired
        private Bean2 bean2;
        public Bean2 getBean2() {
            return bean2;
        }
        @Autowired
        @Resource(name = "bean4")
        private Inter bean3;
        public Inter getInter() {
            return bean3;
        }
        public Bean1() {
            log.debug("构造 Bean1()");
        }
    }
    @Slf4j
    static class Bean2 {
        public Bean2() {
            log.debug("构造 Bean2()");
        }
    }
    interface Inter {
    }
    @Slf4j
    static class Bean3 implements Inter {
        public Bean3() {
            log.debug("构造 Bean3()");
        }
    }
<span class="token annotation punctuation">&#64;Slf4j</span>
<span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">Bean4</span> <span class="token keyword">implements</span> <span class="token class-name">Inter</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">public</span> <span class="token class-name">Bean4</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">&#34;构造 Bean4()&#34;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

}

总结:

  • beanFactory 不会做的事

    • 不会主动调用BeanFactory的后处理器

    • 不会主动添加Bean的后处理器

    • 不会主动初始化单例

    • 不会解析BeanFactory,还不会解析 ${}, #{}

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

    先定义一个接口Inter,再定义两个Bean,名称分别为Bean3和Bean4,都继承Inter,接着在Config中通过@Bean注解将Bean3和Bean4都加进Bean工厂中,然后在Bean1中定义一个Inter对象,通过@Autowired注解将实现类注入进来。

    @Configuration
    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }
        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
        @Bean
        public Bean3 bean3() {
            return new Bean3();
        }
        @Bean
        public Bean4 bean4() {
            return new Bean4();
        }
    }
    @Slf4j
    static class Bean1 {
        @Autowired
        private Bean2 bean2;
        public Bean2 getBean2() {
            return bean2;
        }
        @Autowired
        @Resource(name = "bean4")
        private Inter bean3;
        public Inter getInter() {
            return bean3;
        }
        public Bean1() {
            log.debug("构造 Bean1()");
        }
    }
    @Slf4j
    static class Bean2 {
        public Bean2() {
            log.debug("构造 Bean2()");
        }
    }
    interface Inter {
    }
    @Slf4j
    static class Bean3 implements Inter {
        public Bean3() {
            log.debug("构造 Bean3()");
        }
    }
    @Slf4j
    static class Bean4 implements Inter {
        public Bean4() {
            log.debug("构造 Bean4()");
        }
    }
    

    如果把以Inter接口声明的变量名定义为inter@Autowired注解首先会**根据名称(byName)进行匹配,没有匹配上,于是又会根据类型(byType)**进行匹配,发现Bean3和Bean4都实现了Inter接口,会报无法自动装配的错误。

    image-20220325121422536

    所以为了避免这种错误,以Inter接口声明的变量名只能为bean3或者bean4,这里把以Inter接口声明的变量名定义为bean3,然后就不报错了,@Autowired会通过byName的方式进行匹配。

    image-20220325121717437

    在main方法中去获取Inter,然后打印,可以看到注入的是Bean3

    image-20220325133334762

    如果此时在private Inter bean3;上面再加上@Resource(name = "bean4")注解,然后再打印结果,结果还是bean3,为什么呢?我们先看一下加入BeanFactory的Bean后处理器的顺序,解析@Autowired注解的后处理器internalAutowiredAnnotationProcessor的顺序排在解析@Resource注解的后处理器internalCommonAnnotationProcessor的前面,所以internalAutowiredAnnotationProcessor会被BeanFactory先启用,故@Autowired注解先被解析了。

    image-20220325134154838

    如果想要让@Resource注解先被解析呢,这就需要让后处理器internalCommonAnnotationProcessorinternalAutowiredAnnotationProcessor先加入BeanFactory,代码如下:

    // 改变Bean后处理器加入BeanFactory的顺序
            beanFactory.addBeanPostProcessors(beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().sorted(beanFactory.getDependencyComparator()).collect(Collectors.toCollection(ArrayList::new)));
    

    这样一来注入的结果就是Bean4@Resource(name = "bean4")注解被先解析了

    image-20220325141300707

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

    image-20220325143844005

    从打印结果来看,internalAutowiredAnnotationProcessor:2147483645internalCommonAnnotationProcessor:2147483644internalCommonAnnotationProcessororder值更小,所以排序的时候会排在前面

    image-20220325144433436

  • BeanFactory本身功能只是将定义好的BeanDefinition加进来,而BeanFactory的后处理器BeanFactoryPostProcessor补充了一些Bean的定义,可以解析@Configuration@Bean等注解,将这些被注解修饰的Bean也加进BeanFactory@Configuration@Bean注解的解析过程的源码可以看AnnotationConfigUtilsConfigurationClassPostProcessor

    image-20220325005027558

    image-20220325005135527

  • 要想@Autowired@Resource等注解被解析,还要添加Bean的后处理器BeanPostProcessor,可以针对Bean的生命周期的各个阶段提供扩展。

  • BeanFactory中的对象都是懒加载的,如果不去调用get()方法获取的话,就不会初始化,如果想要让对象在get()之前就创建好,需要调用beanFactory.preInstantiateSingletons()方法。

  • 教程弹幕中有人问:为啥@Bean@Configration注解不需要建立联系就能使用?

    • 建立联系了啊,上面也获取了BeanFactory的后置处理器,然后foreach循环就是建立BeanFactory的后置处理器和BeanFactory的联系。
    • 另外@Configuration加不加,Config类中的@Bean注解都会被解析,@Configuration是用于spring类扫描的时候用的,加了这个注解的类被扫描到了就会被放进Bean工厂

spring_02_02_applicationcontext_impl

p11 010-第二讲-ApplicationContext实现1,2

p12 011-第二讲-ApplicationContext实现3

p13 012-第二讲-ApplicationContext实现4

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

image-20220325174005606

  • ClassPathXmlApplicationContext:
  • FileSystemXmlApplicationContext:
  • AnnotationConfigApplicationContext:
  • AnnotationConfigServletWebServerApplication:

相关测试代码如下:

@Slf4j
public class TestApplicationContext {
    @Test
    // ⬇️1.最为经典的容器,基于classpath 下 xml 格式的配置文件来创建
    public void testClassPathXmlApplicationContext() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring_bean.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());
    }
    @Test
    // ⬇️2.基于磁盘路径下 xml 格式的配置文件来创建
    public void testFileSystemXmlApplicationContext() {
        // 可以用绝对路径或者相对路径
        // FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("D:\\ideacode\\spring-source-study\\spring_02_02_applicationcontext_impl\\src\\main\\resources\\spring_bean.xml");
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src\\main\\resources\\spring_bean.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());
    }
    @Test
    // ⬇️模拟一下ClassPathXmlApplicationContext和FileSystemXmlApplicationContext底层的一些操作
    public 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);
        }
    }
    @Test
    // ⬇️3.较为经典的容器,基于java配置类来创建
    public 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());
    }
    @Test
    // ⬇️4.较为经典的容器,基于java配置类来创建,并且还可以用于web环境
    // 模拟了 springboot web项目内嵌Tomcat的工作原理
    public void testAnnotationConfigServletWebServerApplicationContext() throws IOException {
        AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        // 防止程序终止
        System.in.read();
    }
}
@Configuration
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;
        };
    }
}
// 单元测试的过程中如果要解析一些Spring注解,比如@Configuration的时候不要把相关类定义到写单元测试类的内部类,会读取不到
@Configuration
class Config {
    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }
    @Bean
    public Bean2 bean2(Bean1 bean1) {
        Bean2 bean2 = new Bean2();
        bean2.setBean1(bean1);
        return bean2;
    }
}
class Bean1 {
}
class Bean2 {
    private Bean1 bean1;
    public Bean1 getBean1() {
        return bean1;
    }
    public void setBean1(Bean1 bean1) {
        this.bean1 = bean1;
    }
}

spring_bean.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--5个后处理器加进来
            等价于:AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
    -->
    <context:annotation-config />
    <bean id="bean1" class="top.jacktgq.Bean1" />
    <bean id="bean2" class="top.jacktgq.Bean2">
        <property name="bean1" ref="bean1"/>
    </bean>
</beans>

第三讲 Bean的生命周期和模板方法设计模式

spring_03_bean_lifecycle

p14 013-第三讲-bean生命周期

springboot项目启动类

@SpringBootApplication
public class BeanLifeCycleApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(BeanLifeCycleApplication.class, args);
        context.close();
    }
}

定义一个LifeCycleBean,加上@Component注解,再编写一些方法,给这些方法加上Bean的生命周期过程中的注解

@Component
@Slf4j
public class LifeCycleBean {
    public LifeCycleBean() {
        log.debug("构造");
    }
    @Autowired
    public void autowire(@Value("${JAVA_HOME}") String name) {
        log.debug("依赖注入:{}", name);
    }
    @PostConstruct
    public void init() {
        log.debug("初始化");
    }
    @PreDestroy
    public void destroy() {
        log.debug("销毁");
    }
}

编写自定义Bean的后处理器,需要实现InstantiationAwareBeanPostProcessorDestructionAwareBeanPostProcessor接口,并加上@Component注解,对lifeCycleBean的生命周期过程进行扩展。

@Slf4j
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
    @Override
    // 实例化前(即调用构造方法前)执行的方法
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            log.debug("<<<<<<<<<<< 实例化前执行,如@PreDestroy");
        // 返回null保持原有对象不变,返回不为null,会替换掉原有对象
        return null;
    }
    @Override
    // 实例化后执行的方法
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean")) {
            log.debug("<<<<<<<<<<< 实例化后执行,这里如果返回 false 会跳过依赖注入阶段");
            // return false;
        }
        return true;
    }
    @Override
    // 依赖注入阶段执行的方法
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean"))
            log.debug("<<<<<<<<<<< 依赖注入阶段执行,如@Autowired、@Value、@Resource");
        return pvs;
    }
    @Override
    // 销毁前执行的方法
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        if(beanName.equals("lifeCycleBean"))
            log.debug("<<<<<<<<<<<销毁之前执行");
    }
    @Override
    // 初始化之前执行的方法
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(beanName.equals("lifeCycleBean"))
            log.debug("<<<<<<<<<<< 初始化之前执行,这里返回的对象会替换掉原本的bean,如 @PostConstruct、@ConfigurationProperties");
        return bean;
    }
    @Override
    // 初始化之后执行的方法
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(beanName.equals("lifeCycleBean"))
            log.debug("<<<<<<<<<<< 初始化之后执行,这里返回的对象会替换掉原本的bean,如 代理增强");
        return bean;
    }
}

运行结果如下:

image-20220326140553213

p15 014-第三讲-模板方法

public class TestMethodTemplatePattern {
    public static void main(String[] args) {
        MyBeanFactory beanFactory = new MyBeanFactory();
        beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Autowired"));
        beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));
        beanFactory.getBean();
    }
    static class MyBeanFactory {
        public Object getBean() {
            Object bean = new Object();
            System.out.println("构造:" + bean);
            System.out.println("依赖注入:" + bean);
            for (BeanPostProcessor processor : processors) {
                processor.inject(bean);
            }
            System.out.println("初始化:" + bean);
            return bean;
        }
        private List<BeanPostProcessor> processors = new ArrayList<>();
        public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
            processors.add(beanPostProcessor);
        }
    }
    interface BeanPostProcessor {
        void inject(Object bean);
    }
}

第四讲 常见Bean后处理器以及@Autowired注解被解析的详细过程

spring_04_beanpostprocessor

p16 015-第四讲-常见bean后处理器1,2

p17 016-第四讲-常见bean后处理器3

定义三个Bean,名称分别为Bean1Bean2Bean3,其中Bean1中依赖了Bean2Bean3Bean2通过@Autowired的注解注入,Bean3通过@Resource注解注入,再通过@Value注解注入一个Java的环境变量JAVA_HOME的值。最后定义两个方法init()destroy(),分别加上@PostConstruct@PreDestroy注解。

@Slf4j
public class Bean1 {
    private Bean2 bean2;
    @Autowired
    public void setBean2(Bean2 bean2) {
        log.debug("@Autowired 生效:{}", bean2);
        this.bean2 = bean2;
    }
    @Autowired
    public void setJava_home(@Value("${JAVA_HOME}") String java_home) {
        log.debug("@Value 生效:{}", java_home);
        this.java_home = java_home;
    }
    private Bean3 bean3;
    @Resource
    public void setBean3(Bean3 bean3) {
        log.debug("@Resource 生效:{}", bean3);
        this.bean3 = bean3;
    }
    private String java_home;
    @PostConstruct
    public void init() {
        log.debug("@PostConstruct 生效:{}");
    }
    @PreDestroy
    public void destroy() {
        log.debug("@PreDestroy 生效:{}");
    }
    @Override
    public String toString() {
        return "Bean1{" +
                "bean2=" + bean2 +
                ", bean3=" + bean3 +
                ", java_home='" + java_home + '\'' +
                '}';
    }
}

public class Bean2 {

}

public class Bean3 {

}

@ConfigurationProperties(prefix = “java”)
@Slf4j
public class Bean4 {
private String home;
private String version;
}

这里用GenericApplicationContext 来探究一下@Autowired@Value@Resource@PostConstruct@PreDestroy以及springboot项目中的@ConfigurationProperties这些注解分别是由哪个后处理器来解析的。

注:GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试,这里用DefaultListableBeanFactory也可以完成测试,只是会比使用GenericApplicationContext麻烦一些。

测试代码如下:

@Slf4j
public class TestBeanPostProcessor {
    @Test
    public void testBeanPostProcessor() throws Exception {
        // ⬇️GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
        // 这里用DefaultListableBeanFactory也可以完成测试,只是会比使用GenericApplicationContext麻烦一些
        GenericApplicationContext context = new GenericApplicationContext();
        // 用原始方法注册三个Bean
        context.registerBean("bean1", Bean1.class);
        context.registerBean("bean2", Bean2.class);
        context.registerBean("bean3", Bean3.class);
        context.registerBean("bean4", Bean4.class);
        // 设置解析 @Value 注解的解析器
        context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        // 添加解析 @Autowired 和 @Value 注解的后处理器
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        // 添加解析 @Resource、@PostConstruct、@PreDestroy 注解的后处理器
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        // 添加解析 @ConfigurationProperties注解的后处理器
        // ConfigurationPropertiesBindingPostProcessor后处理器不能像上面几种后处理器那样用context直接注册上去
        // context.registerBean(ConfigurationPropertiesBindingPostProcessor.class);
        // 需要反着来注册一下
        ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
        // ⬇️初始化容器
        context.refresh();
        System.out.println(context.getBean(Bean4.class));
        // ⬇️销毁容器
        context.close();
    }
}

运行结果如下:

image-20220327233426083

经过测试和运行结果的比对:

  • @Autowired注解对应的后处理器是AutowiredAnnotationBeanPostProcessor
  • @Value注解需要配合@Autowired注解一起使用,所以也用到了AutowiredAnnotationBeanPostProcessor后处理器,然后@Value注解还需要再用到ContextAnnotationAutowireCandidateResolver解析器,否则会报错;
  • @Resource@PostConstruct@PreDestroy注解对应的后处理器是CommonAnnotationBeanPostProcessor
  • @ConfigurationProperties注解对应的后处理器是ConfigurationPropertiesBindingPostProcessor

p18 017-第四讲-@Autowired bean后处理器执行分析

p19 018-第四讲-@Autowired bean后处理器执行分析

本案例测试代码紧接着上面,这里对Bean1中加了@Autowired注解的属性注入Bean2、方法注入Bean3以及方法注入环境变量JAVA_HOME的过程进行分析。

@Autowired注解解析用到的后处理器是AutowiredAnnotationBeanPostProcessor

  • 这个后处理器就是通过调用postProcessProperties(PropertyValues pvs, Object bean, String beanName)完成注解的解析和注入的功能
  • 这个方法中又调用了一个私有的方法findAutowiringMetadata(beanName, bean.getClass(), pvs),其返回值InjectionMetadata中封装了被@Autowired注解修饰的属性和方法
  • 然后会调用InjectionMetadata.inject(bean1, "bean1", null)进行依赖注入
  • 由于InjectionMetadata.inject(bean1, "bean1", null)的源码调用链过长,摘出主要调用过程进行说明:
  • 成员变量注入,InjectionMetadata注入Bean3的过程:
    • InjectionMetadata会把Bean1中加了@Autowired注解的属性的BeanName先拿到,这里拿到的BeanName就是 bean3,然后再通过反射拿到这个属性,Field bean3Field = Bean1.class.getDeclaredField("bean3");
    • 将这个属性封装成一个DependencyDescriptor对象,再去调用Bean3 bean3Value = (Bean3) beanFactory.doResolveDependency(dd1, null, null, null);拿到bean3Value
    • 最后把值赋给这个属性bean3Field.set(bean1, bean3Value);
  • 方法参数注入,InjectionMetadata注入Bean2的过程:
    • InjectionMetadata会把Bean1中加了@Autowired注解的方法的MethodName先拿到,这里拿到的MethodName就是 setBean2,然后再通过反射拿到这个方法,Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
    • 将这个属性封装成一个DependencyDescriptor对象,再去调用Bean2 bean2Value = (Bean2) beanFactory.doResolveDependency(dd2, "bean2", null, null);拿到bean2Value
    • 最后调用方法setBean2.invoke(bean1, bean2Value),给方法参数赋值。
  • 方法参数注入,参数类型为String类型,且加上了@Value注解,InjectionMetadata注入环境变量JAVA_HOME的过程:
    • InjectionMetadata会把Bean1中加了@Autowired注解的方法的MethodName先拿到,这里拿到的MethodName就是 setJava_home,然后再通过反射拿到这个方法,Method setJava_home = Bean1.class.getDeclaredMethod("setJava_home", String.class);
    • 将这个属性封装成一个DependencyDescriptor对象,再去调用String java_home = (String) beanFactory.doResolveDependency(dd3, null, null, null);拿到java_home
    • 最后调用方法setJava_home.invoke(bean1, java_home);,给方法参数赋值。

全部测试代码如下:

@Slf4j
public class TestBeanPostProcessors {
    @Test
    public void testAutowiredAnnotationBeanPostProcessor() throws Throwable {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 这里为了省事就不使用 beanFactory.registerBeanDefinition()方法去添加类的描述信息了
        // 直接使用 beanFactory.registerSingleton可以直接将Bean的单例对象注入进去,
        // 后面调用beanFactory.getBean()方法的时候就不会去根据Bean的定义去创建Bean的实例了,
        // 也不会有懒加载和依赖注入的初始化过程了。
        beanFactory.registerSingleton("bean2", new Bean2());
        beanFactory.registerSingleton("bean3", new Bean3());
        // 设置@Autowired注解的解析器
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        // 设置解析 @Value 注解中的 ${} 表达式的解析器
        beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);
        // 1. 查找哪些属性、方法加了 @Autowired,这称之为InjectionMetadata
        // 创建后处理器
        AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
        // 后处理器在解析@Autowired和@Value的时候需要用到其他Bean,
        // 而BeanFactory提供了需要的Bean,所以需要把BeanFactory传给这个后处理器
        processor.setBeanFactory(beanFactory);
        // 创建Bean1
        Bean1 bean1 = new Bean1();
        System.out.println(bean1);
        // 解析@Autowired和@Value注解,执行依赖注入
        // PropertyValues pvs: 给注解的属性注入给定的值,这里不需要手动给定,传null即可
        // processor.postProcessProperties(null, bean1, "bean1");
        // postProcessProperties()方法底层原理探究
        // 通过查看源码得知 postProcessProperties()方法中调用了一个私有的方法findAutowiringMetadata(beanName, bean.getClass(), pvs); 会返回一个InjectionMetadata的对象,然后会调用InjectionMetadata.inject(bean1, "bean1", null)进行依赖注入
        // 通过反射调用一下
        /*Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata",String.class, Class.class, PropertyValues.class);
        findAutowiringMetadata.setAccessible(true);
        // 获取Bean1上加了@Value @Autowired注解的成员变量和方法参数信息
        InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);
        System.out.println(metadata);
        // 2. 调用 InjectionMetaData 来进行依赖注入,注入时按类型查找值
        metadata.inject(bean1, "bean1", null);
        System.out.println(bean1);*/
        // 3. 如何去Bean工厂里面按类型查找值
        // 由于InjectionMetadata.inject(bean1, "bean1", null)的源码调用链过长,摘出主要调用过程进行演示
        // 3.1 @Autowired加在成员变量上,InjectionMetatadata给Bean1注入Bean3的过程
        // 通过InjectionMetadata把Bean1加了@Autowired注解的属性的BeanName先拿到,这里假设拿到的BeanName就是 bean3
        // 通过BeanName反射获取到这个属性,
        Field bean3Field = Bean1.class.getDeclaredField("bean3");
        // 设置私有属性可以被访问
        bean3Field.setAccessible(true);
        // 将这个属性封装成一个DependencyDescriptor对象
        DependencyDescriptor dd1 = new DependencyDescriptor(bean3Field, false);
        // 再执行beanFactory的doResolveDependency
        Bean3 bean3Value = (Bean3) beanFactory.doResolveDependency(dd1, null, null, null);
        System.out.println(bean3Value);
        // 给Bean1的成员bean3赋值
        bean3Field.set(bean1, bean3Value);
        System.out.println(bean1);
        // 3.2 @Autowired加在方法上,InjectionMetatadata给Bean1注入Bean2的过程
        Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
        DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2, 0), true);
        Bean2 bean2Value = (Bean2) beanFactory.doResolveDependency(dd2, "bean2", null, null);
        System.out.println(bean2Value);
        // 给Bean1的setBean2()方法的参数赋值
        setBean2.invoke(bean1, bean2Value);
        System.out.println(bean1);
        // 3.3 @Autowired加在方法上,方法参数为String类型,加了@Value,
        // InjectionMetadata给Bean1注入环境变量JAVA_HOME属性的值
        Method setJava_home = Bean1.class.getDeclaredMethod("setJava_home", String.class);
        DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setJava_home, 0), true);
        String java_home = (String) beanFactory.doResolveDependency(dd3, null, null, null);
        System.out.println(java_home);
        setJava_home.invoke(bean1, java_home);
        System.out.println(bean1);
    }
}

运行结果如下:

image-20220329115607946

第五讲 常见Bean工厂后处理器以及模拟实现组件扫描

spring_05_beanfactorypostprocessor

p20 019-第五讲-常见工厂后处理器

定义Bean1Bean2Mapper1Mapper2Config 5个类,其中Bean2上面加上@Component@ComponentScan注解,Config上加@Component注解,Config中通过@Bean注解定义Bean1Mapper1Mapper2上加@Mapper注解,类的定义参考下图,由于涉及的类比较多,具体代码可以去我的代码仓库获取。

image-20220329142407664

这里用GenericApplicationContext 来探究一下@Component@ComponentScan@Bean@MapperScan这些注解分别是由哪个后处理器来解析的。

测试代码如下:

@Slf4j
public class TestBeanFactoryPostProcessors {
    @Test
    public void testBeanPostProcessors() throws IOException {
        // ⬇️GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        // 添加Bean工厂后处理器ConfigurationClassPostProcessor
        // 解析@ComponentScan、@Bean、@Import、@ImportResource注解
        context.registerBean(ConfigurationClassPostProcessor.class);
        // 添加Bean工厂后处理器MapperScannerConfigurer,解析@MapperScan注解
        context.registerBean(MapperScannerConfigurer.class, beanDefinition -> {
            // 指定扫描的包名
            beanDefinition.getPropertyValues().add("basePackage", "top.jacktgq.mapper");
        });
        // ⬇️初始化容器
        context.refresh();
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        // ⬇️销毁容器
        context.close();
    }
}

经过测试和运行结果的比对:

  • @Component@Bean对应的Bean工厂后处理器是ConfigurationClassPostProcessor
  • @MapperScan对应的Bean工厂后处理器是MapperScannerConfigurer

p21 020-第五讲-工厂后处理器模拟实现-组件扫描

p22 021-第五讲-工厂后处理器模拟实现-组件扫描

自定义组件扫描Bean工厂后处理器CandyComponentScanPostProcessor来解析@Component注解,代码如下:

public class CandyAtComponentScanPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if (componentScan != null) {
                for (String basePage : componentScan.basePackages()) {
                    System.out.println(basePage);
                    // top.jacktgq.component -> classpath*:com/jacktgq/component/**/*.class
                    String path = "classpath*:" + basePage.replace('.', '/') + "/**/*.class";
                    // System.out.println(path);
                    CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                    AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                    for (Resource resource : new PathMatchingResourcePatternResolver().getResources(path)) {
                        // System.out.println(resource);
                        // 查看对应的类上是否有@Component注解
                        // System.out.println("分隔符>>>>>>>>>>>>>>>>>");
                        MetadataReader reader = factory.getMetadataReader(resource);
                        String className = reader.getClassMetadata().getClassName();
                        // System.out.println("类名:" + className);
                        String name = Component.class.getName();
                        // System.out.println("是否加了 @Component注解:" + reader.getAnnotationMetadata().hasAnnotation(name));
                        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                        // System.out.println("是否加了@Component的派生注解:" + annotationMetadata.hasMetaAnnotation(name));
                        // 如果直接或者间接加了@Component注解
                        if (annotationMetadata.hasAnnotation(Component.class.getName()) || annotationMetadata.hasMetaAnnotation(name)) {
                            // 创建Bean的定义
                            AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(className).getBeanDefinition();
                            String beanName = generator.generateBeanName(beanDefinition, beanFactory);
                            // 将Bean定义加入工厂
                            beanFactory.registerBeanDefinition(beanName, beanDefinition);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    // context.refresh()中会回调该方法
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    }
}

测试代码:

@Slf4j
public class TestBeanFactoryPostProcessors {
    @Test
    // 模拟实现组件扫描
    public void testMockComponentScan() throws Exception {
        // ⬇️GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        // 把自定义组件扫描Bean工厂后处理器加进来
        context.registerBean(CandyComponentScanPostProcessor.class);
        // ⬇️初始化容器
        context.refresh();
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        // ⬇️销毁容器
        context.close();
    }
}

运行结果:

image-20220329192201153

p23 022-第五讲-工厂后处理器模拟实现-@Bean

自定义Bean工厂后处理器CandyAtBeanPostProcessor来解析@Bean注解,代码如下:

public class CandyAtBeanPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            MetadataReader reader = factory.getMetadataReader(new ClassPathResource("top/jacktgq/Config.class"));
            Set<MethodMetadata> annotatedMethods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
            for (MethodMetadata annotatedMethod : annotatedMethods) {
                System.out.println(annotatedMethod);
                String initMethod = annotatedMethod.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
                // 这里不需要指定类名了,因为最终的BeanDefinition是Config类中加了@Bean属性的方法的返回值的类型的定义。
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
                builder.setFactoryMethodOnBean(annotatedMethod.getMethodName(), "config");
                builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
                if (initMethod.length() > 0) {
                    builder.setInitMethodName(initMethod);
                }
                AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
                beanFactory.registerBeanDefinition(annotatedMethod.getMethodName(), beanDefinition);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    }
}

注:自定义解析 @ComponentScan 和 后面的 @Bean 注解的Bean工厂后处理器,实现BeanDefinitionRegistryPostProcessor接口而不是BeanFactoryPostProcessor接口,这么做的原因是:

  • 实现BeanFactoryPostProcessorpostProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)方法,参数configurableListableBeanFactory工厂调用不了registerBeanDefinition()方法,需要做强制转换,转成DefaultableBeanFactory类型,才能调用registerBeanDefinition()方法。
  • 实现BeanDefinitionRegistryPostProcessor,它里面除了postProcessBeanFactory()方法,还有一个postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory),参数beanFactory可以直接调用registerBeanDefinition()方法,避免了ConfigurableListableBeanFactoryDefaultableBeanFactory的强制转换。

测试代码:

public class TestBeanFactoryPostProcessors {
    @Test
    // 模拟实现@Bean注解的解析
    public void testMockAtBeanAnnotation() throws Exception {
        // ⬇️GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        context.registerBean(CandyAtBeanPostProcessor.class);
        // ⬇️初始化容器
        context.refresh();
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        // ⬇️销毁容器
        context.close();
    }
}

运行结果:

image-20220329224604315

p25 024-第五讲-工厂后处理器模拟实现-Mapper

自定义Bean工厂后处理器CandyAtMapperPostProcessor来解析@Mapper注解,代码如下:

public class CandyAtMapperPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resolver.getResources("classpath:top/jacktgq/mapper/**/*.class");
            // Bean的名字生成器
            AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            for (Resource resource : resources) {
                MetadataReader reader = factory.getMetadataReader(resource);
                ClassMetadata classMetadata = reader.getClassMetadata();
                if (classMetadata.isInterface()) {
                    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class).addConstructorArgValue(classMetadata.getClassName()).setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE).getBeanDefinition();
                    // 这里不能使用名字生成器和MapperFactoryBean的BeanDefinition作为参数直接生成名字,
                    // 这样会导致多个相同的类型的对象因为名字一样产生覆盖的问题
                    // 解决办法 这里参考Spring源码的做法
                    // 用@Mapper注解修饰的接口的BeanDefinition作为参数生成名字
                    AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();
                    String beanName = generator.generateBeanName(bd, beanFactory);
                    beanFactory.registerBeanDefinition(beanName, beanDefinition);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    }
}

测试代码:

@Slf4j
public class TestBeanFactoryPostProcessors {
    @Test
    // 模拟实现@Mapper注解的解析
    public void testMockAtMapperAnnotation() throws Exception {
        // ⬇️GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        // 先解析@Bean注解,把SqlSessionFactory加到Bean工厂里面
        context.registerBean(CandyAtBeanPostProcessor.class);
        // 解析Mapper接口
        context.registerBean(CandyAtMapperPostProcessor.class);
        // ⬇️初始化容器
        context.refresh();
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        // ⬇️销毁容器
        context.close();
    }
}

运行结果:

image-20220330012845575

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值