乐趣区

关于java:我想挑战下我的软肋动手实现个Spring应用上下文

作者:小傅哥
博客:https://bugstack.cn

积淀、分享、成长,让本人和别人都能有所播种!😄

目录

  • [x] 第 1 章:开篇介绍,我要带你撸 Spring 啦!
  • [x] 第 2 章:小试牛刀,实现一个简略的 Bean 容器
  • [x] 第 3 章:初显身手,使用设计模式,实现 Bean 的定义、注册、获取
  • [x] 第 4 章:锋芒毕露,基于 Cglib 实现含构造函数的类实例化策略
  • [x] 第 5 章:一举成名,为 Bean 对象注入属性和依赖 Bean 的性能实现
  • [x] 第 6 章:气吞山河,设计与实现资源加载器,从 Spring.xml 解析和注册 Bean 对象
  • [x] 第 7 章:所向无敌,实现利用上下文,自动识别、资源加载、扩大机制
  • [] 第 8 章:待归档 …

一、前言

你这代码,可不能写死了呀!

按照我的项目落地教训来看,咱们在承接紧急的产品需要时候,通常会抉择在原有同类我的项目中进行扩大,如果没有相干类型我的项目的储备,也可能会抉择长期搭建出一个工程来实现产品的需要。但这个时候就会遇到十分事实的问题,抉择残缺的设计和开发就可能满足不了上线工夫,长期拼凑式的实现需要又可能不具备上线后响应产品的长期调整。

上线后的调整有哪些呢?我的项目刚一上线,经营了还不到半天,老板发现自己的配置的流动如同金额配置的太小了,用户都不来,割不到韭菜呀。连忙中午分割产品,来来来,你给我这改改,那修修,把人均优惠 1 万元放大大的,把可能两字放大放在前面。再把优惠的奖金池配置从 10 元调整 11 元,快快快,连忙批改,你批改了咱们能赚 1 个亿!!!

好家伙,我的项目是长期开发堆进去的,没有后盾零碎、没有配置核心、没有模块拆分,老板一句句改改改,产品来传播督促,最初背锅的可就是研发了。你这不能写死,这优惠配置得抽出来,这文案也后盾下发吧,这接口入参也写死了,再写一个新接口吧! 一顿操作猛如虎,研发搬砖修接口,经营折腾好几宿,最初 PV150!

无论业务、产品、经营如何,但就研发本身来讲,尽可能的要不防止长期堆出一个服务来,尤其是在团队建设初期或者经营思路常常调整的状况下,更要重视设计细节和实现计划。哪怕去报危险延期,也不要让本人背上一个明知是烂坑还要接的活。

而本章节说到 不把代码写死 ,就是因为咱们须要持续在手写 Spring 框架中持续扩大新的性能,如一个 Bean 的定义和实例化的过程前后,是否能够满足咱们进行自定义扩大,对 Bean 对象执行一些批改、加强、记录等操作呢? 这个过程根本就是你在应用 Spring 容器框架时候做的一些中间件扩大开发。

二、指标

如果你在本人的理论工作中开发过基于 Spring 的技术组件,或者学习过对于 SpringBoot 中间件设计和开发 等内容。那么你肯定会继承或者实现了 Spring 对外裸露的类或接口,在接口的实现中获取了 BeanFactory 以及 Bean 对象的获取等内容,并对这些内容做一些操作,例如:批改 Bean 的信息,增加日志打印、解决数据库路由对数据源的切换、给 RPC 服务连贯注册核心等。

在对容器中 Bean 的实例化过程增加扩大机制的同时,还须要把目前对于 Spring.xml 初始化和加载策略进行优化,因为咱们不太可能让面向 Spring 自身开发的 DefaultListableBeanFactory 服务,间接给予用户应用。批改点如下:

  • DefaultListableBeanFactory、XmlBeanDefinitionReader,是咱们在目前 Spring 框架中对于服务功能测试的应用形式,它能很好的体现出 Spring 是如何对 xml 加载以及注册 Bean 对象的操作过程,但这种形式是面向 Spring 自身的,还不具备肯定的扩展性。
  • 就像咱们当初须要提供出一个能够在 Bean 初始化过程中,实现对 Bean 对象的扩大时,就很难做到自动化解决。所以咱们要把 Bean 对象扩大机制性能和对 Spring 框架上下文的包装交融起来,对外提供残缺的服务。

三、设计

