文章目录
- 一、目标:实现应用上下文
- 二、设计:实现应用上下文
- 三、实现:实现应用上下文
- 3.1 工程结构
- 3.2 Spring应用上下文和Bean对象扩展类图
- 3.3 对象工厂和对象扩展接口
- 3.3.1 对象工厂扩展接口
- 3.3.2 对象扩展接口
- 3.4 定义应用上下文
- 3.4.1 定义上下文接口
- 3.4.2 配置应用上下文接口
- 3.4.3 应用上下文抽象类实现
- 3.4.4 获取Bean工厂和加载资源
- 3.4.5 上下文中对配置信息的加载
- 3.4.6 应用上下文实现类
- 3.5 对象定义读取方法添加
- 3.5.1 对象定义读取接口
- 3.5.2 XML处理对象注册修改
- 3.6 对象工厂整合应用上下文
- 3.6.1 配置Bean工厂接口
- 3.6.2 抽象的Bean工厂基类
- 3.6.3 配置列表Bean工厂接口
- 3.6.4 默认的Bean工厂实现类
- 3.6.5 Bean工厂超类接口
- 3.6.6 在Bean创建时完成前置和后置处理
- 四、测试:实现应用上下文
- 4.1 配置测试环境
- 4.1.1 修改UserService用户对象
- 4.1.2 实现BeanFactoryPostProcessor
- 4.1.3 实现BeanPostProcessor
- 4.1.4 基础配置,无BeanFactoryPostProcessor、BeanPostProcessor实现类
- 4.1.5 增强配置,有BeanFactoryPostProcessor、BeanPostProcessor实现类
- 4.2 单元测试
- 4.2.1 不使用应用上下文测试
- 4.2.2 使用应用上下文
- 五、总结:实现应用上下文
一、目标:实现应用上下文
💡 如何在 Spring 接口的实现中获取 BeanFactory 以及 Bean 对象内容,并对这些内容做一些操作呢?
- 在开发基于 Spring 的技术组件时,你一定会继承或者实现了 Spring 对外暴露的类或接口,在接口的实现中获取 BeanFactory 以及 Bean 对象等内容,并对这些内容做一些操作。
- 例如:修改 Bean 的信息,添加日志打印、处理数据库路由对数据源的切换、给 RPC 服务连接注册中心等。
- 在对容器中 Bean 的实例化过程添加扩展机制的同时,还需要把目前关于
spring.xml
初始化和加载策略进行优化。- 因为我们不太可能让面向 Spring 本身开发的
DefaultListableBeanFactory
服务,直接给予用户使用。
- 因为我们不太可能让面向 Spring 本身开发的
DefaultListableBeanFactory
、XmlBeanDefinitionReader
,是我们在目前 Spring 框架中对于服务功能测试的使用方式,它能很好的体现出 Spring 是如何对xml
加载以及注册 Bean 对象的操作过程,但这种方式是面向 Spring 本身的,还不具备一定的扩展性。- 我们现在需要提供出一个可以在 Bean 初始化过程中,完成对 Bean 对象的扩展时,就很难做到自动化处理。
- 所以我们要把 Bean 对象扩展机制功能和对 Spring 框架上下文的包装融合起来,对外提供完整的服务。
二、设计:实现应用上下文
💡 技术设计:实现应用上下文
- 为了满足:在 Bean 对象从注册到实例化的过程中执行用户的自定义操作。
- 需要在 Bean 的定义和初始化过程中插入接口类,这个接口再由外部去实现自己需要的服务。再结合对 Spring 框架上下文的处理能力。
- 满足于对 Bean 对象扩展的两个接口,其实也是 Spring 框架中具有重量级的两个接口:
BeanFactoryPostProcessor
和BeanPostProcessor
,也几乎是在使用 Spring 框架额外新增开发自己组件需求的两个必备接口。 BeanFactoryPostProcessor
:是由 Spring 框架组件提供的容器扩展机制,允许在 Bean 对象注册后但未实例化之前,对 Bean 的定义信息BeanDefinition
执行修改操作。BeanPostProcessor
:也是 Spring 提供的扩展机制,不过BeanPostProcessor
是在 Bean 对象实例化之后修改 Bean 对象,也可以替换 Bean 对象。这部分与后面的 AOP 密切相关。- 设计:开发 Spring 的上下文操作类,把相应的 XML 加载、注册、实例化以及新增的修改和扩展都融合进去,让 Spring 可以自动扫描到我们的新增服务,便于用户使用。
三、实现:实现应用上下文
3.1 工程结构
spring-step-06
|-src
|-main
| |-java
| |-com.lino.springframework
| |-beans
| | |-factory
| | | |-config
| | | | |-AutowireCapableBeanFactory.java
| | | | |-BeanDefinition.java
| | | | |-BeanFactoryPostProcessor.java
| | | | |-BeanPostProcessor.java
| | | | |-BeanReference.java
| | | | |-ConfigurableBeanFactory.java
| | | | |-SingletonBeanRegistry.java
| | | |-support
| | | | |-AbstractAutowireCapableBeanFactory.java
| | | | |-AbstractBeabDefinitionReader.java
| | | | |-AbstractBeabFactory.java
| | | | |-BeabDefinitionReader.java
| | | | |-BeanDefinitionRegistry.java
| | | | |-CglibSubclassingInstantiationStrategy.java
| | | | |-DefaultListableBeanFactory.java
| | | | |-DefaultSingletonBeanRegistry.java
| | | | |-InstantiationStrategy.java
| | | | |-SimpleInstantiationStrategy.java
| | | |-support
| | | | |-XMLBeanDefinitionReader.java
| | | |-BeanFactory.java
| | | |-ConfigurableListableBeanFactory.java
| | | |-HierarcgicalBeanFactory.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
| |-util
| | |-ClassUtils.java
|-test
|-java
|-com.lino.springframework.test
|-bean
| |-UserDao.java
| |-UserService.java
|-common
| |-MyBeanFactoryPostProcessor.java
| |-MyBeanPostProcessor.java
|-ApiTest.java
|-resources
|-important.properties
|-spring.xml
|-springPostProcessor.xml
3.2 Spring应用上下文和Bean对象扩展类图
- 在整个类图中主要体现出来的是关于 Spring 应用上下文以及对 Bean 对象扩展机制的实现。
- 以继承了
ListableBeanFactory
接口的ApplicationContext
接口开始,扩展出一系列应用上下文的抽象实现类,并最终完成ClassPathXmlApplicationContext
类的实现。而这个类就是最后交给用户使用的类。 - 同时在实现应用上下文的过程中,通过定义接口:
BeanFactoryPostProcessor
、BeanPostProcessor
两个接口,把关于 Bean 的扩展机制串联进去。
3.3 对象工厂和对象扩展接口
3.3.1 对象工厂扩展接口
BeanFactoryPostProcessor.java
package com.lino.springframework.beans.factory.config;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
/**
* @description: 允许自定义修改 BeanDefinition 属性信息
*/
public interface BeanFactoryPostProcessor {
/**
* 在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的机制
*
* @param beanFactory 对象工厂
* @throws BeansException 对象异常
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
- 这个接口是满足于在所有的
BeanDefinition
加载完成后,实例化 Bean 对象之前,提供修改BeanDefinition
属性的机制。
3.3.2 对象扩展接口
BeanPostProcessor.java
package com.lino.springframework.beans.factory.config;
import com.lino.springframework.beans.BeansException;
/**
* @description: 用于修改新实例化 Bean 对象的扩展点
*/
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;
}
- 提供了修改新实例化 Bean 对象的扩展点。
- 此接口提供了两个方法。
postProcessBeforeInitialization
:用于在 Bean 对象执行初始化方法之前,执行此方法。postProcessAfterInitialization
:用于在 Bean 对象执行初始化方法之后,执行此方法。
3.4 定义应用上下文
3.4.1 定义上下文接口
ApplicationContext.java
package com.lino.springframework.context;
import com.lino.springframework.beans.factory.ListableBeanFactory;
/**
* @description: 应用上下文接口
*/
public interface ApplicationContext extends ListableBeanFactory {
}
context
是本次实现应用上下文功能新增的服务包。ApplicationContext
,继承于ListableBeanFactory
,也就是继承了关于BeanFactory
方法。比如一些getBean
的方法。- 另外
ApplicationContext
本身是Central
接口,后续会扩展。
- 另外
3.4.2 配置应用上下文接口
ConfigurableApplicationContext.java
package com.lino.springframework.context;
import com.lino.springframework.beans.BeansException;
/**
* @description: SPI 接口配置应用上下文
*/
public interface ConfigurableApplicationContext extends ApplicationContext {
/**
* 刷新容器
*
* @throws BeansException 对象异常
*/
void refresh() throws BeansException;
}
ConfigurableApplicationContext
继承自ApplicationContext
,并提供了refresh
这个核心方法。- 接下来也是需要在上下文的实现中完成刷新容器的操作过程。
3.4.3 应用上下文抽象类实现
AbstractApplicationContext.java
package com.lino.springframework.context.support;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanFactoryPostProcessor;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.context.ConfigurableApplicationContext;
import com.lino.springframework.core.io.DefaultResourceLoader;
import java.util.Map;
/**
* @description: 抽象应用上下文
*/
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 实例化之前,执行 BeanFactoryPostProcess
invokeBeanFactoryPostProcessor(beanFactory);
// 4.BeanPostProcessor 需要提前与其他 Bean 对象实例化之前执行注册操作
registerBeanPostProcessor(beanFactory);
// 5.提前实例化单例 Bean 对象
beanFactory.preInstantiateSingletons();
}
/**
* 创建 BeanFactory,并加载 BeanDefinition
*
* @throws BeansException 异常
*/
protected abstract void refreshBeanFactory() throws BeansException;
/**
* 获取对象工厂
*
* @return 配置列表 Bean工厂接口
*/
protected abstract ConfigurableListableBeanFactory getBeanFactory();
private void invokeBeanFactoryPostProcessor(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
}
}
private void registerBeanPostProcessor(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()
定义实现过程。- 创建 BeanFactory,并加载 BeanDefinition。
- 获取 BeanFactory。
- 在 Bean 实例化之前,执行 BeanFactoryPostProcessor。
- BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作。
- 提前实例化单例 Bean 对象。
- 另外把定义出来的抽象方法:
refreshBeanFactory()
、getBeanFactory()
由后面的继承此抽象类的其它抽象类实现。
3.4.4 获取Bean工厂和加载资源
AbstractRefreshableApplicationContext.java
package com.lino.springframework.context.support;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.lino.springframework.beans.factory.support.DefaultListableBeanFactory;
/**
* @description: 抽象基类刷新应用上下文
*/
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();
}
/**
* 加载Bean对象
*
* @param beanFactory 对象工厂
*/
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)
,继续由其他抽象类继承实现。
3.4.5 上下文中对配置信息的加载
AbstractXmlApplicationContext.java
package com.lino.springframework.context.support;
import com.lino.springframework.beans.factory.support.DefaultListableBeanFactory;
import com.lino.springframework.beans.factory.xml.XMLBeanDefinitionReader;
/**
* @description: 抽象基类 XML 上下文
*/
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);
}
}
/**
* 获取配置
*
* @return 字符串列表
*/
protected abstract String[] getConfigLocations();
}
- 在
AbstractXmlApplicationContext
抽象类的loadBeanDefinitions
方法实现中,使用 XMLBeanDefinitionReader 类,处理了关于 XML 文件配置信息的操作。 - 同时这里又留下一个抽象类方法,
getConfigLocations()
,此方法是为了从入口上下文类,拿到配置信息的地址描述。
3.4.6 应用上下文实现类
ClassPathXmlApplicationContext.java
package com.lino.springframework.context.support;
import com.lino.springframework.beans.BeansException;
/**
* @description: XML 文件应用上下文
*/
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
的实现中就简单多,主要是对继承抽象类中方法的调用和提供配置文件地址信息。
3.5 对象定义读取方法添加
3.5.1 对象定义读取接口
BeanDefinitionReader.java
package com.lino.springframework.beans.factory.support;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.core.io.Resource;
import com.lino.springframework.core.io.ResourceLoader;
/**
* @description: Bean定义读取接口
*/
public interface BeanDefinitionReader {
/**
* 获取bean对象注册对象
*
* @return bean对象注册对象
*/
BeanDefinitionRegistry getRegistry();
/**
* 获取资源加载器
*
* @return 资源加载器
*/
ResourceLoader getResourceLoader();
/**
* 加载bean定义方法
*
* @param resource 资源
* @throws BeansException bean异常
*/
void loadBeanDefinitions(Resource resource) throws BeansException;
/**
* 加载bean定义方法
*
* @param resources 资源列表
* @throws BeansException bean异常
*/
void loadBeanDefinitions(Resource... resources) throws BeansException;
/**
* 加载bean定义方法
*
* @param location 路径名称
* @throws BeansException bean异常
*/
void loadBeanDefinitions(String location) throws BeansException;
/**
* 加载bean定义方法
*
* @param locations 路径名称
* @throws BeansException bean异常
*/
void loadBeanDefinitions(String... locations) throws BeansException;
}
- 定价加载 Bean 定义方法:
loadBeanDefinitions(String... locations)
,支持多地址的参数构造。
3.5.2 XML处理对象注册修改
XMLBeanDefinitionReader.java
package com.lino.springframework.beans.factory.xml;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanReference;
import com.lino.springframework.beans.factory.support.AbstractBeanDefinitionReader;
import com.lino.springframework.beans.factory.support.BeanDefinitionRegistry;
import com.lino.springframework.core.io.Resource;
import com.lino.springframework.core.io.ResourceLoader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.io.IOException;
import java.io.InputStream;
/**
* @description: XML处理Bean注册
*/
public class XMLBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XMLBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
public XMLBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
super(registry, resourceLoader);
}
@Override
public void loadBeanDefinitions(Resource resource) throws BeansException {
try {
try (InputStream inputStream = resource.getInputStream()) {
doLoadBeanDefinitions(inputStream);
}
} catch (IOException | ClassNotFoundException e) {
throw new BeansException("IOException parsing XML document from " + resource, e);
}
}
@Override
public void loadBeanDefinitions(Resource... resources) throws BeansException {
for (Resource resource : resources) {
loadBeanDefinitions(resource);
}
}
@Override
public void loadBeanDefinitions(String location) throws BeansException {
ResourceLoader resourceLoader = getResourceLoader();
Resource resource = resourceLoader.getResource(location);
loadBeanDefinitions(resource);
}
@Override
public void loadBeanDefinitions(String... locations) throws BeansException {
for (String location : locations) {
loadBeanDefinitions(location);
}
}
protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {
Document doc = XmlUtil.readXML(inputStream);
Element root = doc.getDocumentElement();
NodeList childNodes = root.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
// 判断元素
if (!(childNodes.item(i) instanceof Element)) {
continue;
}
// 判断对象
if (!"bean".equals(childNodes.item(i).getNodeName())) {
continue;
}
// 解析标签
Element bean = (Element) childNodes.item(i);
String id = bean.getAttribute("id");
String name = bean.getAttribute("name");
String className = bean.getAttribute("class");
// 获取 Class, 方便获取类中的名称
Class<?> clazz = Class.forName(className);
// 优先级 id > name
String beanName = StrUtil.isNotEmpty(id) ? id : name;
if (StrUtil.isEmpty(beanName)) {
beanName = StrUtil.lowerFirst(clazz.getSimpleName());
}
// 定义bean
BeanDefinition beanDefinition = new BeanDefinition(clazz);
// 读取属性并填充
for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
// 判断元素
if (!(bean.getChildNodes().item(j) instanceof Element)) {
continue;
}
// 判断对象
if (!"property".equals(bean.getChildNodes().item(j).getNodeName())) {
continue;
}
// 解析标签:property
Element property = (Element) bean.getChildNodes().item(j);
String attrName = property.getAttribute("name");
String attrValue = property.getAttribute("value");
String attrRef = property.getAttribute("ref");
// 获取属性值:引入对象、值对象
Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;
// 创建属性信息
PropertyValue propertyValue = new PropertyValue(attrName, value);
beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
}
if (getRegistry().containsBeanDefinition(beanName)) {
throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
}
// 注册 BeanDefinition
getRegistry().registerBeanDefinition(beanName, beanDefinition);
}
}
}
3.6 对象工厂整合应用上下文
3.6.1 配置Bean工厂接口
ConfigurableBeanFactory.java
package com.lino.springframework.beans.factory.config;
import com.lino.springframework.beans.factory.HierarchicalBeanFactory;
/**
* @description: 配置Bean工厂接口
*/
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
/**
* 添加修改新实例化 Bean 对象的扩展点
*
* @param beanPostProcessor 新实例化 Bean 对象
*/
void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
}
3.6.2 抽象的Bean工厂基类
AbstractBeanFactory.java
package com.lino.springframework.beans.factory.support;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.beans.factory.config.ConfigurableBeanFactory;
import java.util.ArrayList;
import java.util.List;
/**
* @description: 抽象的 Bean 工厂基类,定义模板方法
*/
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {
private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, args);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return (T) getBean(name);
}
protected <T> T doGetBean(final String name, final Object[] args) {
Object bean = getSingleton(name);
if (bean != null) {
return (T) bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return (T) createBean(name, beanDefinition, args);
}
/**
* 获取 Bean 对象
*
* @param beanName 要检索的bean的名称
* @return Bean 对象
*/
protected abstract BeanDefinition getBeanDefinition(String beanName);
/**
* 创建Bean对象
*
* @param beanName 要检索的bean的名称
* @param beanDefinition Bean对象
* @param args 构造函数入参
* @return 实例化的Bean对象
*/
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args);
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
}
public List<BeanPostProcessor> getBeanPostProcessors() {
return beanPostProcessors;
}
}
3.6.3 配置列表Bean工厂接口
ConfigurableListableBeanFactory.java
package com.lino.springframework.beans.factory;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.config.AutowireCapableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.ConfigurableBeanFactory;
/**
* @description: 配置列表 Bean工厂接口
*/
public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
/**
* 根据对象名称获取bean对象
*
* @param beanName 对象名称
* @return bean对象
* @throws BeansException bean异常
*/
BeanDefinition getBeanDefinition(String beanName) throws BeansException;
/**
* 实例化单例 Bean 对象
*
* @throws BeansException bean异常
*/
void preInstantiateSingletons() throws BeansException;
}
- 添加实例化单例 Bean 对象方法。
3.6.4 默认的Bean工厂实现类
DefaultListableBeanFactory.java
package com.lino.springframework.beans.factory.support;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import java.util.HashMap;
import java.util.Map;
/**
* @description: 默认的Bean工厂实现类
*/
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry, ConfigurableListableBeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
@Override
public BeanDefinition getBeanDefinition(String beanName) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition == null) {
throw new BeansException("No bean named '" + beanName + "' is defined");
}
return beanDefinition;
}
@Override
public void preInstantiateSingletons() throws BeansException {
beanDefinitionMap.keySet().forEach(this::getBean);
}
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
beanDefinitionMap.put(beanName, beanDefinition);
}
@Override
public boolean containsBeanDefinition(String beanName) {
return beanDefinitionMap.containsKey(beanName);
}
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
Map<String, T> result = new HashMap<>(16);
beanDefinitionMap.forEach((beanName, beanDefinition) -> {
Class beanClass = beanDefinition.getBeanClass();
if (type.isAssignableFrom(beanClass)) {
result.put(beanName, (T) getBean(beanName));
}
});
return result;
}
@Override
public String[] getBeanDefinitionNames() {
return beanDefinitionMap.keySet().toArray(new String[0]);
}
}
3.6.5 Bean工厂超类接口
AutowireCapableBeanFactory.java
package com.lino.springframework.beans.factory.config;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.BeanFactory;
/**
* @description: Bean工厂超类接口
*/
public interface AutowireCapableBeanFactory extends BeanFactory {
/**
* 执行 BeanPostProcessors 接口实现类的 postProcessorsBeforeInitialization 方法
*
* @param existingBean 现有的对象
* @param beanName 对象名称
* @return 新对象
* @throws BeansException 异常
*/
Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException;
/**
* 执行 BeanPostProcessors 接口实现类的 postProcessorsAfterInitialization 方法
*
* @param existingBean 现有的对象
* @param beanName 对象名称
* @return 新对象
* @throws BeansException 异常
*/
Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException;
}
- 添加了执行
BeanPostProcessors
接口实现类的前置和后置操作。
3.6.6 在Bean创建时完成前置和后置处理
AbstractAutowireCapableBeanFactory.java
package com.lino.springframework.beans.factory.support;
import cn.hutool.core.bean.BeanUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.config.AutowireCapableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.beans.factory.config.BeanReference;
import java.lang.reflect.Constructor;
/**
* @description: 实现默认bean创建的抽象bean工厂超类
*/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
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);
}
registerSingletonBean(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(wrappedBean, beanName);
return wrappedBean;
}
private void invokeInitMethods(String beanName, Object wrappedBean, BeanDefinition beanDefinition) {
}
private 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) {
// 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);
}
}
protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
Constructor constructorToUse = null;
Class<?> beanClass = beanDefinition.getBeanClass();
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for (Constructor ctor : declaredConstructors) {
if (null != args && ctor.getParameterTypes().length == args.length) {
constructorToUse = ctor;
break;
}
}
return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
}
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;
}
}
- 实现
BeanPostProcessor
接口后,会涉及到两个接口方法:postProcessBeforeInitialization
、postProcessAfterInitialization
。- 分别作用于 Bean 对象执行初始化前后的额外处理。
- 也就是需要在创建 Bean 对象时,在
createBean
方法中添加initializeBean(beanName, bean, beanDefinition)
操作。- 这个操作方法主要是对于前置和后置方法的使用。
applyBeanPostProcessorsBeforeInitialization()
applyBeanPostProcessorsAfterInitialization()
- 这个操作方法主要是对于前置和后置方法的使用。
四、测试:实现应用上下文
4.1 配置测试环境
4.1.1 修改UserService用户对象
UserService.java
package com.lino.springframework.test.bean;
/**
* @description: 模拟用户 Bean 对象
*/
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 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;
}
}
- 添加
company
和location
字段。
4.1.2 实现BeanFactoryPostProcessor
MyBeanFactoryPostProcessor.java
package com.lino.springframework.test.common;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanFactoryPostProcessor;
/**
* @description: BeanFactoryPostProcessor 实例化 Bean 对象之前,修改 BeanDefinition 属性
*/
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", "改为:字节跳动"));
}
}
4.1.3 实现BeanPostProcessor
MyBeanPostProcessor.java
package com.lino.springframework.test.common;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.test.bean.UserService;
/**
* @description: BeanPostProcessor 在 Bean 对象执行初始化方法前后进行扩展
*/
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;
}
}
4.1.4 基础配置,无BeanFactoryPostProcessor、BeanPostProcessor实现类
spring.xml
<?xml version="1.0" encoding="utf-8" ?>
<beans>
<bean id="userDao" class="com.lino.springframework.test.bean.UserDao"/>
<bean id="userService" class="com.lino.springframework.test.bean.UserService">
<property name="uId" value="10001"/>
<property name="company" value="阿里"/>
<property name="location" value="杭州"/>
<property name="userDao" ref="userDao"/>
</bean>
</beans>
4.1.5 增强配置,有BeanFactoryPostProcessor、BeanPostProcessor实现类
springPostProcessor.xml
<?xml version="1.0" encoding="utf-8" ?>
<beans>
<bean id="userDao" class="com.lino.springframework.test.bean.UserDao"/>
<bean id="userService" class="com.lino.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="com.lino.springframework.test.common.MyBeanPostProcessor"/>
<bean class="com.lino.springframework.test.common.MyBeanFactoryPostProcessor"/>
</beans>
- 这里提供两个配置文件,一个不包含
BeanFactoryPostProcessor、BeanPostProcessor
,另外一个是包含的。
4.2 单元测试
4.2.1 不使用应用上下文测试
ApiTest.java
@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 属性信息。
测试结果
测试结果:张三,改为:字节跳动,改为:温州
- 从测试结果来看,我们配置的属性信息和
spring.xml
配置文件中不一样了。
4.2.2 使用应用上下文
ApiTest.java
@Test
public void test_xml() {
// 1.初始化 BeanFactory
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:springPostProcessor.xml");
// 3.获取Bean对象调用方法
UserService userService = applicationContext.getBean("userService", UserService.class);
String result = userService.queryUserInfo();
System.out.println("测试结果:" + result);
}
- 新增 ClassPathXmlApplicationContext 应用上下文,再操作起来就方便很多。
- 在这里可以一步把配置文件交给 ClassPathXmlApplicationContext,也不需要管理一些自定义实现的 Spring 接口的类。
测试结果
测试结果:张三,改为:字节跳动,改为:温州
五、总结:实现应用上下文
- 新增加了 Spring 框架中两个非常重要的接口
BeanFactoryPostProcessor、BeanPostProcessor
同时还添加了关于应用上下文的实现。ApplicationContext
接口的定义是继承BeanFactory
外新增加功能的接口,它可以满足于自动识别、资源加载、容器事件、监听器等功能。- 同时例如一些国际化支持、单例 Bean 自动初始化等,也是可以再这个类里实现和扩充的。
- 通过本节的实现了解
BeanFactoryPostProcessor、BeanPostProcessor
,以后再做一些关于 Spring 中间件的开发时,如果需要用到 Bean 对象的获取以及修改一些属性信息,那么就可以使用这两个接口了。同时BeanPostProcessor
也是实现 AOP 切面技术的关键所在。