手写简易版Spring框架(五):实现Spring应用上下文、扩展机制

目标

如果你在自己的实际工作中开发过基于 Spring 的技术组件,或者学习过关于 SpringBoot 中间件设计和开发 等内容。那么你一定会继承或者实现了 Spring 对外暴露的类或接口,在接口的实现中获取了 BeanFactory 以及 Bean 对象的获取等内容,并对这些内容做一些操作,例如:修改 Bean 的信息,添加日志打印等。

在对容器中 Bean 的实例化过程添加扩展机制的同时,还需要把目前关于 Spring.xml 初始化和加载策略进行优化,因为我们不太可能让面向 Spring 本身开发的 DefaultListableBeanFactory 服务,直接给予用户使用。修改点如下:
在这里插入图片描述
DefaultListableBeanFactory、XmlBeanDefinitionReader,是我们在目前 Spring 框架中对于服务功能测试的使用方式,它能很好的体现出 Spring 是如何对 xml 加载以及注册Bean对象的操作过程,但这种方式是面向 Spring 本身的,还不具备一定的扩展性。就像我们现在需要提供出一个可以在 Bean 初始化过程中,完成对 Bean 对象的扩展时,就很难做到自动化处理。所以我们要把 Bean 对象扩展机制功能和对 Spring 框架上下文的包装融合起来,对外提供完整的服务。

设计

在这里插入图片描述

  • 满足于对 Bean 对象扩展的两个接口,其实也是 Spring框架中非常具有重量级的两个接口:BeanFactoryPostProcess 和 BeanPostProcessor,也几乎是大家在使用Spring 框架额外新增开发自己组建需求的两个必备接口。
  • BeanFactoryPostProcessor,是由 Spring 框架组建提供的容器扩展机制,允许在 Bean对象注册后但未实例化之前,对 Bean 的定义信息 BeanDefinition 执行修改操作。
  • BeanPostProcessor,也是 Spring 提供的扩展机制,不过 BeanPostProcessor 是在 Bean对象实例化之后修改 Bean 对象,也可以替换 Bean 对象。这部分与后面要实现的 AOP 有着密切的关系。
  • 同时如果只是添加这两个接口,不做任何包装,那么对于使用者来说还是非常麻烦的。我们希望于开发 Spring 的上下文操作类,把相应的 XML加载 、注册、实例化以及新增的修改和扩展都融合进去,让 Spring 可以自动扫描到我们的新增服务,便于用户使用。

实现

定义 BeanFactoryPostProcessor

package com.qingyun.springframework.beans.factory.config;

import com.qingyun.springframework.beans.BeansException;
import com.qingyun.springframework.beans.factory.ConfigurableListableBeanFactory;

/**
 * @description: 允许自定义修改 BeanDefinition 属性信息
 * @author: 張青云
 * @create: 2021-08-21 17:10
 **/
public interface BeanFactoryPostProcessor {
    
    

    /**
     * 在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的机制
     */
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

在 Spring 源码中有这样一段描述 Allows for custom modification of an application context’s bean definitions,adapting the bean property values of the context’s underlying bean factory. 其实也就是说这个接口是满足于在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的机制。

定义 BeanPostProcessor

package com.qingyun.springframework.beans.factory.config;

import com.qingyun.springframework.beans.BeansException;

/**
 * @description: 用于修改新实例化 Bean 对象的扩展点
 * @author: 張青云
 * @create: 2021-08-21 17:11
 **/
public interface BeanPostProcessor {
    
    

    /**
     * 在 Bean 对象执行初始化方法之前,执行此方法
     */
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

