您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關Spring源碼中BeanPostProcessor的原理是什么,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
Spring具有很好的擴展性,但是這個擴展它的這個擴展性體現在哪里呢?而我們要說的BeanPostProcessor就是對Spring擴展性優秀的表現之一。
簡單的說就是BeanPostProcessor提供了初始化前后回調的方法,我們所說的擴展就是在實例化前后對Bean進行擴展。
BeanDefinition注冊完成之后進行注冊,在創建Bean過程中的實例化前后分別調用其中定義的方法;
其操作對象為:已經實例化且進行了屬性填充,待初始化的Bean實例。
public interface BeanPostProcessor { /** * 初始前調用 */ @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } /** * 初始化后調用 */ @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
上面就是BeanPostProcessor接口的定義,從方法名字也能看出這兩個方法一個在初始化前調用一個在初始化后調用。
注意的是,方法的返回值為原始實例或者包裝后的實例。如果返回null會導致后續的BeanPostProcessor不生效(BeanPostProcessor是可以注冊多個的)。
BeanPostProcessorDemo代碼如下:
public class BeanPostProcessorDemo { public static void main(String[] args) { //創建基礎容器 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); //加載xml配置文件 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions("spring-bean-post-processor.xml"); //添加BeanPostProcessor beanFactory.addBeanPostProcessor(new UserBeanPostProcessor()); User user = beanFactory.getBean(User.class); System.out.println(user); } } @Data class User{ private String userName; private Integer age; private String beforeMessage; private String afterMessage; public void initMethod(){ System.out.println("初始化:"+this); this.setUserName("小明"); this.setAge(18); } } class UserBeanPostProcessor implements BeanPostProcessor{ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof User){ System.out.println("初始化前:"+bean); ((User) bean).setBeforeMessage("初始化前信息"); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof User){ System.out.println("初始化后:"+bean); ((User) bean).setAfterMessage("初始化后信息"); } return bean; } }
其他的省略......
運行之后打印結果如下:
初始化前:User(userName=null, age=null, beforeMessage=null, afterMessage=null) 初始化:User(userName=null, age=null, beforeMessage=初始化前信息, afterMessage=null) 初始化后:User(userName=小明, age=18, beforeMessage=初始化前信息, afterMessage=null) User(userName=小明, age=18, beforeMessage=初始化前信息, afterMessage=初始化后信息)
上面的代碼很簡單就是創建基礎的容器,因為我這個里面用的是BeanFactory,BeanFactory作為基礎容器是這里我采用手動將BeanPostProcessor注冊到容器中去的。 同時也可以采用掃描或者定義的方式生成到容器中。
下面分析打印結果:
初始化前:User(userName=null, age=null, beforeMessage=null, afterMessage=null) 該結果是postProcessBeforeInitialization方法中輸出的內容,這個時候User實例還只是進行了實例化,還未進行到初始化步驟,所以所有的屬性都為null,說明該方法確實是初始化執行的。——(此時的初始化指的是bean對象的init方法)
初始化:User(userName=null, age=null, beforeMessage=初始化前信息, afterMessage=null) 該結果為自定義的初始化方法initMethod方法中輸出的內容,這個時候User實例真正初始化,而beforeMessage中中的值正是我們在postProcessBeforeInitialization設置的。
初始化后:User(userName=小明, age=18, beforeMessage=初始化前信息, afterMessage=null) 該結果是postProcessAfterInitialization中輸出內容,從打印結果可以看出它的確是在自定義initMethod后。
Spring中Bean總體上來說可以分為四個周期:實例化、屬性賦值、初始化、銷毀。而BeanPostProcessor則是在初始化階段的前后執行。
首先看AbstractAutowireCapableBeanFactory中doCreateBean方法,該方法實際就是創建指定Bean的方法。
其中三個重要的方法調用如下:createBeanInstance、populateBean、initializeBean。
這三個方法分別代表了Spring Bean中的實例化、屬性賦值和初始化三個生命周期。
BeanPostProcessor是在初始化前后調用,所以我們查看initializeBean中的方法詳情即可。該方法詳情如下:
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { //處理BeanNameAware、BeanClassLoaderAware、BeanFactoryAware if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } //處理BeanPostProcessor Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { //回調postProcessBeforeInitialization方法 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { //處理InitializingBean和BeanDefinition中指定的initMethod invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { //回調postProcessAfterInitialization方法 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
從上面的源碼可以看出首先是處理部分Aware相關接口,然后接著就是處理BeanPostProcessor中的postProcessBeforeInitialization方法,該方法詳情如下:
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; //依次處理BeanPostProcessor for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessBeforeInitialization(result, beanName); //如果放回null,則直接返回后續BeanPostProcessor中的 // postProcessBeforeInitialization不再執行 if (current == null) { return result; } result = current; } return result; }
該方法就是執行postProcessBeforeInitialization回調的詳情內容,從該實現可以知道,BeanPostProcessor可以有多個,而且會按照順序依次處理。如果只要其中的任意一個返回null,則后續的BeanPostProcessor的postProcessBeforeInitialization將不會再處理了。
接著就是執行初始化方法,即invokeInitMethods方法被調用。
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isTraceEnabled()) { logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } //如果當前Bean實現了InitializingBean接口則會執行它的afterPropertiesSet()方法 if (System.getSecurityManager() != null) { try { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { ((InitializingBean) bean).afterPropertiesSet(); return null; }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { ((InitializingBean) bean).afterPropertiesSet(); } } //如果在BeanDefinition中定義了initMethod則執行初始化方法 if (mbd != null && bean.getClass() != NullBean.class) { String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); } } }
從上面代碼也進一步驗證了BeanPostProcessor中的postProcessBeforeInitialization方法的確是在初始化前調用。
當invokeInitMethods執行之后接著就執行applyBeanPostProcessorsAfterInitialization方法。
@Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
該方法與applyBeanPostProcessorsBeforeInitialization幾乎就是相同的,不同的在于它執行的是postProcessAfterInitialization。至此Spring Bean的初始化也就完成了。
通過上面了解了Spring Bean生命周期中初始化的過程,但是實際上Spring對于JSR250也支持,例如對@PostConstruct注解的支持,但是在之前的源碼中并沒有發現Spring Bean的初始化過程中有所體現。
這里面的秘密就是我們的BeanPostProcessor了。
在Spring中有一個CommonAnnotationBeanPostProcessor類,這個類的注釋中有說到這個類就是用來對JSR250及其他一些規范的支持。
下面我就通過這個類的源碼來說明Spring是如何通過BeanPostProcessor來實現對@PostContruct的支持。
從上圖中我們可以看出,CommonAnnotationBeanPostProcessor并沒有直接對BeanPostProcessor有所實現,它繼承InitDestroyAnnotationBeanPostProcessor該類,而對@PostConstruct的實現主要在該類中。
而對BeanPostProcessor的實現代碼如下:
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { //生命周期元數據封裝 LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { //執行InitMethods metadata.invokeInitMethods(bean, beanName); } catch (InvocationTargetException ex) { throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException()); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Failed to invoke init method", ex); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; }
對BeanPostProcessor的實現主要在before方法中,該方法主要就是兩部分內容,第一部分主要是信息封裝到LifecycleMetadata中,便于后面第二步的執行相關初始化方法。
通過上面的方法實現我們知道了,Spring對JSR250的實現借助于BeanPostProcessor來實現的。
public class BeanPostProcessorDemo2 { public static void main(String[] args) { //創建基礎容器 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); //構建BeanDefinition并注冊 AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Person.class) .getBeanDefinition(); beanFactory.registerBeanDefinition("person",beanDefinition); //注冊CommonAnnotationBeanPostProcessor CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor = new CommonAnnotationBeanPostProcessor(); beanFactory.addBeanPostProcessor(commonAnnotationBeanPostProcessor); //獲取Bean Person person = beanFactory.getBean(Person.class); System.out.println(person); } } class Person{ @PostConstruct public void annotationInitMethod(){ System.out.println("@PostConstruct"); } }
上面的代碼比較簡單,我們定義一個Person并使用@PostConstruct標記出它的初始化方法,然后我們創建BeanFactory,并創建Person的BeanDefinition將其注冊到BeanFactory(與讀取配置文件一樣),然后我們創建CommonAnnotationBeanPostProcessor并將其添加到BeanFactory中。
最后打印結果打印出@PostConstruct。如果我們將下面這句代碼注釋。
beanFactory.addBeanPostProcessor(commonAnnotationBeanPostProcessor);
再次執行可以發現,@PostConstruct將會失效,且最后不會打印出結果。
BeanPostProcessor是可以注冊多個的,在AbstractBeanFactory內部通過List變量beanPostProcessors來存儲BeanPostProcessor。而在執行時是按照List中BeanPostProcessor的順序一個個執行的,所以我們在想容器中添加BeanPostProcessor時需要注意順序。如果我們不是通過手動添加(大多數時候不是)時,而是在代碼或者配置文件中定義多個BeanPostProcessor時,我們可以通過實現Ordered接口來控制它的順序。
BeanPostProcessor依賴的Bean不會執行BeanPostProcessor BeanPostProcessor依賴的Bean是不會執行BeanPostProcessor的,這是因為在創建BeanPostProcessor之所依賴的Bean就需要完成初始化,而這個時候BeanPostProcessor都還未完初始化完成。
此外我們需要了解點:@PostConstruct 執行點(beforeInitialization) 要早于 afterProperitesSet(invokeInitMethod-1) 早于對應的Bean定義的initMethod(invokeinitiMethod-2)方法的執行。
實例代碼如下:
public class App3 { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.scan("com.buydeem.beanpostprocessor"); context.register(App3.class); context.refresh(); } } @Component class ClassA{ } @Component class ClassB{ } @Component class MyBeanPostProcessor implements BeanPostProcessor{ @Autowired private ClassA classA; @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("MyBeanPostProcessor"+bean); return bean; } }
注意:最后ClassA是不會打印出來的,而ClassB是會被打印出來。因為MyBeanPostProcessor依賴ClassA實例。
Spring中BeanPostProcessor的子接口或實現類有很多種,例如。
InstantiationAwareBeanPostProcessor、MergedBeanDefinitionPostProcessor、DestructionAwareBeanPostProcessor等等。
這些接口分別處在Spring Bean生命周期的不同階段,而他們的功能與BeanPostProcessor都類似,都是為了給Spring Bean各個聲明周期提供擴展點。
看完上述內容,你們對Spring源碼中BeanPostProcessor的原理是什么有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。