文章目录

  • 目标
  • 设计流程
  • 项目结构
  • 一、实现
  • 1、定义实例化前-BeanFactoryPostProcessor
  • 2、定义初始化前后-BeanPostProcessor
  • 3、定义上下文接口--ApplicationContext
  • 4、应用上下文抽象类实现--AbstractBeanFactory
  • 5、获取Bean工厂和加载资源--AbstractRefreshableApplicationContext
  • 6、上下文中对xml配置信息的加载--AbstractXmlApplicationContext
  • 7、应用上下文实现类--ClassPathXmlApplicationContext
  • 8、在Bean创建时完成前置和后置处理
  • 二、测试
  • 1、事先准备
  • 2、 实现 BeanPostProcessor 和 BeanFactoryPostProcessor
  • 3、配置文件
  • 4、不用应用上下文
  • 5、使用应用上下文



目标

本章目标是 实现应用上下文,自动创建bean工厂、xml资源加载、实例化前扩展机制、初始化前后置扩展机制等(这也是spring对外提供的上下文api)

手写单例模式和spring的单例有什么区别吗_加载


设计流程

创建上下文时
1、创建了bean工厂、资源加载xml、注册bean定义
2、实现实例化前扩展点BeanFactoryPostProcessor,如果有实现该接口,则调用自定义的逻辑处理
3、注册BeanPostProcessor
4、遍历bean定义,创建bean,且在属性填充后,执行初始化前、初始化、初始化后的扩展逻辑处理

手写单例模式和spring的单例有什么区别吗_加载_02


项目结构

手写单例模式和spring的单例有什么区别吗_前端_03

Spring 应用上下文和对Bean对象扩展机制的类关系,如图

手写单例模式和spring的单例有什么区别吗_spring_04


BeanFactoryPostProcessor,是由 Spring 框架组建提供的容器扩展机制,允许在 Bean 对象注册后但未实例化之前,对 Bean 的定义信息 BeanDefinition 执行修改操作。

BeanPostProcessor,也是 Spring 提供的扩展机制,不过 BeanPostProcessor 是在 Bean 对象实例化之后修改 Bean 对象,也可以替换 Bean 对象。这部分与后面要实现的 AOP 有着密切的关系。

同时如果只是添加这两个接口,不做任何包装,那么对于使用者来说还是非常麻烦的。所以 Spring 的上下文操作类,把相应的 XML 加载 、注册、实例化以及新增的修改和扩展都融合进去,让 Spring 可以自动扫描到我们的新增服务,便于用户使用


一、实现

1、定义实例化前-BeanFactoryPostProcessor

public interface BeanFactoryPostProcessor {

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

这个接口是满足于在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的扩展机制


2、定义初始化前后-BeanPostProcessor

public interface BeanPostProcessor {


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

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

1、这个接口提供了 Bean 对象的扩展点。

2、提供了两个方法:postProcessBeforeInitialization 用于在 Bean 对象执行初始化方法之前,执行此方法、postProcessAfterInitialization用于在 Bean 对象执行初始化方法之后,执行此方法。


3、定义上下文接口–ApplicationContext

public interface ApplicationContext extends ListableBeanFactory {
}

1、context 是本次实现应用上下文功能新增的服务包

2、ApplicationContext,继承于 ListableBeanFactory,也就继承了关于 BeanFactory 方法,比如一些 getBean 的方法。

3、ApplicationContext 本身是 Central(中央)接口,但目前还不需要添加一些获取ID和父类上下文,所以暂时没有接口方法的定义

ConfigurableApplicationContext

public interface ConfigurableApplicationContext extends ApplicationContext {

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

}

1、ConfigurableApplicationContext 继承自 ApplicationContext,并提供了 refresh 这个核心方法

如果你有看过一些 Spring 源码,那么一定会看到这个方法。 接下来也是需要在上下文的实现中完成刷新容器的操作过程。


4、应用上下文抽象类实现–AbstractBeanFactory

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