    /**
     * 在 Bean 对象执行初始化方法之后,执行此方法
     */
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

在 Spring 源码中有这样一段描述 Factory hook that allows for custom modification of new bean instances,e.g. checking for marker interfaces or wrapping them with proxies.也就是提供了修改新实例化 Bean 对象的扩展点。另外此接口提供了两个方法:postProcessBeforeInitialization 用于在 Bean 对象执行初始化方法之前,执行此方法、postProcessAfterInitialization用于在 Bean 对象执行初始化方法之后,执行此方法。

定义上下文接口

public interface ApplicationContext extends ListableBeanFactory {
    
    
}

context 是本次实现应用上下文功能新增的服务包ApplicationContext,继承于 ListableBeanFactory,也就继承了关于 BeanFactory 方法,比如一些 getBean 的方法。另外 ApplicationContext 本身是 Central 接口,但目前还不需要添加一些获取ID和父类上下文,所以暂时没有接口方法的定义。

package com.qingyun.springframework.context;

import com.qingyun.springframework.beans.BeansException;

/**
 *
 * @author: 張青云
 * @create: 2021-08-21 17:25
 **/
public interface ConfigurableApplicationContext extends ApplicationContext {
    
    

    /**
     * 刷新容器
     */
    void refresh() throws BeansException;
}

ConfigurableApplicationContext 继承自 ApplicationContext,并提供了 refresh 这个核心方法。如果你有看过一些 Spring 源码,那么一定会看到这个方法。 接下来也是需要在上下文的实现中完成刷新容器的操作过程。

应用上下文抽象类实现

package com.qingyun.springframework.context.support;

import com.qingyun.springframework.beans.BeansException;
import com.qingyun.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.qingyun.springframework.beans.factory.config.BeanFactoryPostProcessor;
import com.qingyun.springframework.beans.factory.config.BeanPostProcessor;
import com.qingyun.springframework.context.ConfigurableApplicationContext;
import com.qingyun.springframework.core.io.DefaultResourceLoader;

import java.util.Map;

/**
 * @description: 抽象应用上下文
 * @author: 張青云
 * @create: 2021-08-21 17:26
 **/
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
    
    

    @Override
    public void refresh() throws BeansException {
    
    
        // 1. 创建BeanFactory,并加载、注册BeanDefinition
        refreshBeanFactory();

        // 2. 获取 BeanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // 3. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor
        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) {
    
    
        //  获取BeanFactoryPostProcessor的实例对象(这一步会完成从Bean的定义信息到实例对象的转变)
        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);
        }
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
    
    
        return getBeanFactory().getBeansOfType(type);
    }

    @Override
    public String[] getBeanDefinitionNames() {
    
    
        return getBeanFactory().getBeanDefinitionNames();
    }

    @Override
    public Object getBean(String name) throws BeansException {
    
    
        return getBeanFactory().getBean(name);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
    
    
        return getBeanFactory().getBean(name, args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    
    
        return getBeanFactory().getBean(name, requiredType);
    }

}

AbstractApplicationContext 继承 DefaultResourceLoader 是为了处理 spring.xml 配置资源的加载。
之后是在 refresh() 定义实现过程,包括:

  1. 创建 BeanFactory,并加载 BeanDefinition
  2. 获取 BeanFactory
  3. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
  4. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
  5. 提前实例化单例Bean对象

另外把定义出来的抽象方法,refreshBeanFactory()、getBeanFactory() 由后面的继承此抽象类的其他抽象类实现。

获取Bean工厂和加载资源

package com.qingyun.springframework.context.support;

import com.qingyun.springframework.beans.BeansException;
import com.qingyun.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.qingyun.springframework.beans.factory.support.DefaultListableBeanFactory;

/**
 * 完成BeanFactory的创建和Bean定义信息的加载注册
 * @author: 張青云
 * @create: 2021-08-21 18:35
 **/
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
    
    

    private DefaultListableBeanFactory beanFactory;

    @Override
    protected void refreshBeanFactory() throws BeansException {
    
    
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        //  加载bean的定义信息
        loadBeanDefinitions(beanFactory);
        this.beanFactory = beanFactory;
    }

    @Override
    protected ConfigurableListableBeanFactory getBeanFactory() {
    
    
        return beanFactory;
    }

    private DefaultListableBeanFactory createBeanFactory() {
    
    
        return new DefaultListableBeanFactory();
    }

    protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory);

}

