1. 程式人生 > 實用技巧 >spring擴充套件介面解析--Aware系列介面

spring擴充套件介面解析--Aware系列介面

前言

Spring的核心思想之一就是IOC(控制反轉),而IOC的實現方式DI(依賴注入),也就是說當某個bean需要依賴另一個bean時,就可以採用依賴注入的方式將依賴的bean自動注入到該bean中。但是如果一個bean依賴的物件並非是一個bean,此時通過容器的依賴注入顯然就無法實現了,不過Spring容器提供了擴充套件介面,當某個bean對某個物件有興趣或者是想要獲取該物件時,比如想要獲取Spring容器本身的資源,此時就可以採用Aware介面來獲取。

一、Aware介面

Aware介面是Aware系列介面的頂級介面,當時Aware介面沒有任何定義,僅僅是一個宣告,也就是僅僅起到了一個標識的作用。實現了Aware介面的類就會被Spring容器所感知。而具體需要感知什麼內容需要具體的子介面去定義。

比如說想要得到BeanFactory這個物件,此時就可以定義一個BeanFactoryAware介面實現Aware介面;想要得到ApplicationContext物件,就可以定義ApplicationContextAware介面,那麼實現了對應介面的bean就可以獲取到對應的物件。

每個Aware介面的子介面,內部都需要有一個set方法,將本身設定進去,這樣實現了該介面的類就可以獲取到該物件了

比如某個bean實現了BeanFactoryAware介面,BeanFactoryAware介面就會有一個setBeanFactroy(BeanFactroy beanFactory)方法,子類實現了之後,就可以得到beanFactory物件了。同理實現了XXXAware介面,就可以得到XXX這個物件。

二、Spring提供的常用的Aware介面

Spring提供了Aware介面的同時,也提供了很多自帶的Aware子介面,主要是用於獲取Spring容器本身的物件。如下圖示:

可以看出Spring本身就已經提供了很多的Aware介面,需要使用到某個物件就可以實現對應的Aware介面即可

2.1、BeanFactoryAware介面(獲取BeanFactory物件)

1 public interface BeanFactoryAware extends Aware {
2 
3     /**
4          * 設定BeanFactory屬性
5      */
6     void setBeanFactory(BeanFactory beanFactory) throws
BeansException; 7 8 }

2.2、ApplicatioContextAware介面(獲取ApplicationContext物件)

public interface ApplicationContextAware extends Aware {

    /**
     * 設定ApplicationContext屬性
     */
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

2.3、BeanNameAware介面(獲取當前bean的beanName)

public interface BeanNameAware extends Aware {

    /**
     * 設定BeanName屬性
     */
    void setBeanName(String name);

}

2.4、ApplicationEventPublisherAware介面(獲取容器中事件釋出器,可以用於釋出事件)

public interface ApplicationEventPublisherAware extends Aware {

    /**
     * 設定事件釋出器屬性
     */
    void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);

}

2.5、ResourceLoaderAware介面(獲取資源載入器,用於獲取外部資原始檔)

public interface ResourceLoaderAware extends Aware {

    /**
     * 設定資源載入器屬性
     */
    void setResourceLoader(ResourceLoader resourceLoader);

}

介面比較多就不再一一列舉,可以看出每個Aware子介面都有一個共同點,就是都有一個set方法用於設定該型別物件的方法。

三、Aware介面使用

以Spring提供的Aware介面為例,自定義Bean分別實現Spring提供的Aware介面,測試案例如下:

 1 public class AwareBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {
 2 
 3     private String beanName;
 4 
 5     private BeanFactory beanFactory;
 6 
 7     private ApplicationContext applicationContext;
 8 
 9     @Override
10     public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
11         this.beanFactory = beanFactory;
12     }
13 
14     @Override
15     public void setBeanName(String beanName) {
16         this.beanName = beanName;
17     }
18 
19     @Override
20     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
21         this.applicationContext = applicationContext;
22     }
23 
24     public void test(){
25         System.out.println("beanName:" + beanName);
26         System.out.println("從BeanFactory中獲取當前bean " + beanFactory.getBean(AwareBean.class).equals(this));
27         System.out.println("從ApplicationContext中獲取當前bean " + applicationContext.getBean(AwareBean.class).equals(this));
28     }
29 }

自定義AwareBean物件,分別實現了BeanNameAware、BeanFactoryAware和ApplicationContextAware介面,分別實現方法給內部屬性賦值,呼叫test()方法測試結果如下:

