找回密码
 立即注册
首页 业界区 安全 手写Spring框架-壹

手写Spring框架-壹

俞秋荣 4 天前
背景

最近工作比较轻松,于是趁着手里没有活,就打算自己写一个简单的Spring框架,因为之前背Spring的八股的时候老是背了就忘。
--本来前面写的好好的,也能勉强理解,但是到了第七章写应用上下文时,一下子来了十多个接口和抽象类,直接就蒙了,于是打算画图帮助理解,并且写博客记录,防止以后又忘了。。
参考

小傅哥:https://bugstack.cn/md/spring/develop-spring/2021-05-16-第1章:开篇介绍,手写Spring能给你带来什么?.html
因为前面第七章前面并不难,所以直接从第七章开始。
首先介绍一下Bean的生命周期:
1. 容器启动阶段

加载配置(XML、注解、JavaConfig)
解析成 BeanDefinition(class、scope、依赖等元信息)
注册到 BeanDefinitionRegistry
2. BeanFactoryPostProcessor 阶段

触发时机:在任何 Bean 实例化之前
作用:修改 BeanDefinition 的元信息
典型用途:占位符替换 ${}、动态修改属性值等
注意:此时 Bean 还没有被创建。
3. Bean 实例化阶段

Spring 调用构造方法 / 工厂方法,new 出对象。
此时只是一个“空壳对象”,还没有属性。
4. 属性填充(依赖注入)

Spring 根据 BeanDefinition 里的信息,进行 依赖注入:
XML 里  配置的属性注入
构造器 / Setter 注入
时机:实例化之后,初始化之前
5. BeanPostProcessor 前置处理

调用 postProcessBeforeInitialization(bean, beanName)
在 Bean 初始化方法之前执行
6. 初始化方法

如果实现了 InitializingBean,执行 afterPropertiesSet()
7. BeanPostProcessor 后置处理

调用 postProcessAfterInitialization(bean, beanName)
8. Bean 就绪

现在 Bean 已经完全可用了,交给容器管理。
正文

本章的目标是实现满足于在 Bean 对象从容器启动到Bean可用的过程中执行用户的自定义操作,但是如果只是添加这两个接口,不做任何包装,那么对于使用者来说还是非常麻烦的。我们希望于开发 Spring 的上下文操作类,把相应的 XML 加载 、注册、实例化以及新增的修改和扩展都融合进去,让 Spring 可以自动扫描到我们的新增服务,便于用户使用。
1.png

提供给用户的扩展接口

首先是BeanFactoryPostProcessor接口,该接口是spring提供给用户使用的接口,用户实现该接口就可以在Bean实例化之前使用BeanFactory对Bean的注册信息进行操作。
注意:此时 Bean 还没被创建。
  1. public interface BeanFactoryPostProcessor {
  2.     /**
  3.      * 在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的机制
  4.      *
  5.      * @param beanFactory
  6.      * @throws BeansException
  7.      */
  8.     void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
  9. }
复制代码
然后是实现BeanPostProcessor接口,该接口是spring提供给用户使用的接口,用户通过实现该接口,就可以在Bean初始化前后对Bean进行操作。
  1. public interface BeanPostProcessor {
  2.     /**
  3.      * 在 Bean 对象执行初始化方法之前,执行此方法
  4.      *
  5.      * @param bean
  6.      * @param beanName
  7.      * @return
  8.      * @throws BeansException
  9.      */
  10.     Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
  11.     /**
  12.      * 在 Bean 对象执行初始化方法之后,执行此方法
  13.      *
  14.      * @param bean
  15.      * @param beanName
  16.      * @return
  17.      * @throws BeansException
  18.      */
  19.     Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
  20. }
复制代码
Spring内部使用的接口

上面讲的是Spring提供给用户使用的接口,而spring内部也得有相关的定义,才能支持这种扩展
ListableBeanFactory接口

该接口的作用是可以获取IOC容器里的多个Bean,是对BeanFactory的扩展,BeanFactory一次只能获取一个Bean
  1. public interface ListableBeanFactory extends BeanFactory{
  2.     /**
  3.      * 按照类型返回 Bean 实例
  4.      * @param type
  5.      * @param <T>
  6.      * @return
  7.      * @throws BeansException
  8.      */
  9.     <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException;
  10.     /**
  11.      * Return the names of all beans defined in this registry.
  12.      *
  13.      * 返回注册表中所有的Bean名称
  14.      */
  15.     String[] getBeanDefinitionNames();
  16. }
复制代码
HierarchicalBeanFactory接口

这是一个标记性接口,定义了spring容器分层的概念
  1. public interface HierarchicalBeanFactory extends BeanFactory {
  2. }
复制代码
AutowireCapableBeanFactory接口

