中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring源碼中BeanPostProcessor的原理是什么

發布時間:2021-09-13 15:45:53 來源:億速云 閱讀:156 作者:柒染 欄目:編程語言

今天就跟大家聊聊有關Spring源碼中BeanPostProcessor的原理是什么,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

 前提概要

Spring具有很好的擴展性,但是這個擴展它的這個擴展性體現在哪里呢?而我們要說的BeanPostProcessor就是對Spring擴展性優秀的表現之一。

 BeanPostProcessor的作用

  • 簡單的說就是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注冊到容器中去的。 同時也可以采用掃描或者定義的方式生成到容器中。

下面分析打印結果:

  1. 初始化前:User(userName=null, age=null, beforeMessage=null, afterMessage=null) 該結果是postProcessBeforeInitialization方法中輸出的內容,這個時候User實例還只是進行了實例化,還未進行到初始化步驟,所以所有的屬性都為null,說明該方法確實是初始化執行的。——(此時的初始化指的是bean對象的init方法)

  2. 初始化:User(userName=null, age=null, beforeMessage=初始化前信息, afterMessage=null) 該結果為自定義的初始化方法initMethod方法中輸出的內容,這個時候User實例真正初始化,而beforeMessage中中的值正是我們在postProcessBeforeInitialization設置的

  3. 初始化后:User(userName=小明, age=18, beforeMessage=初始化前信息, afterMessage=null) 該結果是postProcessAfterInitialization中輸出內容,從打印結果可以看出它的確是在自定義initMethod后。

 Spring的生命周期

Spring中Bean總體上來說可以分為四個周期:實例化、屬性賦值、初始化、銷毀。而BeanPostProcessor則是在初始化階段的前后執行。

  • 首先看AbstractAutowireCapableBeanFactorydoCreateBean方法,該方法實際就是創建指定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源碼中BeanPostProcessor的原理是什么

???? @PostConstruct的支持

通過上面了解了Spring Bean生命周期中初始化的過程,但是實際上Spring對于JSR250也支持,例如對@PostConstruct注解的支持,但是在之前的源碼中并沒有發現Spring Bean的初始化過程中有所體現。

這里面的秘密就是我們的BeanPostProcessor了。

在Spring中有一個CommonAnnotationBeanPostProcessor類,這個類的注釋中有說到這個類就是用來對JSR250及其他一些規范的支持。

下面我就通過這個類的源碼來說明Spring是如何通過BeanPostProcessor來實現對@PostContruct的支持。

Spring源碼中BeanPostProcessor的原理是什么

從上圖中我們可以看出,CommonAnnotationBeanPostProcessor并沒有直接對BeanPostProcessor有所實現,它繼承InitDestroyAnnotationBeanPostProcessor該類,而對@PostConstruct的實現主要在該類中。 Spring源碼中BeanPostProcessor的原理是什么

而對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的子接口或實現類有很多種,例如。

InstantiationAwareBeanPostProcessorMergedBeanDefinitionPostProcessorDestructionAwareBeanPostProcessor等等

這些接口分別處在Spring Bean生命周期的不同階段,而他們的功能與BeanPostProcessor都類似,都是為了給Spring Bean各個聲明周期提供擴展點。

看完上述內容,你們對Spring源碼中BeanPostProcessor的原理是什么有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

乌审旗| 陆河县| 德钦县| 侯马市| 隆回县| 三河市| 江门市| 瓮安县| 阜新市| 新乡县| 自治县| 东乌| 宁安市| 巩义市| 黑水县| 称多县| 高安市| 来凤县| 恩施市| 惠州市| 永顺县| 柯坪县| 大城县| 横山县| 曲阜市| 昌乐县| 东光县| 汶川县| 新绛县| 宿州市| 丰宁| 应城市| 长白| 虞城县| 香港| 容城县| 息烽县| 海林市| 龙川县| 得荣县| 呼图壁县|