1 beanName:awareBean
2 從BeanFactory中獲取當前bean true
3 從ApplicationContext中獲取當前bean true

既然bean可以通過實現BeanFactoryAware和ApplicationContextAware介面的方式可以注入Spring容器,所以bean獲取其他bean的方式就可以通過容器直接獲取,而不需要通過依賴注入來實現了,比如以下案例:

 1 public class AwareBean implements ApplicationContextAware {
 2 
 3     private ApplicationContext applicationContext;
 4 
 5     private UserService userService;
 6     private OrderService orderService;
 7 
 8     @Override
 9     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
10         this.applicationContext = applicationContext;
11         this.orderService = applicationContext.getBean(OrderService.class);
12         this.userService = applicationContext.getBean(UserService.class);
13     }
14 
15     public void test(){
16         System.out.println(userService != null);
17         System.out.println(orderService != null);
18     }
19 }

AwareBean依賴UserService和OrderService,但是沒有采用依賴注入的方式,而是直接通過從Spring容器ApplicationContext中獲取來設定賦值。

四、Aware介面的實現原理解析

當bean實現了Aware介面之後,由於實現了Aware介面的方法,所以bean在初始化的過程中就需要執行Aware介面的方法,準確的說是在bean填充屬性之後,執行init方法之前。

具體執行的邏輯是在初始化bean的方法initializeBean方法中,由前面幾篇文章可知,bean的初始化過程分成 createBeanInstance(建立bean) ->populateBean(屬性注入) ->initializeBean(執行初始化方法) 三步

而Aware介面方法的執行就是在第三步initializeBean方法當中,原始碼如下:

 1 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
 2         if (System.getSecurityManager() != null) {
 3             AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
 4                 /** 1、執行Aware介面的方法*/
 5                 invokeAwareMethods(beanName, bean);
 6                 return null;
 7             }, getAccessControlContext());
 8         }
 9         else {
10             /** 1、執行Aware介面的方法*/
11             invokeAwareMethods(beanName, bean);
12         }
13 
14         Object wrappedBean = bean;
15         if (mbd == null || !mbd.isSynthetic()) {
/** 2、執行bean的前置處理器方法*/
16 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); 17 } 18 19 try { 20 /** 3、執行初始化方法*/ 21 invokeInitMethods(beanName, wrappedBean, mbd); 22 } 23 catch (Throwable ex) { 24 throw new BeanCreationException( 25 (mbd != null ? mbd.getResourceDescription() : null), 26 beanName, "Invocation of init method failed", ex); 27 } 28 if (mbd == null || !mbd.isSynthetic()) {
/** 4、執行bean的後置處理器方法*/
29 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); 30 } 31 32 return wrappedBean; 33 }

從原始碼中可看出bean的初始化方法中會先執行Aware介面的方法,然後才會去執行bean的具體的初始化方法。所以執行Aware介面的方法具體邏輯都在 invokeAwareMethods方法中實現,原始碼如下:

 1 /** 執行 Aware介面的方法 */
 2     private void invokeAwareMethods(final String beanName, final Object bean) {
 3         /**判斷bean實現了Aware介面*/
 4         if (bean instanceof Aware) {
 5             //1.如果實現了BeanNameAware介面,則執行setBeanName方法
 6             if (bean instanceof BeanNameAware) {
 7                 ((BeanNameAware) bean).setBeanName(beanName);
 8             }
 9             //2.如果實現了BeanClassLoaderAware介面,則執行setBeanClassLoader方法
10             if (bean instanceof BeanClassLoaderAware) {
11                 ClassLoader bcl = getBeanClassLoader();
12                 if (bcl != null) {
13                     ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
14                 }
15             }
16             //3.如果實現了BeanFactoryAware介面,則執行BeanFactoryAware介面方法
17             if (bean instanceof BeanFactoryAware) {
18                 ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
19             }
20         }
21     }

可以看出這裡分別判斷bean是否實現了對應的Aware子介面,如果實現了Aware子介面,就將Bean轉換成對應Aware子介面的物件,然後直接執行對應的set方法,將需要傳入的引數傳入即可。

但是這個方法很明顯只判斷了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware三個Aware介面,而Spring容器中還有很多的Aware介面的方法在這裡並沒有執行,那麼其他的介面比如ApplicationContextAware等介面又是何時執行的呢?

此時如果熟悉Spring的後置處理器的同學可能已經想到了,在bean初始化之前,會執行bean的後置處理器的方法,而其他的Aware介面就是通過後置處理器來執行的。