这个接口很容易与前面的BeanPostFactory接口混淆,这个接口是Spring内部使用的!!!
继承BeanFactory接口是需要获得getBean的能力,它本身提供了两个方法,用于在Bean初始化前后
  1. public interface AutowireCapableBeanFactory extends BeanFactory {
  2.     /**
  3.      * 执行 BeanPostProcessors 接口实现类的 postProcessBeforeInitialization 方法
  4.      * 在Bean初始化之前执行一些操作-BeforeInitialization
  5.      *
  6.      * @param existingBean
  7.      * @param beanName
  8.      * @return
  9.      * @throws BeansException
  10.      */
  11.     Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException;
  12.     /**
  13.      * 执行 BeanPostProcessors 接口实现类的 postProcessorsAfterInitialization 方法
  14.      * 在Bean初始化之后执行一些操作-AfterInitialization
  15.      *
  16.      * @param existingBean
  17.      * @param beanName
  18.      * @return
  19.      * @throws BeansException
  20.      */
  21.     Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException;
  22. }
复制代码
ConfigurableBeanFactory接口

继承HierarchicalBeanFactory代表支持容器分层的能力
继承SingletonBeanRegistry代表有获取单例Bean的能力
它的功能是在BeanFactory基础上,一个支持父子容器、单例缓存并且可以有生命周期扩展(BeanPostProcessor-Bean初始化前后扩展处理的能力)
并且具有保存和管理 BeanPostProcessor 列表的能力,定义了addBeanPostProcessor()方法
  1. public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
  2.     /**
  3.      * 两种作用域
  4.      */
  5.     String SCOPE_SINGLETON = "singleton";
  6.     String SCOPE_PROTOTYPE = "prototype";
  7.     void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
  8. }
复制代码
ConfigurableListableBeanFactory接口

这个接口非常重要,它继承了ListableBeanFactory(支持一次获取多个Bean的能力)、AutowireCapableBeanFactory(支持自动注入能力-创建和装配Bean)、
ConfigurableBeanFactory(支持作用域、配置、Bean初始化前后扩展的能力)
这代表了这个接口能够完整实现IOC容器的所有职责,实现了它就代表了是一个完整Spring容器!!!
  1. public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
  2.     BeanDefinition getBeanDefinition(String beanName) throws BeansException;
  3.     void preInstantiateSingletons() throws BeansException;
  4. }
复制代码
到了这里,Spring内部管理Bean实例的接口就创建好了,接下来创建上下文相关接口
ApplicationContext是对外的接口,给用户使用的,所以得继承ListableBeanFactory来获得对Bean的查询能力,方便用户获取Bean。
问题:为什么不继承其他继承了BeanFactory的接口,比如ConfigurableBeanFactory,它也有这些功能?
解答:还是上面那句话,ApplicationContext是给用户使用的,而ConfigurableBeanFactory是给容器内部使用的
ApplicationContext接口
  1. public interface ApplicationContext extends ListableBeanFactory {
  2. }
复制代码
ConfigurableApplicationContext接口

refresh()是spring容器的核心启动方法
这也是给spring内部容器使用的,所以单独创建了它,而不是在ApplicationContext里定义refresh()方法
  1. public interface ConfigurableApplicationContext extends ApplicationContext{
  2.     /**
  3.      * 刷新容器
  4.      * @throws BeansException
  5.      */
  6.     void refresh() throws BeansException;
  7. }
复制代码
AbstractApplicationContext抽象类

