本篇主要是講解IOC容器初始化過程當中大致進行了哪一些工做,以及Bean後置處理器的工做原理和BeanPostProcessor在底層的使用。
實現BeanPostProcessor接口的組件,而且在兩個方法體內打上斷點:spring
public class BeanPostProcessorDefinition implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object o, String s) throws BeansException { System.out.println("postProcessBeforeInitialization -->"+s+" = "+o); return o; } @Override public Object postProcessAfterInitialization(Object o, String s) throws BeansException { System.out.println("postProcessorAfterInitialization -->"+s+"="+o); return o; } }
調試後查看方法調用棧以下(如圖1):app
在方法調用棧中的initializeBean(初始化Bean)方法中,有下面一段相似的僞代碼:maven
initializeBean(param){ wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); ... invokeInitMethods(beanName, wrappedBean, mbd); ... wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }
這段僞代碼的大體意思就是先執行bean初始化以前的方法,而後執行bean初始化方法,最後執行初始化後的方法。
applyBeanPostProcessorsBeforeInitialization也是屬於方法調用棧的一環,進去有相似一段僞代碼:ide
applyBeanPostProcessorsBeforeInitialization(param) throws BeansException { for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { result = beanProcessor.postProcessBeforeInitialization(result, beanName); if (result == null) { return result; } } return result; }
這段代碼經過遍歷獲得全部的BeanPostProcessor,而後挨個執行重寫的postProcessBeforeInitialization方法,假若有一個方法返回的bean爲null,那麼循環就會跳出,意味着下面的postProcessBeforeInitialization方法不會被執行。在初始化方法後執行的applyBeanPostProcessorsAfterInitialization同理也是同樣的。
大體總結後置處理器處理Bean初始化的過程(如圖2):工具
談到spring的IOC容器都離不開兩個接口BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口,他們均可以表明spring容器。
圖1打斷點所示的方法調用棧能夠用來分析容器初始化所進行的工做(以AnnotationConfigApplicationContext獲取容器爲例):源碼分析
refresh過程:post
registerBeanPostProcessors(Param)註冊Bean後置處理器用來攔截Bean的建立ui
註冊BeanPostProcessor,實際上spring就會建立對象保存在容器中;
如下是建立Bean的流程:
一、doCreateBean(Param)方法內建立Bean實例
二、populateBean(Param)給bean實例屬性賦值
三、initializeBean(Param):初始化Bean
四、invokeAwareMethods():處理Bean實現Aware接口的方法回調
五、後置處理器處理的流程:圖2的流程this
==========上面流程則完成對BeanPostProcessor的註冊和建立spa
refresh過程接上:
在spring中,Aware接口的Bean在被初始以後,能夠取得一些相對應的資源,也就是說,自定義組件想要使用Spring容器底層的一些組件(ApplicationContext,BeanFactory,xxx)的話,自定義組件就須要實現xxxxAware接口;在建立對象的時候,會調用接口規定的方法注入相關組件,把Spring底層一些組件注入到自定義的Bean中;
ApplicationContextAware
能夠在Spring初始化實例 Bean的時候,能夠經過這個接口將當前的Spring上下文傳入,即得到spring 容器,實際開發中,經常封裝成一個工具類(方便獲取容器獲取bean):
//將組件註冊添加到容器中後能夠直接看成工具類 public class SpringContextTool implements ApplicationContextAware { private static ApplicationContext context = null; public static Object getBean(String beanName) { return context.getBean(beanName); } public static <T> T getBean(Class<T> clazz){ return context.getBean(clazz); } public static ApplicationContext getContext() { return context; } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext;//打個斷點 } }
原理:在重寫方法打個斷點,查看方法調用棧
容器看出,在bean初始化方法執行以前,先執行後置處理器的postProcessBeforeInitialization方法,程序跳進ApplicationContextAwareProcessor這個類中(此類實現了BeanPostProcessor接口),執行重寫的postProcessBeforeInitialization方法,在跳到invokeAwareInterfaces方法中,判斷了當前初始化bean時候繼承了對應的Aware,若是是則調用對應的set方法,傳入對應的資源。
同理還有**EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware**也是注入spring底層組件
再舉個EmbeddedValueResolverAware的例子,能夠實現這個aware接口來完成Spring獲取properties文件屬性值:
public class PropertiesUtil implements EmbeddedValueResolverAware { private static StringValueResolver resolver; @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { this.resolver = resolver; } public static String getPropertiesValue(String key) { StringBuilder name = new StringBuilder("${").append(key).append("}"); return resolver.resolveStringValue(name.toString()); } }
須要獲取properties文件的屬性值時能夠採用:propertiesUtil.getPropertiesValue("xxxxxxx")或者@value("xxxx")來達到獲取屬性值。
打個斷點後發現它的原理和ApplicationContextAware是同樣的。都是判斷了當前初始化bean時候繼承了對應的Aware,若是是則調用對應的set方法,傳入對應的資源。源碼以下:
private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } } }
ServletContextAware、ServletConfigAware等幾個原理也是差很少相似的。
同理還有BeanValidationPostProcessor也實現了BeanPostProcessor接口,可用於數據校驗,還有InitDestroyAnnotationBeanPostProcessor也實現了此接口,主要是用於處理JSR250那幾個註解的,AutowiredAnnotationBeanPostProcessor也實現了該接口,用於處理@autowired註解裝載bean。總之,Bean的賦值、注入其餘組件,@autowired,@Async,生命週期等都是使用BeanPostProcessor來完成的。這一些使用和原理在下一章再分析並補上流程圖。