日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring 钩子之BeanFactoryPostProcessor和BeanPostProcessor

發布時間:2023/12/10 javascript 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring 钩子之BeanFactoryPostProcessor和BeanPostProcessor 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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" />

輸出結果


先打印出了構造器內部執行的話,意味著這個時候實例化了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>() {@Overridepublic 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>() {@Overridepublic 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);}} }

總結

以上是生活随笔為你收集整理的Spring 钩子之BeanFactoryPostProcessor和BeanPostProcessor的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。