	/**
     * @desc: 刷新容器
     **/
    @Override
    @Override
    public void refresh() throws BeansException {
        // 1、创建BeanFactory,并加载BeanDefintion
        refreshBeanFactory();

        // 2、获取beanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // 3、在 Bean 实例化之前,执行 BeanFactoryPostProcesso
        invokeBeanFactoryPostProcessors(beanFactory);

        // 4、BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
        registerBeanPostProcessors(beanFactory);

        // 5. 提前实例化单例Bean对象
        beanFactory.preInstantiateSingletons();
    }

    /**
     * @desc: 实例化bean工厂&获取、加载资源&注册Bean定义
     **/
    protected abstract void refreshBeanFactory() throws BeansException;

    protected abstract ConfigurableListableBeanFactory getBeanFactory();

    /**
     * @desc: bean定义加载后,bean实例化前(对bean定义的扩展)
     **/
    private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    /**
     * @desc: 注册,初始化bean扩展点 
     **/
    private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    }

    /**
     * @desc: 根据类型获取相同类型的map集合
     **/
    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws org.springframework.beans.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);
    }

}

1、AbstractApplicationContext 继承 DefaultResourceLoader 是为了处理 spring.xml 配置资源的加载

2、 实现ConfigurableApplicationContextrefresh()(刷新容器)

refresh() 定义实现过程,包括:

1、创建 BeanFactory,并加载 BeanDefinition
2、获取 BeanFactory
3、在 Bean 实例化之前,执行 BeanFactoryPostProcessor (如果有扩展bean,则执行扩展的逻辑)
4、注册BeanPostProcessor的扩展点 (需要提前于其他 Bean 对象实例化之前执行注册操作)
5、提前实例化单例Bean对象

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


5、获取Bean工厂和加载资源–AbstractRefreshableApplicationContext

/**
 * @desc 获取bean工厂、加载资源
 * @Author: ljc
 * @Date: 2022/12/15 12:03
 */
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext{

    private DefaultListableBeanFactory beanFactory;

    /**
     * @desc: 实例化bean工厂、加载、注册bean定义
     **/
    @Override
    protected void refreshBeanFactory() throws BeansException {
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        loadBeanDefinition(beanFactory);
        this.beanFactory = beanFactory;
    }

    /**
     * @desc: 加载bean定义
     **/
    protected abstract void loadBeanDefinition(DefaultListableBeanFactory beanFactory);

    /**
     * @desc: 创建bean工厂
     **/
    private DefaultListableBeanFactory createBeanFactory(){
        return new DefaultListableBeanFactory();
    }

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

1、继承AbstractApplicationContext ,重写了refreshBeanFactory() 中主要是获取了 DefaultListableBeanFactory 的实例化以及对资源配置的加载操作

2、定义了抽象方法loadBeanDefinitions(beanFactory),在加载完成后即可完成对 spring.xml 配置文件中 Bean 对象的定义和注册

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


6、上下文中对xml配置信息的加载–AbstractXmlApplicationContext

/**
 * @desc 上下文中对xml配置信息的加载
 * @Author: ljc
 * @Date: 2022/12/15 12:12
 */
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableApplicationContext{

    // 加载bean定义
    @Override
    protected void loadBeanDefinition(DefaultListableBeanFactory beanFactory) {
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory, this);
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            xmlBeanDefinitionReader.loadBeanDefinitions(configLocations);
        }
    }

    // 获取配置信息
    protected abstract String[] getConfigLocations();
}

1、继承AbstractRefreshableApplicationContext,重写loadBeanDefinition方法,通过XmlBeanDefinitionReader去加载xml配置信息、解析、注册beanDefintion

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


7、应用上下文实现类–ClassPathXmlApplicationContext

