手写Spring笔记

197 阅读11分钟

一、创建简单的Bean容器

  1. 需求:实现最简单的Bean容器。
  2. 实现:将实例注册到Map中,然后每次从Map中获取实例。
    • BeanDefinition 定义bean属性,用于保存bean的Object对象。
    • BeanFactory使用Map存储相应的BeanDefinition对象。

二、实现Bean的定义、注册、获取

  1. 需求:
    • 将Bean的创建交给容器,而不是传一个实例化好的Object对象。
    • 完善基础容器框架的结构,建立单例对象池。
  2. 思路:
    • 改造 BeanDefinition对象:将属性从Object改为Class,即直接class信息而非实例化好的Object。
    • 单例注册表
      1. 定义SingletonBeanRegistry接口,并定义getSingleton方法用于获取Object对象。
      2. 定义DefaultSingletonBeanRegistry类实现SingletonBeanRegistry接口(使用Map存储单例对象),对外提供getSingleton和addSingleton方法。
    • 定义 BeanFactory 接口,并定义getBean方法用于创建、获取bean对象。
      1. 定义 AbstractBeanFactory抽象类实现BeanFactory接口,并让它继承DefaultSingletonBeanRegistry类使该抽象类获取 注册、获取单例表的能力。
      2. AbstractBeanFactory 实现了getBean方法。它定义了getBeanDefinition、createBean的抽象方法,规范创建bean的逻辑。
          public Object getBean(String name) throws BeansException {
              Object bean = getSingleton(name);
              if (bean != null) {
                  return bean;
              }
        
              BeanDefinition beanDefinition = getBeanDefinition(name);
              return createBean(name, beanDefinition);
          }
        
      3. AbstractAutowireCapableBeanFactory 实现了对应的createBean抽象方法,即通过BeanDefinition对象获取class信息,然后使用newInstance方法进行创建对象。
    • 定义 BeanDefinitionRegistry接口 完善框架,该接口中定义registerBeanDefinition方法,功能为向注册表注册BeanDefinition
      1. 定义DefaultListableBeanFactory类,该类继承AbstractAutowireCapableBeanFactory和实现了BeanDefinitionRegistry接口,该类分别实现了registerBeanDefinition和getBeanDefinition方法。

三、对象实例化策略

  1. 需求:当模型只提供带无参创建对象,如果对象只提供有参的构造方法时,使用newInstance方法则会报错,这时需要提供新的创建对象的方法,本节将解决这一问题。
  2. 思路:修改createBean创建方法
    • 定义 InstantiationStrategy 接口,提供instantiate方法,用于Bean的实例化
      1. 定义CglibSubclassingInstantiationStrategy和SimpleInstantiationStrategy两种实例化bean的类
      public Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException {
           Class clazz = beanDefinition.getBeanClass();
           try {
               if (null != ctor) {
                   return clazz.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args);
               } else {
                   return clazz.getDeclaredConstructor().newInstance();
               }
           } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
               throw new BeansException("Failed to instantiate [" + clazz.getName() + "]", e);
           }
       }
      
    • 修改AbstractAutowireCapableBeanFactory中的createBean方法
      1. 扩展 BeanFactory 接口:提供一个 带参数的 getBean 方法,并在AbstractBeanFactory类中提供一个doGetBean,让使得所有的getBean都使用该方法去注册、获取bean对象。
      2. 修改AbstractAutowireCapableBeanFactory中的createBean方法,定义createBeanInstance方法,让其首先找到合适的构造方法,然后调用instantiate方法创建bean。

四、注入属性和依赖对象

  1. 需求:现有模型还缺少一个类中是否有属性的问题,如果有类中包含属性那么在实例化的时候就需要把属性信息填充上,这样才是一个完整的对象创建。其中属性包括两类:
    • int、long、string对象。
    • 没有实例化的对象属性。
    • ps:目前暂不考虑循环依赖问题。
  2. 思路:扩展BeanDefinition对象,增加其属性,然后在createBean时,将属性注入进来。
    • 扩展 BeanDefinition 对象,增加 PropertyValues 对象
      • PropertyValues 为一个List<PropertyValue>对象
      • PropertyValue 的属性有name和value,如果value的对象为BeanReference则表示该属性存储的为Bean对象,否则则是普通对象。
    • 修改 createBean 方法,使其调用 applyPropertyValues 注入属性
      protected void applyPropertyValues(String beanName, Object com.windranger.bean, BeanDefinition beanDefinition) {
          try {
              PropertyValues propertyValues = beanDefinition.getPropertyValues();
              for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
                  String name = propertyValue.getName();
                  Object value = propertyValue.getValue();
                  if (value instanceof BeanReference) {
                      // A 依赖 B,获取 B 的实例化
                      BeanReference beanReference = (BeanReference) value;
                      value = getBean(beanReference.getBeanName());
                  }
                  // 属性填充
                  BeanUtil.setFieldValue(com.windranger.bean, name, value);
              }
          } catch (Exception e) {
              throw new BeansException("Error setting property values:" + beanName);
          }
      }
      