在 refreshBeanFactory() 中主要是获取了 DefaultListableBeanFactory 的实例化以及对资源配置的加载操作 loadBeanDefinitions(beanFactory),在加载完成后即可完成对 spring.xml 配置文件中 Bean 对象的定义和注册,同时也包括实现了接口 BeanFactoryPostProcessor、BeanPostProcessor 的配置 Bean 信息。

但此时资源加载还只是定义了一个抽象类方法 loadBeanDefinitions(DefaultListableBeanFactory beanFactory),继续由其他抽象类继承实现。

上下文中对配置信息的加载

package com.qingyun.springframework.context.support;

import com.qingyun.springframework.beans.factory.support.DefaultListableBeanFactory;
import com.qingyun.springframework.beans.factory.xml.XmlBeanDefinitionReader;

/**
 * 从Xml文件中加载Bean定义信息
 * @author: 張青云
 * @create: 2021-08-21 18:37
 **/
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableApplicationContext {
    
    
    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
    
    
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory, this);
        String[] configLocations = getConfigLocations();
        if (null != configLocations && configLocations.length != 0){
    
    
            beanDefinitionReader.loadBeanDefinitions(configLocations);
        }
    }

    /**
     * 获取XML配置文件的路径地址
     */
    protected abstract String[] getConfigLocations();
}

在 AbstractXmlApplicationContext 抽象类的 loadBeanDefinitions 方法实现中,使用 XmlBeanDefinitionReader 类,处理了关于 XML 文件配置信息的操作。

同时这里又留下了一个抽象类方法,getConfigLocations(),此方法是为了从入口上下文类,拿到配置信息的地址描述。

应用上下文实现类(ClassPathXmlApplicationContext)

package com.qingyun.springframework.context.support;

import com.qingyun.springframework.beans.BeansException;

/**
 * @description: XML文件应用上下文
 * @author: 張青云
 * @create: 2021-08-21 19:33
 **/
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
    
    

    //  配置文件的路径地址
    private String[] configLocations;

    public ClassPathXmlApplicationContext() {
    
    
    }

    /**
     * 从 XML 中加载 BeanDefinition,并刷新上下文
     */
    public ClassPathXmlApplicationContext(String configLocations) throws BeansException {
    
    
        this(new String[]{
    
    configLocations});
    }

    /**
     * 从 XML 中加载 BeanDefinition,并刷新上下文
     */
    public ClassPathXmlApplicationContext(String[] configLocations) throws BeansException {
    
    
        this.configLocations = configLocations;
        refresh();
    }

    @Override
    protected String[] getConfigLocations() {
    
    
        return configLocations;
    }

}

ClassPathXmlApplicationContext,是具体对外给用户提供的应用上下文方法。在继承了 AbstractXmlApplicationContext 以及层层抽象类的功能分离实现后,在此类 ClassPathXmlApplicationContext 的实现中就简单多了,主要是对继承抽象类中方法的调用和提供了配置文件地址信息。

在Bean创建时完成前置和后置处理

package com.qingyun.springframework.beans.factory.support;

import cn.hutool.core.bean.BeanUtil;
import com.qingyun.springframework.beans.BeansException;
import com.qingyun.springframework.beans.factory.PropertyValue;
import com.qingyun.springframework.beans.factory.PropertyValues;
import com.qingyun.springframework.beans.factory.config.AutowireCapableBeanFactory;
import com.qingyun.springframework.beans.factory.config.BeanDefinition;
import com.qingyun.springframework.beans.factory.config.BeanPostProcessor;
import com.qingyun.springframework.beans.factory.config.BeanReference;

import java.lang.reflect.Constructor;