为了能满足于在 Bean 对象从注册到实例化的过程中执行用户的自定义操作,就须要在 Bean 的定义和初始化过程中插入接口类,这个接口再有内部去实现本人须要的服务。那么在联合对 Spring 框架上下文的解决能力,就能够满足咱们的指标需要了。整体设计构造如下图:

  • 满足于对 Bean 对象扩大的两个接口,其实也是 Spring 框架中十分具备重量级的两个接口:BeanFactoryPostProcessBeanPostProcessor,也简直是大家在应用 Spring 框架额定新增开发本人组建需要的两个必备接口。
  • BeanFactoryPostProcessor,是由 Spring 框架组建提供的容器扩大机制,容许在 Bean 对象注册后但未实例化之前,对 Bean 的定义信息 BeanDefinition 执行批改操作。
  • BeanPostProcessor,也是 Spring 提供的扩大机制,不过 BeanPostProcessor 是在 Bean 对象实例化之后批改 Bean 对象,也能够替换 Bean 对象。这部分与前面要实现的 AOP 有着亲密的关系。
  • 同时如果只是增加这两个接口,不做任何包装,那么对于使用者来说还是十分麻烦的。咱们心愿于开发 Spring 的上下文操作类,把相应的 XML 加载、注册、实例化以及新增的批改和扩大都交融进去,让 Spring 能够主动扫描到咱们的新增服务,便于用户应用。

四、实现

1. 工程构造

small-spring-step-06
└── src
    ├── main
    │   └── java
    │       └── cn.bugstack.springframework
    │           ├── beans
    │           │   ├── factory
    │           │   │   ├── factory
    │           │   │   │   ├── AutowireCapableBeanFactory.java
    │           │   │   │   ├── BeanDefinition.java
    │           │   │   │   ├── BeanFactoryPostProcessor.java
    │           │   │   │   ├── BeanPostProcessor.java
    │           │   │   │   ├── BeanReference.java
    │           │   │   │   ├── ConfigurableBeanFactory.java
    │           │   │   │   └── SingletonBeanRegistry.java
    │           │   │   ├── support
    │           │   │   │   ├── AbstractAutowireCapableBeanFactory.java
    │           │   │   │   ├── AbstractBeanDefinitionReader.java
    │           │   │   │   ├── AbstractBeanFactory.java
    │           │   │   │   ├── BeanDefinitionReader.java
    │           │   │   │   ├── BeanDefinitionRegistry.java
    │           │   │   │   ├── CglibSubclassingInstantiationStrategy.java
    │           │   │   │   ├── DefaultListableBeanFactory.java
    │           │   │   │   ├── DefaultSingletonBeanRegistry.java
    │           │   │   │   ├── InstantiationStrategy.java
    │           │   │   │   └── SimpleInstantiationStrategy.java  
    │           │   │   ├── support
    │           │   │   │   └── XmlBeanDefinitionReader.java
    │           │   │   ├── BeanFactory.java
    │           │   │   ├── ConfigurableListableBeanFactory.java
    │           │   │   ├── HierarchicalBeanFactory.java
    │           │   │   └── ListableBeanFactory.java
    │           │   ├── BeansException.java
    │           │   ├── PropertyValue.java
    │           │   └── PropertyValues.java 
    │           ├── context
    │           │   ├── support
    │           │   │   ├── AbstractApplicationContext.java 
    │           │   │   ├── AbstractRefreshableApplicationContext.java 
    │           │   │   ├── AbstractXmlApplicationContext.java 
    │           │   │   └── ClassPathXmlApplicationContext.java 
    │           │   ├── ApplicationContext.java 
    │           │   └── ConfigurableApplicationContext.java
    │           ├── core.io
    │           │   ├── ClassPathResource.java 
    │           │   ├── DefaultResourceLoader.java 
    │           │   ├── FileSystemResource.java 
    │           │   ├── Resource.java 
    │           │   ├── ResourceLoader.java 
    │           │   └── UrlResource.java
    │           └── utils
    │               └── ClassUtils.java
    └── test
        └── java
            └── cn.bugstack.springframework.test
                ├── bean
                │   ├── UserDao.java
                │   └── UserService.java  
                ├── common
                │   ├── MyBeanFactoryPostProcessor.java
                │   └── MyBeanPostProcessor.java
                └── ApiTest.java

工程源码 公众号「bugstack 虫洞栈」,回复:Spring 专栏,获取残缺源码

Spring 利用上下文和对 Bean 对象扩大机制的类关系,如图 7-3

  • 在整个类图中次要体现进去的是对于 Spring 利用上下文以及对 Bean 对象扩大机制的实现。
  • 以继承了 ListableBeanFactory 接口的 ApplicationContext 接口开始,扩大出一系列利用上下文的形象实现类,并最终实现 ClassPathXmlApplicationContext 类的实现。而这个类就是最初交给用户应用的类。
  • 同时在实现利用上下文的过程中,通过定义接口:BeanFactoryPostProcessorBeanPostProcessor 两个接口,把对于对 Bean 的扩大机制串联进去了。