五、资源加载器解析文件注册对象

  1. 需求:手动操作Bean的定义、注册和属性填充是一件很麻烦的事,为了简化该过程,我们通过配置文件简化了创建过程,本章是从xml中读取配置。
  2. 思路:编写一个用于解析xml文件的工具类。
    • 编写ClassUtils类:用于获取ClassLoader。
    • 定义Resource接口,编写getInputStream方法用于获取输入InputStream。
      1. ClassPathResource:用于获取类资源
      2. FileSystemResource:用于获取文件资源
      3. UrlResource:用于获取网络资源
    • 定义ResourceLoader接口,编写getResource方法用于获取Resource。
      1. DefaultResourceLoader:继承接口,调用Resource的实现类获取资源。
        public Resource getResource(String location) {
            Assert.notNull(location, "Location must not be null");
            if (location.startsWith(CLASSPATH_URL_PREFIX)) {
                return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()));
            } else {
                try {
                    URL url = new URL(location);
                    return new UrlResource(url);
                } catch (MalformedURLException e) {
                    return new FileSystemResource(location);
                }
            }
        }
        
    • 定义BeanDefinitionReader接口,用于加载beanDefinitions
      1. 定义抽象类AbstractBeanDefinitionReader,用于规范ResourceLoader实现
      2. 定义XmlBeanDefinitionReader实现类,实现loadBeanDefinition等方法。实际逻辑在doLoadBeanDefinitions方法中,流程为解析数据,然后注册BeanDefinition。

六、应用上下文

  1. 需求:在对容器中 Bean 的实例化过程添加扩展机制的同时,还需要把目前关于Spring.xml 初始化和加载策略进行优化,因为我们不太可能让面向Spring本身开发的DefaultListableBeanFactory服务,直接给予用户使用。

    image.png

  2. 思路:

    • 定义BeanFactoryPostProcessorBeanPostProcessor接口
      • BeanFactoryPostProcessor中提供postProcessBeanFactory方法,用于在所有BeanDefinition加载完成后,在Bean对象实例化前,提供修改BeanDefinition属性的机制。
      • BeanPostProcessor接口中提供 postProcessBeforeInitialization 方法用于在Bean对象初始化前执行,postProcessAfterInitialization用于在初始化方法后执行。
    • 定义ApplicationContext接口
      • BeanFactory接口中添加根据类型获取bean的方法
      • 定义ListableBeanFactory接口,使其继承BeanFactory接口,并提供了getBeansOfTypegetBeanDefinitionNames方法,分别用于按照类型返回 Bean 实例和返回注册表中所有的Bean名称。
      • ApplicationContext继承ListableBeanFactory接口
    • 定义ConfigurableApplicationContext接口,使其继承于ApplicationContext接口,并且定义重要的方法refresh,该方法用于刷新容器(入口方法,执行所有容器初始化过程)
      • 定义AbstractApplicationContext抽象类,抽象应用上下文。
        public void refresh() throws BeansException {
            // 1. 创建 BeanFactory,并加载 BeanDefinition
            refreshBeanFactory();
        
            // 2. 获取 BeanFactory
            ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        
            // 3. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
            invokeBeanFactoryPostProcessors(beanFactory);
        
            // 4. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
            registerBeanPostProcessors(beanFactory);
        
            // 5. 提前实例化单例Bean对象
            beanFactory.preInstantiateSingletons();
        }
        protected abstract void refreshBeanFactory() throws BeansException;
        
        protected abstract ConfigurableListableBeanFactory getBeanFactory();
        
        private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
            Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
            for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
                beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
            }
        }
        
        private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
            Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
                beanFactory.addBeanPostProcessor(beanPostProcessor);
            }
        }
        
      • 定义AbstractRefreshableApplicationContext类,实现refreshBeanFactory方法
        protected void refreshBeanFactory() throws BeansException {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            loadBeanDefinitions(beanFactory);
            this.beanFactory = beanFactory;
        }
        private DefaultListableBeanFactory createBeanFactory() {
            return new DefaultListableBeanFactory();
        }
        protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory);
        
      • 定义AbstractXmlApplicationContext类,实现loadBeanDefinitions方法
        protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
           XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory, this);
           String[] configLocations = getConfigLocations();
           if (null != configLocations){
               beanDefinitionReader.loadBeanDefinitions(configLocations);
           }
        }
        
      • 定义ClassPathXmlApplicationContext给对外的用户提供上下文方法
    • Bean 创建时完成前置和后置处理
      protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
         Object bean = null;
         try {
             bean = createBeanInstance(beanDefinition, beanName, args);
             // 给 Bean 填充属性
             applyPropertyValues(beanName, bean, beanDefinition);
             // 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法
             bean = initializeBean(beanName, bean, beanDefinition);
         } catch (Exception e) {
             throw new BeansException("Instantiation of bean failed", e);
         }
      
         addSingleton(beanName, bean);
         return bean;
      }
      