该抽象类用模板方法模式实现了refresh()方法逻辑
并且继承了DefaultResourceLoader来获得加载资源的能力,因为refresh()需要解析xml文件加载Bean
  1. public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
  2.     @Override
  3.     public void refresh() throws BeansException {
  4.         // 1. 创建 BeanFactory,并加载 BeanDefinition
  5.         refreshBeanFactory();
  6.         // 2. 获取 BeanFactory
  7.         ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  8.         // 3. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
  9.         // 真正执行了
  10.         invokeBeanFactoryPostProcessors(beanFactory);
  11.         // 4. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
  12.         // 只是注册,加入到执行链中,并没有执行
  13.         registerBeanPostProcessors(beanFactory);
  14.         // 5. 提前实例化单例Bean对象
  15.         beanFactory.preInstantiateSingletons();
  16.     }
  17.     /**
  18.      * 获取所有实现了BeanPostProcessor的Bean,将它加到BeanPostProcessor执行链,getBeansOfType()返回的就是beanDefinitionMap的遍历顺序,也就是注册顺序
  19.      * 即BeanPostProcessor执行链里执行的顺序是它的注册顺序
  20.      * 如果需要改变执行的优先级,可以实现 PriorityOrdered 或 Ordered 接口
  21.      * @param beanFactory
  22.      */
  23.     private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
  24.         Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
  25.         for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
  26.             beanFactory.addBeanPostProcessor(beanPostProcessor);
  27.         }
  28.     }
  29.     /**
  30.      * 直接执行了BeanFactoryProcessor
  31.      * @param beanFactory
  32.      */
  33.     private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
  34.         Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
  35.         for (BeanFactoryPostProcessor beanFactoryPostProcessor:beanFactoryPostProcessorMap.values()){
  36.             beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
  37.         }
  38.     }
  39.     /**
  40.      * 门面+委托模式的应用,在这里再次实现getBeansOfType只是因为ApplicationContext是对用户使用的,
  41.      * 这里再次实现只是提供一个门面,但是真正实现还是委托给DefaultListableBeanFactory去做
  42.      * @param type
  43.      * @return
  44.      * @param <T>
  45.      * @throws BeansException
  46.      */
  47.     @Override
  48.     public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
  49.         return getBeanFactory().getBeansOfType(type);
  50.     }
  51.     @Override
  52.     public String[] getBeanDefinitionNames() {
  53.         return getBeanFactory().getBeanDefinitionNames();
  54.     }
  55.     @Override
  56.     public Object getBean(String beanName) {
  57.         return getBeanFactory().getBean(beanName);
  58.     }
  59.     @Override
  60.     public Object getBean(String beanName, Object... args) {
  61.         return getBeanFactory().getBean(beanName, args);
  62.     }
  63.     @Override
  64.     public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
  65.         return getBeanFactory().getBean(name, requiredType);
  66.     }
  67.     protected abstract void refreshBeanFactory() throws BeansException;
  68.     protected abstract ConfigurableListableBeanFactory getBeanFactory();
  69. }
复制代码
AbstractRefreshableApplicationContext抽象类

实现了父类AbstractApplicationContext的refreshBeanFactory()和getBeanFactory()方法
分担了父类AbstractApplicationContext的解析xml文件并创建beanFactory的职责
自己实现了创建beanFactory的功能
并且定义了抽象方法loadBeanDefinitions将解析xml文件的职责下发给子类
  1. public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext{
  2.     private DefaultListableBeanFactory beanFactory;
  3.     @Override
  4.     protected void refreshBeanFactory() throws BeansException {
  5.         DefaultListableBeanFactory beanFactory = createBeanFactory();
  6.         loadBeanDefinitions(beanFactory);
  7.         this.beanFactory = beanFactory;
  8.     }
  9.     protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory);
  10.     private DefaultListableBeanFactory createBeanFactory() {
  11.         return new DefaultListableBeanFactory();
  12.     }
  13.     @Override
  14.     protected ConfigurableListableBeanFactory getBeanFactory() {
  15.         return this.beanFactory;
  16.     }
  17. }
复制代码
AbstractXmlApplicationContext抽象类

负责解析配置文件并注册Bean的功能
定义抽象方法getConfigLocations()将获取配置文件的职责下发
  1. public abstract class AbstractXmlApplicationContext extends AbstractRefreshableApplicationContext{
  2.     @Override
  3.     protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
  4.         XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(this, beanFactory);
  5.         String[] configLocations = getConfigLocations();
  6.         if(null != configLocations && configLocations.length > 0) {
  7.             xmlBeanDefinitionReader.loadBeanDefinitions(configLocations);
  8.         }
  9.     }
  10.     protected abstract String[] getConfigLocations();
  11. }
复制代码
ClassPathXmlApplicationContext抽象类

负责获取xml文件
ClassPathXmlApplicationContext是这条继承链的终点,也是spring容器启动的起点
通过调用refresh()来启动容器
  1. public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
  2.     private String[] configLocations;
  3.     public ClassPathXmlApplicationContext() {}
  4.     public ClassPathXmlApplicationContext(String configLocation) {
  5.         this(new String[]{configLocation});
  6.     }
  7.     public ClassPathXmlApplicationContext(String[] configLocations) {
  8.         this.configLocations = configLocations;
  9.         //开启容器启动流程
  10.         refresh();
  11.     }
  12.     @Override
  13.     protected String[] getConfigLocations() {
  14.         return configLocations;
  15.     }
  16. }
复制代码
spring容器内部在哪扩展?

BeanFactoryPostProcessor在AbstractApplicationContext抽象类的refresh()方法里直接执行,
而BeanPostProcessor只是在这里把所有实现了BeanPostProcessor的接口加入到BeanPostProcessor执行链。
而真正执行BeanPostProcessor是在Bean实例化之后,初始化前后,也就是AbstractAutowireCapableBeanFactory的createBean方法初始化前后
目前第七章的架构图

2.png


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册