从0开始写一个Ioc容器

Spring 框架源码解读3

2020-04-16  本文已影响0人  想54256

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
上一篇 下一篇

猜你喜欢

热点阅读