Spring奇技淫巧之?dāng)U展點的應(yīng)用
本文轉(zhuǎn)載自微信公眾號「月伴飛魚」,作者日常加油站。轉(zhuǎn)載本文請聯(lián)系月伴飛魚公眾號。
最近在看公司項目和中間件的時候,看到一些Spring擴展點的使用,寫篇文章學(xué)習(xí)下,對大家之后看源碼都有幫助
「首先先介紹下Bean的生命周期」
我們知道Bean的生命周期分為幾個主干流程
- Bean(單例非懶加載)的實例化階段
- Bean的屬性注入階段
- Bean的初始化階段
- Bean的銷毀階段
下面是整個Spring容器的啟動流程,可以看到除了上述幾個主干流程外,Spring還提供了很多擴展點
下面詳細介紹下Spring的常見的擴展點
Spring常見擴展點
「BeanFactoryPostProcessor#postProcessBeanFactory」
有時候整個項目工程中bean的數(shù)量有上百個,而大部分單測依賴都是整個工程的xml,導(dǎo)致單測執(zhí)行時需要很長時間(大部分時間耗費在xml中數(shù)百個單例非懶加載的bean的實例化及初始化過程)
解決方法:利用Spring提供的擴展點將xml中的bean設(shè)置為懶加載模式,省去了Bean的實例化與初始化時間
- public class LazyBeanFactoryProcessor implements BeanFactoryPostProcessor {
- @Override
- public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
- DefaultListableBeanFactory fac = (DefaultListableBeanFactory) beanFactory;
- Map<String, AbstractBeanDefinition> map = (Map<String, AbstractBeanDefinition>) ReflectionTestUtils.getField(fac, "beanDefinitionMap");
- for (Map.Entry<String, AbstractBeanDefinition> entry : map.entrySet()) {
- //設(shè)置為懶加載
- entry.getValue().setLazyInit(true);
- }
- }
- }
「InstantiationAwareBeanPostProcessor#postProcessPropertyValues」
非常規(guī)的配置項比如
- <context:component-scan base-package="com.zhou" />
Spring提供了與之對應(yīng)的特殊解析器
正是通過這些特殊的解析器才使得對應(yīng)的配置項能夠生效
而針對這個特殊配置的解析器為 ComponentScanBeanDefinitionParser
在這個解析器的解析方法中,注冊了很多特殊的Bean
- public BeanDefinition parse(Element element, ParserContext parserContext) {
- //...
- registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
- //...
- return null;
- }
- public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
- BeanDefinitionRegistry registry, Object source) {
- Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
- //...
- //@Autowire
- if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
- RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
- def.setSource(source);
- beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
- }
- // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
- //@Resource
- if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
- //特殊的Bean
- RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
- def.setSource(source);
- beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
- }
- //...
- return beanDefs;
- }
以@Resource為例,看看這個特殊的bean做了什么
- public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
- implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
- public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds,
- Object bean, String beanName) throws BeansException {
- InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass());
- try {
- //屬性注入
- metadata.inject(bean, beanName, pvs);
- }
- catch (Throwable ex) {
- throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
- }
- return pvs;
- }
- }
我們看到在postProcessPropertyValues方法中,進行了屬性注入
「invokeAware」
實現(xiàn)BeanFactoryAware接口的類,會由容器執(zhí)行setBeanFactory方法將當(dāng)前的容器BeanFactory注入到類中
- @Bean
- class BeanFactoryHolder implements BeanFactoryAware{
- private static BeanFactory beanFactory;
- public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
- this.beanFactory = beanFactory;
- }
- }
「BeanPostProcessor#postProcessBeforeInitialization」
實現(xiàn)ApplicationContextAware接口的類,會由容器執(zhí)行setApplicationContext方法將當(dāng)前的容器applicationContext注入到類中
- @Bean
- class ApplicationContextAwareProcessor implements BeanPostProcessor {
- private final ConfigurableApplicationContext applicationContext;
- public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
- this.applicationContext = applicationContext;
- }
- @Override
- public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
- //...
- invokeAwareInterfaces(bean);
- return bean;
- }
- private void invokeAwareInterfaces(Object bean) {
- if (bean instanceof ApplicationContextAware) {
- ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
- }
- }
- }
我們看到是在BeanPostProcessor的postProcessBeforeInitialization中進行了setApplicationContext方法的調(diào)用
- class ApplicationContextHolder implements ApplicationContextAware{
- private static ApplicationContext applicationContext;
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- this.applicationContext = applicationContext;
- }
- }
「afterPropertySet()和init-method」
目前很多Java中間件都是基本Spring Framework搭建的,而這些中間件經(jīng)常把入口放到afterPropertySet或者自定義的init中
「BeanPostProcessor#postProcessAfterInitialization」
熟悉aop的同學(xué)應(yīng)該知道,aop底層是通過動態(tài)代理實現(xiàn)的
當(dāng)配置了
不知道大家有沒有思考過動態(tài)代理是如何「在調(diào)用方無感知情況下替換原始對象」的?
根據(jù)上文的講解,我們知道:
- <aop:aspectj-autoproxy/>
Spring也提供了特殊的解析器,和其他的解析器類似,在核心的parse方法中注冊了特殊的bean
這里是一個BeanPostProcessor類型的bean
- class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
- @Override
- public BeanDefinition parse(Element element, ParserContext parserContext) {
- //注冊特殊的bean
- AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
- extendBeanDefinition(element, parserContext);
- return null;
- }
- }
將于當(dāng)前bean對應(yīng)的動態(tài)代理對象返回即可,該過程對調(diào)用方全部透明
- public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
- public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- if (bean != null) {
- Object cacheKey = getCacheKey(bean.getClass(), beanName);
- if (!this.earlyProxyReferences.containsKey(cacheKey)) {
- //如果該類需要被代理,返回動態(tài)代理對象;反之,返回原對象
- return wrapIfNecessary(bean, beanName, cacheKey);
- }
- }
- return bean;
- }
- }
正是利用Spring的這個擴展點實現(xiàn)了動態(tài)代理對象的替換
「destroy()和destroy-method」
bean生命周期的最后一個擴展點,該方法用于執(zhí)行一些bean銷毀前的準備工作,比如將當(dāng)前bean持有的一些資源釋放掉