2. 定义 BeanFactoryPostProcessor

cn.bugstack.springframework.beans.factory.config.BeanFactoryPostProcessor

public interface BeanFactoryPostProcessor {

    /**
     * 在所有的 BeanDefinition 加载实现后,实例化 Bean 对象之前,提供批改 BeanDefinition 属性的机制
     *
     * @param beanFactory
     * @throws BeansException
     */
    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 属性的机制。

3. 定义 BeanPostProcessor

cn.bugstack.springframework.beans.factory.config.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;

}
  • 在 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 对象执行初始化办法之后,执行此办法。

4. 定义上下文接口

cn.bugstack.springframework.context.ApplicationContext

public interface ApplicationContext extends ListableBeanFactory {}
  • context 是本次实现利用上下文性能新增的服务包
  • ApplicationContext,继承于 ListableBeanFactory,也就继承了对于 BeanFactory 办法,比方一些 getBean 的办法。另外 ApplicationContext 自身是 Central 接口,但目前还不须要增加一些获取 ID 和父类上下文,所以临时没有接口办法的定义。

cn.bugstack.springframework.context.ConfigurableApplicationContext

public interface ConfigurableApplicationContext extends ApplicationContext {

    /**
     * 刷新容器
     *
     * @throws BeansException
     */
    void refresh() throws BeansException;}
  • ConfigurableApplicationContext 继承自 ApplicationContext,并提供了 refresh 这个外围办法。如果你有看过一些 Spring 源码,那么肯定会看到这个办法。 接下来也是须要在上下文的实现中实现刷新容器的操作过程。

5. 利用上下文抽象类实现

cn.bugstack.springframework.context.support.AbstractApplicationContext

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 (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);
        }
    }
    
    //... getBean、getBeansOfType、getBeanDefinitionNames 办法

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

      1. 创立 BeanFactory,并加载 BeanDefinition
      1. 获取 BeanFactory
      1. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
      1. BeanPostProcessor 须要提前于其余 Bean 对象实例化之前执行注册操作
      1. 提前实例化单例 Bean 对象
  • 另外把定义进去的形象办法,refreshBeanFactory()、getBeanFactory() 由前面的继承此抽象类的其余抽象类实现。

6. 获取 Bean 工厂和加载资源

cn.bugstack.springframework.context.support.AbstractRefreshableApplicationContext

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {

    private DefaultListableBeanFactory beanFactory;

    @Override
    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);

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

}
  • 在 refreshBeanFactory() 中次要是获取了 DefaultListableBeanFactory 的实例化以及对资源配置的加载操作 loadBeanDefinitions(beanFactory),在加载实现后即可实现对 spring.xml 配置文件中 Bean 对象的定义和注册,同时也包含实现了接口 BeanFactoryPostProcessor、BeanPostProcessor 的配置 Bean 信息。
  • 但此时资源加载还只是定义了一个抽象类办法 loadBeanDefinitions(DefaultListableBeanFactory beanFactory),持续由其余抽象类继承实现。

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

cn.bugstack.springframework.context.support.AbstractXmlApplicationContext

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableApplicationContext {

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory, this);
        String[] configLocations = getConfigLocations();
        if (null != configLocations){beanDefinitionReader.loadBeanDefinitions(configLocations);
        }
    }

    protected abstract String[] getConfigLocations();

}
  • 在 AbstractXmlApplicationContext 抽象类的 loadBeanDefinitions 办法实现中,应用 XmlBeanDefinitionReader 类,解决了对于 XML 文件配置信息的操作。
  • 同时这里又留下了一个抽象类办法,getConfigLocations(),此办法是为了从入口上下文类,拿到配置信息的地址形容。

8. 利用上下文实现类(ClassPathXmlApplicationContext)

cn.bugstack.springframework.context.support.ClassPathXmlApplicationContext

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {private String[] configLocations;

    public ClassPathXmlApplicationContext() {}

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

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

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

}
  • ClassPathXmlApplicationContext,是具体对外给用户提供的利用上下文办法。
  • 在继承了 AbstractXmlApplicationContext 以及层层抽象类的性能拆散实现后,在此类 ClassPathXmlApplicationContext 的实现中就简略多了,次要是对继承抽象类中办法的调用和提供了配置文件地址信息。

9. 在 Bean 创立时实现前置和后置解决