/**
 * @description: 实现了根据BeanDefinition去创建bean的能力
 * @author: 張青云
 * @create: 2021-08-18 18:29
 **/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
    
    
    //  指定实例化方式的策略,默认使用JDK反射的方式
    private InstantiationStrategy instantiation = new SimpleInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
    
    
        Object bean = null;
        try {
    
    
            //  实例化bean
            bean = createBeanInstance(beanDefinition, beanName, args);
            //  对bean对象进行属性填充
            if (beanDefinition.getPropertyValues() != null &&
                    beanDefinition.getPropertyValues().getPropertyValues().length != 0) {
    
    
                applyPropertyValues(beanName, bean, beanDefinition);
            }
            // 执行Bean的初始化方法和BeanPostProcessor的前置和后置处理方法
            bean = initializeBean(beanName, bean, beanDefinition);
        } catch (Exception e) {
    
    
            throw new BeansException("Instantiation of bean failed", e);
        }
        return bean;
    }

    /**
     * 创建bean实例
     */
    protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
    
    
        Constructor usedConstructor = null;
        Constructor[] constructors = beanDefinition.getBeanClass().getDeclaredConstructors();

        for (Constructor ctor: constructors) {
    
    
            if (args != null && ctor.getParameterTypes().length == args.length) {
    
    
                Class[] parameterTypes = ctor.getParameterTypes();
                for (int i = 0; i < parameterTypes.length; i++) {
    
    
                    if (parameterTypes[i] != args[i].getClass()) {
    
    
                        break;
                    }
                }
                usedConstructor = ctor;
                break;
            }
        }
        return instantiation.instantiate(beanName, beanDefinition, usedConstructor, args);
    }

    /**
     * 属性填充
     */
    protected void applyPropertyValues(String beanName, Object 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) {
    
    
                    //  TODO 没有解决循环依赖问题
                    //  A依赖B,获取B的实例
                    BeanReference beanReference = (BeanReference) value;
                    value = getBean(beanReference.getBeanName());
                }
                // 属性填充
                BeanUtil.setFieldValue(bean, name, value);
            }
        } catch (Exception e) {
    
    
            throw new BeansException("Error setting property values:" + beanName);
        }
    }

    /**
     * 初始化Bean的过程
     */
    private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
    
    
        // 1. 执行 BeanPostProcessor Before 处理
        Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

        // TODO Bean的初始化方法
        invokeInitMethods(beanName, wrappedBean, beanDefinition);

        // 2. 执行 BeanPostProcessor After 处理
        wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        return wrappedBean;
    }

    /**
     * 初始化方法
     */
    private void invokeInitMethods(String beanName, Object wrappedBean, BeanDefinition beanDefinition) {
    
    

    }

    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
    
    
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
    
    
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            if (null == current) return result;
            result = current;
        }
        return result;
    }

    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
    
    
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
    
    
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (null == current) return result;
            result = current;
        }
        return result;
    }

    public void setInstantiation(InstantiationStrategy instantiation) {
    
    
        this.instantiation = instantiation;
    }
}

实现 BeanPostProcessor 接口后,会涉及到两个接口方法,postProcessBeforeInitialization、postProcessAfterInitialization,分别作用于 Bean 对象执行初始化前后的额外处理。也就是需要在创建 Bean 对象时,在 createBean 方法中添加 initializeBean(beanName, bean, beanDefinition)操作。而这个操作主要主要是对于方法 applyBeanPostProcessorsBeforeInitialization、applyBeanPostProcessorsAfterInitialization 的使用。

另外需要提一下,applyBeanPostProcessorsBeforeInitialization、applyBeanPostProcessorsAfterInitialization 两个方法是在接口类 AutowireCapableBeanFactory 中新增加的。

测试

事先准备

package com.qingyun.springframework.context.test;

import java.util.HashMap;
import java.util.Map;

/**
 * @description:
 * @author: 張青云
 * @create: 2021-08-19 00:13
 **/
