beanfactorypostprocessor_用BeanPostProcessor和BeanFactoryPostProcessor修改bean的属性

分享自己在Java方面的所思所想,希望你看完之后能有更多更深入的了解

30043198b817e9189f3296dc6f1a271a.png

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

输出结果

721f197bcd519ebdc4d31e0f66ceffc1.png

源码分析

毫无疑问肯定已经解析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 priorityOrderedPostProcessors = new ArrayList(); List orderedPostProcessorNames = new ArrayList(); List nonOrderedPostProcessorNames = new ArrayList(); 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 nonOrderedPostProcessors = new ArrayList(); 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, 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; }}

输出结果

e37f4dcb17629556b78c8893d6f2ce1d.png
  • 先打印出了构造器内部执行的话,意味着这个时候实例化了Student类,
  • 在init方法前执行了postProcessBeforeInitialization
  • 在init方法后执行了postProcessAfterInitialization

源码分析

入口依旧是refresh函数,在完成初始化之后,进入到finishBeanFactoryInitialization(beanFactory)执行BeanPostProcessor的相关操作,中间的流程过长,包含了getBean操作,genBean操作过于繁琐,后续再介绍。

55768b8aa4d9e476c40b7bf3ec20295f.png

AbstractAutowireCapableBeanFactory 文件

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction() { @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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值