/**
 * @desc xml应用上下文实现类
 * @Author: ljc
 * @Date: 2022/12/15 12:30
 */
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext{

    // 类文件路径
    private String[] configLoadtions;

    /**
     * @desc: 根据路径从 XML 中加载 BeanDefinition,并刷新上下文
     * @return:
     **/
    public ClassPathXmlApplicationContext(String[] configLoadtions) {
        this.configLoadtions = configLoadtions;
        refresh();
    }
    
    public ClassPathXmlApplicationContext(String configLoadtion) {
        this(new String[]{configLoadtion});

    }
    public ClassPathXmlApplicationContext() {

    }

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

1、ClassPathXmlApplicationContext是具体对外给用户提供的应用上下文方法

2、在继承了 AbstractXmlApplicationContext 以及层层抽象类的功能分离实现后,在此类 ClassPathXmlApplicationContext 的实现中就简单多了,主要是对继承抽象类中refresh方法的调用提供了配置文件地址信息


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

/**
 * @desc 实例化Bean类
 * @Author: ljc
 * @Date: 2022/12/7 13:06
 */
public abstract class  AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    /**
     * 创建bean
     * @param beanName
     * @param beanDefinition
     * @param args
     * @return
     * @throws BeansException
     */
    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
        Object bean = null;
        try {
            bean = createBeanInstance(beanName,beanDefinition,args);
            // 属性填充
            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;
    }

    private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
        // 1. 执行 BeanPostProcessor Before 处理
        Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

        // 待完成内容:invokeInitMethods(beanName, wrappedBean, beanDefinition);
        invokeInitMethods(beanName, wrappedBean, beanDefinition);

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


    private void invokeInitMethods(String beanName, Object wrappedBean, BeanDefinition beanDefinition) {

    }


    /**
     * 创建实例
     * @param beanName
     * @param beanDefinition
     * @param args
     * @return
     */
    protected Object createBeanInstance(String beanName, BeanDefinition  beanDefinition, Object[] args) {
        Constructor constructorToUse  = null;
        Class beanClass = beanDefinition.getBeanClass();
        Constructor[] declaredConstructors = beanClass.getDeclaredConstructors();
        for (Constructor ctor : declaredConstructors) {
            if (args != null && ctor.getParameterTypes().length == args.length) {
                constructorToUse  = ctor;
                break;
            }
        }
        return getInstantiationStrategy().instantiate(beanDefinition,beanName,constructorToUse,args);
    }


    /**
     * 属性填充
     * @param beanName
     * @param bean
     * @param beanDefinition
     */
    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) {
                    // 获取 依赖的对象实例化
                    BeanReference beanReference = (BeanReference) value;
                    value = getBean(beanReference.getBeanName());
                }
                BeanUtil.setFieldValue(bean, name, value);
            }
        } catch (BeansException e) {
            throw new BeansException("Error setting property values:" + beanName);
        }
    }

    /**
     * 获取实例化策略
     * @return
     */
    public InstantiationStrategy getInstantiationStrategy() {
        return instantiationStrategy;
    }

    // 定义实例化策略
    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
        this.instantiationStrategy = instantiationStrategy;
    }


    @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;
    }
}

1、实现 BeanPostProcessor 接口后,会涉及到两个接口方法,postProcessBeforeInitialization(初始化前)、postProcessAfterInitialization(初始化后),分别作用于 Bean 对象执行初始化前后的额外处理。

2、在创建 Bean 对象时,在 createBean 方法中添加 initializeBean(beanName, bean, beanDefinition); 操作。而这个操作主要主要是对于方法 applyBeanPostProcessorsBeforeInitialization、applyBeanPostProcessorsAfterInitialization 的使用。

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


二、测试

1、事先准备

public class UserDao {

    private static Map<String, String> hashMap = new HashMap<>();

    static {
        hashMap.put("10001", "ljc");
        hashMap.put("10002", "yaya");
        hashMap.put("10003", "zz");
    }

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

}
public class UserService {