七、初始化和销毁方法

  1. 需求:定义bean的初始化和销毁方法
  2. 实现:
    • 定义初始化和销毁方法的接口 InitializingBeanDisposableBean
      • InitializingBean中定义afterPropertiesSet方法,用于属性填充后调用
      • DisposableBean中定义destroy方法,用于销毁时操作。
    • 修改BeanDefinition类,添加initMethodNamedestroyMethodName属性,用于配置初始化方法和销毁方法。
    • 修改AbstractAutowireCapableBeanFactory类,执行Bean对象的初始化方法
      private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
          // 1. 执行 BeanPostProcessor Before 处理
          Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
          // 执行 Bean 对象的初始化方法
          try {
              invokeInitMethods(beanName, wrappedBean, beanDefinition);
          } catch (Exception e) {
              throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", e);
          }
          // 2. 执行 BeanPostProcessor After 处理
          wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
          return wrappedBean;
      }
      
      private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
          // 1. 实现接口 InitializingBean
          if (bean instanceof InitializingBean) {
              ((InitializingBean) bean).afterPropertiesSet();
          }
          // 2. 注解配置 init-method {判断是为了避免二次执行销毁}
          String initMethodName = beanDefinition.getInitMethodName();
          if (StrUtil.isNotEmpty(initMethodName)) {
              Method initMethod = beanDefinition.getBeanClass().getMethod(initMethodName);
              if (null == initMethod) {
                  throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
              }
              initMethod.invoke(bean);
          }
      }
      
    • 定义销毁方法适配器
      • 定义DisposableBeanAdapter类,实现了DisposableBean接口。
         @Override
         public void destroy() throws Exception {
             // 1. 实现接口 DisposableBean
             if (bean instanceof DisposableBean) {
                 ((DisposableBean) bean).destroy();
             }
        
             // 2. 注解配置 destroy-method {判断是为了避免二次执行销毁}
             if (StrUtil.isNotEmpty(destroyMethodName) && !(bean instanceof DisposableBean && "destroy".equals(this.destroyMethodName))) {
                 Method destroyMethod = bean.getClass().getMethod(destroyMethodName);
                 if (null == destroyMethod) {
                     throw new BeansException("Couldn't find a destroy method named '" + destroyMethodName + "' on bean with name '" + beanName + "'");
                 }
                 destroyMethod.invoke(bean);
             }
        
         }
        
      • 定义虚拟机关闭钩子注册调用销毁方法
        @Override
        public void registerShutdownHook() {
            Runtime.getRuntime().addShutdownHook(new Thread(this::close));
         }
        
        @Override
        public void close() {
            getBeanFactory().destroySingletons();
        }
        

八、Aware感知容器对象

  1. 需求:Spring 框架提供的 BeanFactoryApplicationContextBeanClassLoader 等这些能力做一些扩展框架的使用。
  2. 实现:
    • 添加容器感知接口Aware,并定义BeanFactoryAwareBeanClassLoaderAwareBeanNameAwareApplicationContextAwareApplicationContextAwareProcessor接口继承该接口并提供set方法。
    • 注册BeanPostProcessor
      public void refresh() throws BeansException {
          // 1. 创建 BeanFactory,并加载 BeanDefinition
          refreshBeanFactory();
      
          // 2. 获取 BeanFactory
          ConfigurableListableBeanFactory beanFactory = getBeanFactory();
      
          // 3. 添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
          beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
      
          // 4. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
          invokeBeanFactoryPostProcessors(beanFactory);
      
          // 5. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
          registerBeanPostProcessors(beanFactory);
      
          // 6. 提前实例化单例Bean对象
          beanFactory.preInstantiateSingletons();
      }
      
    • 修改AbstractAutowireCapableBeanFactory类,使其在初始化bean的时候将自动注入感知对象
      // invokeAwareMethods
      if (bean instanceof Aware) {
          if (bean instanceof BeanFactoryAware) {
              ((BeanFactoryAware) bean).setBeanFactory(this);
          }
          if (bean instanceof BeanClassLoaderAware){
              ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
          }
          if (bean instanceof BeanNameAware) {
              ((BeanNameAware) bean).setBeanName(beanName);
          }
      }
      

