Spring 框架源码解读3

作者: 想54256 | 来源:发表于2020-04-16 13:40 被阅读0次

    title: Spring 框架源码解读3
    date: 2020/04/16 09:25


    本节内容 & 思考题

    Spring 中的 bean 的生命周期?

    image
    1. 通过xml配置文件或者注解扫描获取要实例化bean的信息,并使用反射创建实例
    2. 如果有需要注入的属性,则进行注入
    3. 执行一些 *Aware 接口的方法
    4. 调用实现了 BeanPostProcessor 接口的前置处理方法
    5. 执行实现 InitializingBean bean的 afterPropertiesSet() 方法
    6. 调用定义的 init-method 方法
    7. 调用实现了 BeanPostProcessor 接口的后置处理方法
    8. 要销毁Bean的时候,如果Bean实现了DisposableBean接口,执行destroy()方法。
    9. 调用定义的 destory-method 方法

    本节内容就会带大家实现 5 6 8 9

    适配器模式:将普通对象适配成 InitializingBean

    实现初始化 bean 的方法

    1、在 BD 中新增字段

    private String initMethod;
    

    2、修改 AbstractBeanFactory#createBean() 方法

    /**
     * 根据 bd 创建对象
     * <p>
     * 1)创建bean 日后需要对有参构造进行扩展
     * 2)注入属性  日后新增
     * 3)执行初始化操作
     * 4)注册销毁的处理
     */
    private Object createBean(BeanDefinition beanDefinition) {
    
        // 1、创建 bean
        Object bean = ReflectUtil.newInstance(beanDefinition.getClassName());
    
        // 2、注入属性 todo
    
        // 3、执行初始化操作(在 Spring 中是直接调用的该类中的 initializeBean 方法,为了让他面向对象一点,我给他抽出一个类)
        InitializeBeanAdapter initializeBeanAdapter = new InitializeBeanAdapter(bean, beanDefinition);
        initializeBeanAdapter.afterPropertiesSet();
    
        // 4、注册销毁的处理  todo
    
        return bean;
    }
    

    3、InitializeBean 接口 & InitializeBeanAdapter 适配器

    public interface InitializingBean {
    
        /**
         * 设置所有提供的bean属性后,由BeanFactory调用。
         */
        void afterPropertiesSet();
    
    }
    
    
    public class InitializeBeanAdapter implements InitializingBean {
    
        private Object bean;
    
        private BeanDefinition bd;
    
        public InitializeBeanAdapter(Object bean, BeanDefinition bd) {
            this.bean = bean;
            this.bd = bd;
        }
    
    
        /**
         * 设置所有提供的bean属性后,由BeanFactory调用。
         */
        @Override
        public void afterPropertiesSet() {
    
            // 1、处理 @PostConstruct 注解,执行注解的方法(此处 Spring 是采用后置处理器实现的,为什么要采用这个实现,而不是直接调用呢?)
            this.postConstruct();
    
            // 2、如果该 bean 实现了 InitializingBean 接口,则调用
            this.initializingBean();
    
            // 3、处理用户在 xml 文件中配置的 init-method 方法
            this.customInit();
        }
    
        private void customInit() {
            String initMethod = bd.getInitMethod();
            if (ObjectUtil.isNotNull(initMethod)) {
                ReflectUtil.invoke(bean, initMethod);
            }
        }
    
        private void initializingBean() {
            if (bean instanceof InitializingBean) {
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }
    
        private void postConstruct() {
            for (Method method : ReflectUtils.getMethodsByAnnotation(bean.getClass(), PostConstruct.class)) {
                ReflectUtil.invoke(bean, method);
            }
        }
    }
    

    4、测试

    public class TestJsonBF {
        public static void main(String[] args) {
            ListableBeanFactory bf = new JsonBeanFactoryImpl("/Users/x5456/IdeaProjects/Summer/src/test/resources/apple.json");
            Apple apple = bf.getBean("apple", Apple.class);
        }
    }
    
    apple.json
    
    [
      {
        "name": "apple",
        "className": "cn.x5456.summer.Apple",
        "initMethod": "init"
      }
    ]
    
    public class Apple implements InitializingBean {
    
        @Override
        public void afterPropertiesSet() {
            System.out.println("InitializingBean");
        }
    
        public void init() {
            System.out.println("init-method");
        }
    
        @PostConstruct
        public void func() {
            System.out.println("@PostConstruct");
        }
    
        @PostConstruct
        public void func2() {
            System.out.println("@PostConstruct2");
        }
    }
    

    集成销毁方法

    1、修改 BD

    private String destroyMethod;
    

    2、修改 AbstractBeanFactory#createBean() 方法

    /**
     * 根据 bd 创建对象
     * <p>
     * 1)创建bean 日后需要对有参构造进行扩展
     * 2)注入属性  日后新增
     * 3)执行初始化操作
     * 4)注册销毁的处理
     */
    private Object createBean(BeanDefinition beanDefinition) {
    
        // 1、创建 bean
        Object bean = ReflectUtil.newInstance(beanDefinition.getClassName());
    
        // 2、注入属性 todo
    
        // 3、执行初始化操作(在 Spring 中是直接调用的该类中的 initializeBean 方法,为了让他面向对象一点,我给他抽出一个类)
        InitializeBeanAdapter initializeBeanAdapter = new InitializeBeanAdapter(bean, beanDefinition);
        initializeBeanAdapter.afterPropertiesSet();
    
        // 4、注册销毁的处理
        if (this.check(beanDefinition, bean)) {
            registry.registerDisposableBean(beanDefinition.getName(), new DisposableBeanAdapter(bean, beanDefinition));
        }
    
        return bean;
    }
    
    /**
     * 检查是否具有销毁方法
     */
    private boolean check(BeanDefinition bd, Object bean) {
        return ObjectUtil.isNotNull(bd.getDestroyMethod()) ||
                bean instanceof DisposableBean ||
                CollectionUtil.isNotEmpty(ReflectUtils.getMethodsByAnnotation(bean.getClass(), PreDestroy.class));
    }
    

    3、DisposableBean & DisposableBeanAdapter

    public interface DisposableBean {
    
        /**
         * 由BeanFactory在销毁bean时调用。
         */
        void destroy();
    
    }
    
    public class DisposableBeanAdapter implements DisposableBean {
    
        private Object bean;
    
        private BeanDefinition bd;
    
        public DisposableBeanAdapter(Object bean, BeanDefinition bd) {
            this.bean = bean;
            this.bd = bd;
        }
    
        /**
         * 由BeanFactory在销毁bean时调用。
         */
        @Override
        public void destroy() {
            // 1、处理 @PreDestroy 注解,执行注解的方法(此处 Spring 是采用后置处理器实现的,为什么要采用这个实现,而不是直接调用呢?)
            this.postPreDestroy();
    
            // 2、如果该 bean 实现了 DisposableBean 接口,则调用
            this.disposableBean();
    
            // 3、处理用户在 xml 文件中配置的 destroy-method 方法
            this.customDestroy();
        }
    
        private void customDestroy() {
            String destroyMethod = bd.getDestroyMethod();
            if (ObjectUtil.isNotNull(destroyMethod)) {
                ReflectUtil.invoke(bean, destroyMethod);
            }
        }
    
        private void disposableBean() {
            if (bean instanceof DisposableBean) {
                ((DisposableBean) bean).destroy();
            }
        }
    
        private void postPreDestroy() {
            for (Method method : ReflectUtils.getMethodsByAnnotation(bean.getClass(), PreDestroy.class)) {
                ReflectUtil.invoke(bean, method);
            }
        }
    }
    

    4、销毁信息注册中心

    public class DefaultSingletonBeanRegistry {
    
        private final Map<String, DisposableBean> disposableBeans = new LinkedHashMap<>();
    
        /** 注册销毁信息 */
        public void registerDisposableBean(String beanName, DisposableBean bean) {
            this.disposableBeans.put(beanName, bean);
        }
    
        /** 执行销毁方法 */
        public void destroySingletons() {
            // 调用销毁方法
            for (DisposableBean disposableBean : disposableBeans.values()) {
                disposableBean.destroy();
            }
            // 清空 map
            disposableBeans.clear();
        }
    }
    

    5、在 BF 中新增调用单例对象销毁方法

    /**
     * 执行单例对象销毁方法
     * <p>
     * 那么原型的怎么办?
     * <p>
     * 原型对象在获取的时候会执行初始化操作,且不会执行销毁操作
     * <p>
     * Note: 在 Spring5.0 中,这个方法在 ConfigurableBeanFactory 中扩展,但是如果新增这个接口
     * 会将类之间的逻辑变得十分复杂,有悖于我们做这个教程的初衷,所以采用 default 方法的方式,让 ABF
     * 实现这个接口,而不用 AAP 实现这个接口
     */
    default void destroySingletons() {
    }
    
    ABF 实现
    
    @Override
    public void destroySingletons() {
        registry.destroySingletons();
    }
    

    6、测试

    public class TestJsonBF {
        public static void main(String[] args) {
            ListableBeanFactory bf = new JsonBeanFactoryImpl("/Users/x5456/IdeaProjects/Summer/src/test/resources/apple.json");
            Apple apple = bf.getBean("apple", Apple.class);
    
            bf.destroySingletons();
        }
    }
    
    apple.json
    
    [
      {
        "name": "apple",
        "className": "cn.x5456.summer.Apple",
        "initMethod": "init",
        "destroyMethod": "destroyMethod"
      }
    ]
    
    public class Apple implements InitializingBean, DisposableBean {
    
        @Override
        public void afterPropertiesSet() {
            System.out.println("InitializingBean");
        }
    
        public void init() {
            System.out.println("init-method");
        }
    
        @PostConstruct
        public void func() {
            System.out.println("@PostConstruct");
        }
    
        @PostConstruct
        public void func2() {
            System.out.println("@PostConstruct2");
        }
    
        // ---> 销毁
    
        @Override
        public void destroy() {
            System.out.println("DisposableBean");
        }
    
        public void destroyMethod() {
            System.out.println("destroyMethod");
        }
    
        @PreDestroy
        public void func3() {
            System.out.println("@PreDestroy");
        }
    
    }
    

    ApplicationContext 新增对对象的销毁方法

    1、ApplicationContext 新增 close 方法

    AP
    
    /**
     * 关闭容器
     */
    void close();
    
    AAP 实现
    
    public abstract class AbstractApplicationContext implements ApplicationContext {
    
        // ...
        
        // 关闭钩子,防止意外关闭
        private Thread shutdownHook = new Thread(AbstractApplicationContext.this::doClose);
    
        /**
         * 加载或刷新配置文件(例如 XML、JSON)
         * <p>
         * 模版方法模式
         */
        @Override
        public void refresh() {
    
            // ...
    
            // 注册关闭钩子
            Runtime.getRuntime().addShutdownHook(shutdownHook);
        }
    
        /**
         * 关闭容器
         */
        @Override
        public void close() {
            // 执行关闭操作
            this.doClose();
    
            // 移除关闭钩子
            if (ObjectUtil.isNotNull(shutdownHook)) {
                Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
            }
        }
    
        private void doClose() {
            // 销毁单例的 bean
            this.getBeanFactory().destroySingletons();
        }
    

    2、测试

    public class TestJsonAP {
    
        public static void main(String[] args) {
            FileSystemJsonApplicationContext fileSystemJsonApplicationContext = new FileSystemJsonApplicationContext(new String[]{
                    "/Users/x5456/IdeaProjects/Summer/src/test/resources/apple.json"
            });
    
            fileSystemJsonApplicationContext.close();
        }
    }
    

    Spring 0.9

    0.9 中并没有提供 DisposableBean 等销毁方法,所以本节是参考 5.0 完成。

    Spring 5.0

    1、初始化操作

    image

    创建bean之后会调用他们的后置处理器

    image

    然后通过反射调用使用 @PostConstruct 注释的方法

    之后调用 invokeInitMethods 方法:

    image

    所以,顺序是 @PostConstruct InitializingBean init-method

    2、注册销毁

    在初始化完成后,Spring 会注册销毁方法。

    image image

    它采用了一个注册中心存放 DisposableBeanAdapter

    image

    DisposableBeanAdapter#destroy()

    image

    3、调用销毁

    image

    最终会调用到这里,调用 DisposableBeanAdapter#destroy()

    image

    相关文章

      网友评论

        本文标题:Spring 框架源码解读3

        本文链接:https://www.haomeiwen.com/subject/htervhtx.html