    private String uId;
    private String company;
    private String location;
    private UserDao userDao;

    public String queryUserInfo() {
        return userDao.queryUserName(uId)+", 公司:"+company+", 地点"+location;
    }


    public String getuId() {
        return uId;
    }

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

    public UserDao getUserDao() {
        return userDao;
    }

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

    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;
    }
}

这里新增加了 company、location,两个属性信息,便于测试 BeanPostProcessor、BeanFactoryPostProcessor 两个接口对 Bean 属性信息扩展的作用


2、 实现 BeanPostProcessor 和 BeanFactoryPostProcessor

/**
 * @desc 测试BeanDefinition加载后扩展处理
 * @Author: ljc
 * @Date: 2022/12/15 14: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","改为:网吧"));
    }
}
/**
 * @desc 初始化前后置处理
 * @Author: ljc
 * @Date: 2022/12/15 14:18
 */
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;
    }
}

如果你在 Spring 中做过一些组件的开发那么一定非常熟悉这两个类,本文的测试也是实现了这两个类,对实例化过程中的 Bean 对象做一些操作。


3、配置文件

spring.xml基础配置,无BeanFactoryPostProcessor、BeanPostProcessor,实现类

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

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

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

</beans>

增强配置,有BeanFactoryPostProcessor、BeanPostProcessor,实现类

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

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

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


    <bean class="springframework.test.common.MyBeanPostProcessor"/>
    <bean class="springframework.test.common.MyBeanFactoryPostProcessor"/>

</beans>

这里提供了两个配置文件

一个是不包含BeanFactoryPostProcessor、BeanPostProcessor,

另外一个是包含的。之所以这样配置主要对照验证,在运用 Spring 新增加的应用上下文和不使用的时候,都是怎么操作的


4、不用应用上下文

@Test
public void test_BeanFactoryPostProcessorAndBeanPostProcessor(){
    // 1.初始化 BeanFactory
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

    // 2. 读取配置文件&注册Bean
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
    reader.loadBeanDefinitions("classpath:spring.xml");

    // 3. BeanDefinition 加载完成 & Bean实例化之前,修改 BeanDefinition 的属性值
    MyBeanFactoryPostProcessor beanFactoryPostProcessor = new MyBeanFactoryPostProcessor();
    beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);

    // 4. Bean实例化之后,修改 Bean 属性信息
    MyBeanPostProcessor beanPostProcessor = new MyBeanPostProcessor();
    beanFactory.addBeanPostProcessor(beanPostProcessor);

    // 5. 获取Bean对象调用方法
    UserService userService = beanFactory.getBean("userService", UserService.class);
    String result = userService.queryUserInfo();
    System.out.println("测试结果:" + result);
}

1、DefaultListableBeanFactory 创建 beanFactory 并使用 XmlBeanDefinitionReader 加载配置文件的方式

2、接下来就是对 MyBeanFactoryPostProcessor 和 MyBeanPostProcessor 的处理
一个是在BeanDefinition 加载完成 & Bean实例化之前,修改 BeanDefinition 的属性值
另外一个是在Bean实例化之后,修改 Bean 属性信息


测试结果

测试结果:ljc, 公司:改为:网吧, 地点改为:上海

Process finished with exit code 0

5、使用应用上下文

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

    // 2. 获取Bean对象调用方法
    UserService userService = applicationContext.getBean("userService", UserService.class);
    String result = userService.queryUserInfo();
    System.out.println("测试结果:" + result);
}

1、使用新增加的 ClassPathXmlApplicationContext 应用上下文类,再操作起来就方便多了,这才是面向用户使用的类,在这里可以一步把配置文件交给 ClassPathXmlApplicationContext,也不需要管理一些自定义实现的 Spring 接口的类。

测试结果

测试结果:ljc, 公司:改为:网吧, 地点改为:上海

Process finished with exit code 0

这与不用应用上下文的测试结果是一样,不过现在的方式更加方便了。