Spring 钩子之BeanFactoryPostProcess
BeanFactoryPostProcessor和BeanPostProcessor这两个接口都是初始化bean时对外暴露的入口之一,和Aware类似(PS:关于spring的hook可以看看Spring钩子方法和钩子接口的使用详解讲的蛮详细)本文也主要是学习具体的钩子的细节,以便于实际开发中我们能有效率,例如如何在scala中如何获取springboot的启动类等等,一些中间件为了监控整个系统的服务,也需要获取到spring容器数据和状态。
接下来具体学习和了解下BeanFactoryPostProcessor和BeanPostProcessor。
BeanFactoryPostProcessor
bean工厂的bean属性处理容器,说通俗一些就是可以管理我们的bean工厂内所有的beandefinition(未实例化)数据,可以随心所欲的修改属性。
使用方法
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
/**
* 主要是用来自定义修改持有的bean
* ConfigurableListableBeanFactory 其实就是DefaultListableBeanDefinition对象
* @param beanFactory
* @throws BeansException
*/
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("调用了自定义的BeanFactoryPostProcessor " + beanFactory);
Iterator it = beanFactory.getBeanNamesIterator();
String[] names = beanFactory.getBeanDefinitionNames();
// 获取了所有的bean名称列表
for(int i=0; i<names.length; i++){
String name = names[i];
BeanDefinition bd = beanFactory.getBeanDefinition(name);
System.out.println(name + " bean properties: " + bd.getPropertyValues().toString());
// 本内容只是个demo,打印持有的bean的属性情况
}
}
}
<context:property-placeholder location="pro.properties" />
<bean id="student" class="Student" init-method="init" />
<bean class="CustomBeanFactoryPostProcessor" id="customBeanFactoryPostProcessor" />
输出结果
源码分析
毫无疑问肯定已经解析xml了,继续看refresh函数
AbstractApplicationContext 文件
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// 解析xml完成,存储在一个具体的bean工厂中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// bean工厂的初始化操作
prepareBeanFactory(beanFactory);
try {
// 由子类继承去实现该类,当前该方法为空
postProcessBeanFactory(beanFactory);
// invoke 其中存在的BeanFactoryPostProcessors,也就是我们现在说的
invokeBeanFactoryPostProcessors(beanFactory);
...
PostProcessorRegistrationDelegate 文件
invokeBeanFactoryPostProcessors方法的参数为bean工厂ConfigurableListableBeanFactory和当前已知的postprocessor对象,函数分为了好几部分去处理,截取其中我们关心的部分即可(其实还包含了优先级、属性等类似处理过程)
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// 筛选出bean工程中存在的所有实现BeanFactoryPostProcessor类的类名称
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// 已经存在了,不再处理
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
// 为PriorityOrdered类型
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
// 为Ordered类型
}
else {
nonOrderedPostProcessorNames.add(ppName);
// 这个就是我们当前需要关心的PostProcessors
}
}
...
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
// 获取自定义的BeanFactoryPostProcessor
// 这里有一点需要注意到!!!!
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
上述代码中nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
中使用了getBean,起初没注意到以为是生成具体的对象然后修改,其实不是,getBean后面还有一个参数BeanFactoryPostProcessor.class,注意看这个函数,会发现返回的是一个抽象类,结论就是nonOrderedPostProcessors添加的不是bean实例,而是beandefinition,在实例化前!!!,这点很重要
private static void invokeBeanFactoryPostProcessors(
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanFactory(beanFactory);
// 调用每一个自定义的BeanFactoryPostProcessor的方法
// 在本文章中就会去调用自定义的CustomBeanFactoryPostProcessor的postProcessBeanFactory方法
}
}
再多说一点关于上面的getBeanNamesForType函数,从名字肯定很容易理解了,根据传递的类型获取容器中的beanName。了解下其内部的实现原理
DefaultListableBeanFactory 文件的 getBeanNamesForType函数
// type:类的类型名称
// includeNonSingletons:返回数据包含了非单例beanName
// allowEagerInit: 可以提前加载初始化
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
// 不可用缓存、类型无效、不允许提前加载初始化
// 需要获取当前type的原始类型,继续获取数据
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
Map<Class<?>, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
// 如果缓存已经存储了该数据,则无需再计算,直接返回即可
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
// 这一步就是真正的获取数据,遍历beanDefinitionNames的每一个数据,符合要求的就会加入到返回的列表中
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
// 便于下一次获取,加入缓存中
}
return resolvedBeanNames;
}
BeanPostProcessor
从范围上来说,从上面的所有的bean成为了特定的bean,其次BeanFactoryPostProcessor可以在初始化前修改bean的属性等情况,但是BeanPostProcessor只能在初始化后(注意初始化不包括init方法)执行一些操作。
网上很多文章都说BeanPostProcessor不能修改bean属性,其实我看来未必,当其实例化之后,完全可以拿到实例化后的对象,对对象进行一些改值操作也完全可以的
使用方法
public class Student {
@Value("${name}")
private String className;
public Student() {
System.out.println("constructor loading");
}
public void init(){
System.out.println("init loading");
}
}
public class CustomBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Student){
// 如果当前的bean是Student,则打印日志
System.out.println("postProcessBeforeInitialization bean : " + beanName);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Student){
System.out.println("postProcessAfterInitialization bean : " + beanName);
}
return bean;
}
}
<bean id="student" class="Student" init-method="init" />
<bean class="CustomBeanPostProcessor" id="customBeanPostProcessor" />
输出结果
image.png- 先打印出了构造器内部执行的话,意味着这个时候实例化了Student类,
- 在init方法前执行了postProcessBeforeInitialization
- 在init方法后执行了postProcessAfterInitialization
源码分析
入口依旧是refresh函数,在完成初始化之后,进入到finishBeanFactoryInitialization(beanFactory)
执行BeanPostProcessor的相关操作,中间的流程过长,包含了getBean操作,genBean操作过于繁琐,后续再介绍。
AbstractAutowireCapableBeanFactory 文件
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
// aware同样是对外提供的钩子
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 这一步就是执行自定义的beanpostprocessor的before操作
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
// 执行init方法
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
// 这一步就是执行自定义的beanpostprocessor的after操作
}
return wrappedBean;
}
public Object applyBeanPostProcessorsBeforeInitialization(
Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
// 获取所有的BeanPostProcessor对象,执行postProcessBeforeInitialization方法
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
// 然后把执行结果返回
}
public Object applyBeanPostProcessorsAfterInitialization(
Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
protected void invokeInitMethods(String beanName,
final Object bean, RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null) {
// invoke 反射执行init方法
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}