文章目录
- 目标
- 设计流程
- 项目结构
- 一、实现
- 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的资源加载、注册beanDefintion等操作
本章目标是 实现应用上下文,自动创建bean工厂、xml资源加载、实例化前扩展机制、初始化前后置扩展机制等(这也是spring对外提供的上下文api)
设计流程
创建上下文时
1、创建了bean工厂、资源加载xml、户厕bean定义
2、实现实例化前扩展点BeanFactoryPostProcessor,如果有实现该接口,则调用自定义的逻辑处理
3、注册BeanPostProcessor
4、遍历bean定义,创建bean,且在属性填充后,执行初始化前、初始化、初始化后的扩展逻辑处理
项目结构
Spring 应用上下文和对Bean对象扩展机制的类关系,如图
一、实现
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、 实现ConfigurableApplicationContext的refresh()(刷新容器)
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、另外需要提一下,applyBeanPostProcessorsBeforeInitialization、applyBeanPostProcessorsAfterInitialization 两个方法是在接口类 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
这与不用应用上下文的测试结果是一样,不过现在的方式更加方便了。