public class UserDao {
    
    
    private static Map<String, String> hashMap = new HashMap<>();

    static {
    
    
        hashMap.put("10001", "青云先生");
        hashMap.put("10002", "張青云");
        hashMap.put("10003", "云鸽");
    }

    public String queryUserName(String uId) {
    
    
        return hashMap.get(uId);
    }
}

package com.qingyun.springframework.context.test;

/**
 * @description:
 * @author: 張青云
 * @create: 2021-08-18 22:54
 **/
public class UserService {
    
    
    private String uId;
    private String company;
    private String location;
    private UserDao userDao;

    public UserService() {
    
    
    }

    public String getuId() {
    
    
        return uId;
    }

    public void setuId(String uId) {
    
    
        this.uId = uId;
    }

    public String getCompany() {
    
    
        return company;
    }

    public void setCompany(String company) {
    
    
        this.company = company;
    }

    public String getLocation() {
    
    
        return location;
    }

    public void setLocation(String location) {
    
    
        this.location = location;
    }

    public UserDao getUserDao() {
    
    
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
    
    
        this.userDao = userDao;
    }

    public void queryUserInfo() {
    
    
        System.out.println("查询用户信息:" + userDao.queryUserName(uId));
    }

    @Override
    public String toString() {
    
    
        return "UserService{" +
                "uId='" + uId + '\'' +
                ", company='" + company + '\'' +
                ", location='" + location + '\'' +
                ", userDao=" + userDao +
                '}';
    }
}

BeanFactoryPostProcessor:

package com.qingyun.springframework.context.test;

import com.qingyun.springframework.beans.BeansException;
import com.qingyun.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.qingyun.springframework.beans.factory.PropertyValue;
import com.qingyun.springframework.beans.factory.PropertyValues;
import com.qingyun.springframework.beans.factory.config.BeanDefinition;
import com.qingyun.springframework.beans.factory.config.BeanFactoryPostProcessor;

/**
 * @description:
 * @author: 張青云
 * @create: 2021-08-21 21:15
 **/
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
    

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    

        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");
        PropertyValues propertyValues = beanDefinition.getPropertyValues();

        propertyValues.addPropertyValue(new PropertyValue("company", "字节跳动(改)"));
    }

}

BeanPostProcessor:

package com.qingyun.springframework.context.test;

import com.qingyun.springframework.beans.BeansException;
import com.qingyun.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @description:
 * @author: 張青云
 * @create: 2021-08-21 21:16
 **/
public class MyBeanPostProcessor implements BeanPostProcessor {
    
    

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        if ("userService".equals(beanName)) {
    
    
            UserService userService = (UserService) bean;
            userService.setLocation("北京(改)");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
        return bean;
    }

}

XML配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <bean id="userDao" class="com.qingyun.springframework.context.test.UserDao"/>

    <bean id="userService" class="com.qingyun.springframework.context.test.UserService">
        <property name="uId" value="10001"/>
        <property name="company" value="腾讯"/>
        <property name="location" value="深圳"/>
        <property name="userDao" ref="userDao"/>
    </bean>

    <bean class="com.qingyun.springframework.context.test.MyBeanPostProcessor"/>
    <bean class="com.qingyun.springframework.context.test.MyBeanFactoryPostProcessor"/>

</beans>

单元测试:

    @Test
    public void test_context() {
    
    
        // 1.初始化 BeanFactory
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");

        // 2. 获取Bean对象调用方法
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.queryUserInfo();

        System.out.println(userService);
    }

结果:
在这里插入图片描述
通过测试结果可以看到,我们配置的属性信息已经与 spring.xml 配置文件中不一样了。

项目代码Github地址:https://github.com/Zhang-Qing-Yun/mini-spring,本节代码对应的commit标识为1b926d2

欢迎标星

猜你喜欢

转载自blog.csdn.net/zhang_qing_yun/article/details/119845283