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) throwsBeansException; 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的初始化方法