每天叫醒你的不是闹钟,而是梦想
● 续言
前面我们已经提到Spring的BeanFactory工厂了,回顾请点击 -> 这一行代码到底做了什么?,那么我们如何通过这个BeanFactory来干涉Spring Bean的构建呢?
● BeanFactoryPostProcessor的使用
Spring为了让我们方便干涉Bean工厂,提供一个BeanFactoryPostProcessor接口。
@Component
public class BeanFactoryPostProcessorImpl implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
// 获取memberService得BeanDefinition对象。
GenericBeanDefinition memberDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("memberServer");
// 用context.getBean(UserService.class)拿UserService对象
// 修改memberDefinition的Bean类
memberDefinition.setBeanClass(UserService.class);
}
}
我们只是把MemberService交给Spring进行管理,而UserService并没有。但是由于我们通过BeanFactoryPostProcessor来干涉Bean的创建,造成的结果是:
// 不可以取到MemberService的bean对象
context.getBean(MemberService.class);
// 可以取到UserService的bean对象
context.getBean(UserService.class);
● BeanFactoryPostProcessor执行时机
在第一篇的推文中有写到,AnnotationConfigApplicationContext的构造器会调用refresh的方法。这一个方法可以说是Spring中最重要的方法了。我们不得不来研究它里面做了些什么事情。
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
//准备工作包括设置启动时间,是否激活标识位
this.prepareRefresh();
//返回一个bean工厂
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//准备工厂
this.prepareBeanFactory(beanFactory);
try {
//这个方法在当前版本是没有代码的,
this.postProcessBeanFactory(beanFactory);
//在spring的环境中去执行已经被注册的factory Processors
//设置执行自定义的ProcessBeanFactory和spring内部自己定义ProcessBeanFactory
//重要用来扫描并且注册到我们beanDefinitionMap中
//beanDefinitionNames也有存上一份
this.invokeBeanFactoryPostProcessors(beanFactory);
//注册beanPostProcessor
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
//实例化bean的方法
//里面调用beanFactory.preInstantiateSingletons()实例化
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
在this.invokeBeanFactoryPostProcessors(beanFactory)执行前的beandefinitionMap的数据,有6个是spring在此前自己注册的,还有一个是我们的java配置类。spring注册的处理器主要是根据java配置类的规则,判断出那些类要交给Spring产生Bean对象。把那些符合规则的类,生成一个BeanDefinition对象,存进beandefinitionMap里面,并且在beanDefinitionNames也存放它的名字。
而我们自己写的BeanFactoryPostProcesssor是在Spring自己的Processor执行完后在执行的,因为Spring的那些执行完,才可以取得到我们那些带@Component的类。
● 有图有真相
this.invokeBeanFactoryPostProcessors(beanFactory)执行前的断点图
this.invokeBeanFactoryPostProcessors(beanFactory)执行后的断点图
finishBeanFactoryInitialization(beanFactory)方法的作用是创建出Bean的,而那些BeanFactoryPostProcessor是在他之前执行的。那么我们就可以通过改变beandefinitionMap存放的信息,最终改变创建出来的Bean。
专注分享Java技术,跟我一起学习吧
长按识别二维码关注