現在還是回到上面的initializeBean方法之後,在執行了BeanFactory的預設invokeAwareMethods方法之後,會先執行bean的前置處理器方法,然後執行invokeInitMethods方法執行初始化邏輯,最後再執行bean的後置處理器方法,執行bean的後置邏輯。

所以可以得知bean初始化時會分別執行前置處理器和後置處理器方法,而會執行Aware介面的處理器是ApplicationContextAwareProcesser,此處理器是在初始化ApplicationContext時加入的

執行ApplicationContext初始化方法時會執行refresh()方法,而refresh方法中第三步就是預處理BeanFactory方法prepareBeanFactory(beanFactory)方法,程式碼如下:

 1 protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
 2         // Tell the internal bean factory to use the context's class loader etc.
 3         beanFactory.setBeanClassLoader(getClassLoader());
 4         beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
 5         beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
 6 
 7         /** 建立ApplicationContextAwareProcessor物件,加入到BeanFactory的處理器中*/
 8         beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
 9         beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
10         beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
11         beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
12         beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
13         beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
14         beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
15 
16         /** 剩下程式碼省略*/
17     }

在預處理BeanFactory時,會初始化ApplicationContextAwareProcessor物件,呼叫BeanFactory的addBeanPostProcessor方法阿靜該處理器加入到BeanFactory中。而在初始化bean的時候,會遍歷BeanFactory中的所有BeanPostProcessor,依次執行前置和後置方法。所以這裡執行Aware介面的方法就需要在ApplicationContextAwareProcessor中檢視,該類的原始碼如下:

 1 class ApplicationContextAwareProcessor implements BeanPostProcessor {
 2 
 3         private final ConfigurableApplicationContext applicationContext;
 4 
 5         private final StringValueResolver embeddedValueResolver;
 6 
 7 
 8         /**
 9          * Create a new ApplicationContextAwareProcessor for the given context.
10          */
11         public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
12             this.applicationContext = applicationContext;
13             this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
14         }
15 
16 
17         @Override
18         @Nullable
19         /** 在bean的初始化之前執行 */
20         public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
21             if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
22                     bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
23                     bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
24                 return bean;
25             }
26 
27             AccessControlContext acc = null;
28 
29             if (System.getSecurityManager() != null) {
30                 acc = this.applicationContext.getBeanFactory().getAccessControlContext();
31             }
32 
33             if (acc != null) {
34                 AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
35                     /**執行Aware介面方法*/
36                     invokeAwareInterfaces(bean);
37                     return null;
38                 }, acc);
39             }
40             else {
41                 /** 執行Aware介面方法 */
42                 invokeAwareInterfaces(bean);
43             }
44 
45             return bean;
46         }
47 
48         /** 回撥執行各種型別Aware介面的方法*/
49         private void invokeAwareInterfaces(Object bean) {
50             //1.執行EnvironmentAware介面方法
51             if (bean instanceof EnvironmentAware) {
52                 ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
53             }
54             //2.執行EmbeddeValueResolverAware介面方法
55             if (bean instanceof EmbeddedValueResolverAware) {
56                 ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
57             }
58             //3.執行ResourceLoaderAware介面方法
59             if (bean instanceof ResourceLoaderAware) {
60                 ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
61             }
62             //4.執行ApplicationEventPublisherAware介面方法
63             if (bean instanceof ApplicationEventPublisherAware) {
64                 ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
65             }
66             //5.執行MessageSourceAware介面方法
67             if (bean instanceof MessageSourceAware) {
68                 ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
69             }
70             //6.執行ApplicationContextAware介面方法
71             if (bean instanceof ApplicationContextAware) {
72                 ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
73             }
74         }
75     }

可以看出在ApplicationContextAwareProcessor中的執行Aware介面的邏輯和BeanFactory初始化bean時的invokeAwareMethods方法邏輯基本差不多,都是依次判斷bean是否實現了Aware的各個子介面,實現了對應的介面就將bean轉換成對應介面的物件,然後直接執行對應的set方法,而這一步是在invokeAwareMethods方法執行之後,bean的init方法執行之前操作的

總結:

1、bean在初始化方法initializeBean方法中執行邏輯為先執行invokeAwareMethods執行BeanFactory提供的Aware子介面

2、然後遍歷執行BeanFactory的後置處理器方法,其中ApplicationContextAwareProcessor處理器會執行ApplicationContext提供的Aware子介面方法

3、執行完Aware子介面方法之後,才會繼續執行bean的初始化方法