九、对象作用域和FactoryBean

  1. 需求:Spring 创建的对象应当既包括单例也包括原型模式;并且Spring需要提供多种创建Bean的方式。
  2. 实现:
    • 修改 BeanDefinition类,添加scope属性用于描述Bean的作用域,目前包括单例和多例。
    • 修改XmlBeanDefinitionReader,添加获取和设置scope的方法,默认为单例。beanDefinition.setScope(beanScope)
    • 修改AbstractAutowireCapableBeanFactory类,针对单例进行判断,只有在单例时才将Bean注入到单例池中,并注册销毁方法。
    • 定义FactoryBean接口,提供3个方法,获取对象、对象类型,以及是否是单例对象。
    • 定义FactoryBeanRegistrySupport抽象类,使其继承DefaultSingletonBeanRegistry,添加获取FactoryBean的方法。
      • FactoryBeanRegistrySupport 类主要处理的就是关于 FactoryBean 此类对象的注册操作,之所以放到这样一个单独的类里,就是希望做到不同领域模块下只负责各自需要完成的功能,避免因为扩展导致类膨胀到难以维护。
      • 同样这里也定义了缓存操作 factoryBeanObjectCache,用于存放单例类型的对象,避免重复创建。 在日常使用用,基本也都是创建的单例对象。
      • doGetObjectFromFactoryBean 是具体的获取 FactoryBean#getObject() 方法,因为既有缓存的处理也有对象的获取,所以额外提供了 getObjectFromFactoryBean进行逻辑包装。
    • 扩展AbstractBeanFactory这里把 AbstractBeanFactory 原来继承的DefaultSingletonBeanRegistry,修改为继承 FactoryBeanRegistrySupport,需要提供创建FactoryBean对象的能力。

十、容器事件和事件监听器

  1. 需求:添加事件类、事件监听、事件发布等功能
  2. 实现:
    1. 定义事件类ApplicationEvent,继承 java.util.EventObject 定义出具备事件功能的抽象类ApplicationEvent,后续所有事件的类都需要继承这个类。
      • 定义ApplicationContextEvent类,事件的抽象类,所有的事件包括关闭、刷新,以及用户自己实现的事件,都需要继承这个类。
      • 定义ContextClosedEventContextRefreshedEvent类,分别是 Spring 框架自己实现的两个事件类,可以用于监听刷新和关闭动作。
    2. 定义事件广播器ApplicationEventMulticaster,在事件广播器中定义了添加监听和删除监听的方法以及一个广播事件的方法multicastEvent 最终推送时间消息也会经过这个接口方法来处理谁该接收事件。
      • 添加AbstractApplicationEventMulticaster类,该类是对事件广播器的公用方法提取,在这个类中可以实现一些基本功能,避免所有直接实现接口放还需要处理细节。除了像 addApplicationListenerremoveApplicationListener,这样的通用方法,这里这个类中主要是对 getApplicationListenerssupportsEvent 的处理。
      • getApplicationListeners 方法主要是摘取符合广播事件中的监听处理器,具体过滤动作在 supportsEvent 方法中。
      • supportsEvent 方法中,主要包括对 Cglib、Simple 不同实例化需要获取目标Class,Cglib 代理类需要获取父类的 Class,普通实例化的不需要。
    3. 事件发布者的定义和实现,定义ApplicationEventPublisher类,整个一个事件的发布接口,所有的事件都需要从这个接口发布出去。
    4. 修改AbstractApplicationContext类,添加初始化事件发布者、注册事件监听器和发布容器刷新完成事件的方法,用于处理事件。
      • 初始化事件发布者(initApplicationEventMulticaster),主要用于实例化一个SimpleApplicationEventMulticaster,这是一个事件广播器。

      • 注册事件监听器(registerListeners),通过 getBeansOfType 方法获取到所有从spring.xml 中加载到的事件配置 Bean 对象。

      • 发布容器刷新完成事件(finishRefresh),发布了第一个服务器启动完成后的事件,这个事件通过 publishEvent 发布出去,其实也就是调用了applicationEventMulticaster.multicastEvent(event); 方法。

      • 最后是一个 close 方法中,新增加了发布一个容器关闭事件。publishEvent(new ContextClosedEvent(this));