cn.bugstack.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

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

    public InstantiationStrategy getInstantiationStrategy() {return instantiationStrategy;}

    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {this.instantiationStrategy = instantiationStrategy;}

    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) { }

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

}
  • 实现 BeanPostProcessor 接口后,会波及到两个接口办法,postProcessBeforeInitializationpostProcessAfterInitialization,别离作用于 Bean 对象执行初始化前后的额定解决。
  • 也就是须要在创立 Bean 对象时,在 createBean 办法中增加 initializeBean(beanName, bean, beanDefinition); 操作。而这个操作次要次要是对于办法 applyBeanPostProcessorsBeforeInitializationapplyBeanPostProcessorsAfterInitialization 的应用。
  • 另外须要提一下,applyBeanPostProcessorsBeforeInitialization、applyBeanPostProcessorsAfterInitialization 两个办法是在接口类 AutowireCapableBeanFactory 中新减少的。

五、测试

1. 当时筹备

cn.bugstack.springframework.test.bean.UserDao

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

}

cn.bugstack.springframework.test.bean.UserService

public class UserService {

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

    public void queryUserInfo() {return userDao.queryUserName(uId);
    }

    // ...get/set
}
  • Dao、Service,是咱们平时开发常常应用的场景。在 UserService 中注入 UserDao,这样就能体现出 Bean 属性的依赖了。
  • 另外这里新减少了 company、location,两个属性信息,便于测试 BeanPostProcessor、BeanFactoryPostProcessor 两个接口对 Bean 属性信息扩大的作用。

2. 实现 BeanPostProcessor 和 BeanFactoryPostProcessor

cn.bugstack.springframework.test.common.MyBeanFactoryPostProcessor

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", "改为:字节跳动"));
    }

}

cn.bugstack.springframework.test.common.MyBeanPostProcessor

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. 配置文件

根底配置,无 BeanFactoryPostProcessor、BeanPostProcessor,实现类

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

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

    <bean id="userService" class="cn.bugstack.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="cn.bugstack.springframework.test.bean.UserDao"/>

    <bean id="userService" class="cn.bugstack.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="cn.bugstack.springframework.test.common.MyBeanPostProcessor"/>
    <bean class="cn.bugstack.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);
}
  • DefaultListableBeanFactory 创立 beanFactory 并应用 XmlBeanDefinitionReader 加载配置文件的形式,还是比拟相熟的。
  • 接下来就是对 MyBeanFactoryPostProcessor 和 MyBeanPostProcessor 的解决,一个是在 BeanDefinition 加载实现 & Bean 实例化之前,批改 BeanDefinition 的属性值,另外一个是在 Bean 实例化之后,批改 Bean 属性信息。

测试后果

测试后果:小傅哥, 改为:字节跳动, 改为:北京

Process finished with exit code 0
  • 通过测试后果能够看到,咱们配置的属性信息曾经与 spring.xml 配置文件中不一样了。

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);
}
  • 另外应用新减少的 ClassPathXmlApplicationContext 利用上下文类,再操作起来就不便多了,这才是面向用户应用的类,在这里能够一步把配置文件交给 ClassPathXmlApplicationContext,也不须要治理一些自定义实现的 Spring 接口的类。

测试后果

测试后果:小傅哥, 改为:字节跳动, 改为:北京

Process finished with exit code 0
  • 这与不必利用上下文的测试后果是一样,不过当初的形式更加不便了。

六、总结

  • 本文次要新增了 Spring 框架中两个十分重要的接口 BeanFactoryPostProcess、BeanPostProcessor 同时还增加了对于利用上下文的实现,ApplicationContext 接口的定义是继承 BeanFactory 外新减少性能的接口,它能够满足于自动识别、资源加载、容器事件、监听器等性能,同时例如一些国际化反对、单例 Bean 主动初始化等,也是能够在这个类里实现和裁减的。
  • 通过本文的实现肯定会十分理解 BeanFactoryPostProcess、BeanPostProcessor,当前再做一些对于 Spring 中间件的开发时,如果须要用到 Bean 对象的获取以及批改一些属性信息,那么就能够应用这两个接口了。同时 BeanPostProcessor 也是实现 AOP 切面技术的关键所在。
  • 有人问:面试问那么多,可是工作又用不到,是嘎哈么呢?,嘎哈么,那你说你开车上桥的时候,会每次都撞两边的护栏吗,不撞是吧,那不要修了哇,间接就铺一个平板,还省资料了。其实核心技术的原理学习,是更有助于你实现更简单的架构设计,当你的常识能更全面笼罩所承接的需要时,也就能更好的做出正当的架构和落地。

七、系列举荐

  • 小傅哥,一个有“副业”的码农!
  • 久等了,小傅哥的《重学 Java 设计模式》终于出版了,彩印 & 纸质!
  • 半年招聘筛选了 400+ 份简历,通知你怎么写容易被撩!
  • 一次代码评审,差点过不了试用期!
  • 大学四年到毕业工作 5 年的学习路线资源汇总
退出移动版