日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
Spring奇技淫巧之?dāng)U展點(diǎn)的應(yīng)用

本文轉(zhuǎn)載自微信公眾號(hào)「月伴飛魚」,作者日常加油站。轉(zhuǎn)載本文請(qǐng)聯(lián)系月伴飛魚公眾號(hào)。

最近在看公司項(xiàng)目和中間件的時(shí)候,看到一些Spring擴(kuò)展點(diǎn)的使用,寫篇文章學(xué)習(xí)下,對(duì)大家之后看源碼都有幫助

「首先先介紹下Bean的生命周期」

我們知道Bean的生命周期分為幾個(gè)主干流程

  • Bean(單例非懶加載)的實(shí)例化階段
  • Bean的屬性注入階段
  • Bean的初始化階段
  • Bean的銷毀階段

下面是整個(gè)Spring容器的啟動(dòng)流程,可以看到除了上述幾個(gè)主干流程外,Spring還提供了很多擴(kuò)展點(diǎn)

下面詳細(xì)介紹下Spring的常見的擴(kuò)展點(diǎn)

Spring常見擴(kuò)展點(diǎn)

「BeanFactoryPostProcessor#postProcessBeanFactory」

有時(shí)候整個(gè)項(xiàng)目工程中bean的數(shù)量有上百個(gè),而大部分單測(cè)依賴都是整個(gè)工程的xml,導(dǎo)致單測(cè)執(zhí)行時(shí)需要很長(zhǎng)時(shí)間(大部分時(shí)間耗費(fèi)在xml中數(shù)百個(gè)單例非懶加載的bean的實(shí)例化及初始化過程)

解決方法:利用Spring提供的擴(kuò)展點(diǎn)將xml中的bean設(shè)置為懶加載模式,省去了Bean的實(shí)例化與初始化時(shí)間

 
 
 
 
  1. public class LazyBeanFactoryProcessor implements BeanFactoryPostProcessor { 
  2.     @Override 
  3.     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { 
  4.         DefaultListableBeanFactory fac = (DefaultListableBeanFactory) beanFactory; 
  5.         Map map = (Map) ReflectionTestUtils.getField(fac, "beanDefinitionMap"); 
  6.         for (Map.Entry entry : map.entrySet()) { 
  7.             //設(shè)置為懶加載 
  8.             entry.getValue().setLazyInit(true); 
  9.         } 
  10.     } 

「InstantiationAwareBeanPostProcessor#postProcessPropertyValues」

非常規(guī)的配置項(xiàng)比如

 
 
 
 
  1.  

Spring提供了與之對(duì)應(yīng)的特殊解析器

正是通過這些特殊的解析器才使得對(duì)應(yīng)的配置項(xiàng)能夠生效

而針對(duì)這個(gè)特殊配置的解析器為 ComponentScanBeanDefinitionParser

在這個(gè)解析器的解析方法中,注冊(cè)了很多特殊的Bean

 
 
 
 
  1. public BeanDefinition parse(Element element, ParserContext parserContext) { 
  2.   //... 
  3.   registerComponents(parserContext.getReaderContext(), beanDefinitions, element); 
  4.     //... 
  5.   return null; 
 
 
 
 
  1. public static Set registerAnnotationConfigProcessors( 
  2.    BeanDefinitionRegistry registry, Object source) { 
  3.  
  4.   Set beanDefs = new LinkedHashSet(4); 
  5.   //... 
  6.     //@Autowire 
  7.   if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { 
  8.    RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class); 
  9.    def.setSource(source); 
  10.    beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); 
  11.   } 
  12.  
  13.   // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor. 
  14.    //@Resource 
  15.   if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { 
  16.       //特殊的Bean 
  17.    RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); 
  18.    def.setSource(source); 
  19.    beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); 
  20.   } 
  21.   //... 
  22.   return beanDefs; 
  23.  } 

以@Resource為例,看看這個(gè)特殊的bean做了什么

 
 
 
 
  1. public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor 
  2.   implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable { 
  3.       
  4.       public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds,  
  5.       Object bean, String beanName) throws BeansException { 
  6.           InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass()); 
  7.           try { 
  8.             //屬性注入 
  9.             metadata.inject(bean, beanName, pvs); 
  10.           } 
  11.           catch (Throwable ex) { 
  12.             throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex); 
  13.           } 
  14.           return pvs; 
  15.     } 
  16.      

我們看到在postProcessPropertyValues方法中,進(jìn)行了屬性注入

「invokeAware」

實(shí)現(xiàn)BeanFactoryAware接口的類,會(huì)由容器執(zhí)行setBeanFactory方法將當(dāng)前的容器BeanFactory注入到類中

 
 
 
 
  1. @Bean 
  2. class BeanFactoryHolder implements BeanFactoryAware{ 
  3.     
  4.     private static BeanFactory beanFactory; 
  5.      
  6.     public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 
  7.         this.beanFactory = beanFactory; 
  8.     } 

「BeanPostProcessor#postProcessBeforeInitialization」

實(shí)現(xiàn)ApplicationContextAware接口的類,會(huì)由容器執(zhí)行setApplicationContext方法將當(dāng)前的容器applicationContext注入到類中

 
 
 
 
  1. @Bean 
  2. class ApplicationContextAwareProcessor implements BeanPostProcessor { 
  3.  
  4.     private final ConfigurableApplicationContext applicationContext; 
  5.  
  6.     public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) { 
  7.       this.applicationContext = applicationContext; 
  8.     } 
  9.  
  10.     @Override 
  11.     public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { 
  12.       //... 
  13.       invokeAwareInterfaces(bean); 
  14.       return bean; 
  15.     } 
  16.  
  17.     private void invokeAwareInterfaces(Object bean) { 
  18.         if (bean instanceof ApplicationContextAware) { 
  19.           ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); 
  20.         } 
  21.     } 

我們看到是在BeanPostProcessor的postProcessBeforeInitialization中進(jìn)行了setApplicationContext方法的調(diào)用

 
 
 
 
  1. class ApplicationContextHolder implements ApplicationContextAware{ 
  2.     
  3.     private static ApplicationContext applicationContext; 
  4.      
  5.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
  6.         this.applicationContext = applicationContext; 
  7.     } 

「afterPropertySet()和init-method」

目前很多Java中間件都是基本Spring Framework搭建的,而這些中間件經(jīng)常把入口放到afterPropertySet或者自定義的init中

「BeanPostProcessor#postProcessAfterInitialization」

熟悉aop的同學(xué)應(yīng)該知道,aop底層是通過動(dòng)態(tài)代理實(shí)現(xiàn)的

當(dāng)配置了 時(shí)候,默認(rèn)開啟aop功能,相應(yīng)地調(diào)用方需要被aop織入的對(duì)象也需要替換為動(dòng)態(tài)代理對(duì)象

不知道大家有沒有思考過動(dòng)態(tài)代理是如何「在調(diào)用方無感知情況下替換原始對(duì)象」的?

根據(jù)上文的講解,我們知道:

 
 
 
 
  1.  

Spring也提供了特殊的解析器,和其他的解析器類似,在核心的parse方法中注冊(cè)了特殊的bean

這里是一個(gè)BeanPostProcessor類型的bean

 
 
 
 
  1. class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser { 
  2.  @Override 
  3.  public BeanDefinition parse(Element element, ParserContext parserContext) { 
  4.     //注冊(cè)特殊的bean 
  5.   AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); 
  6.   extendBeanDefinition(element, parserContext); 
  7.   return null; 
  8.     } 

將于當(dāng)前bean對(duì)應(yīng)的動(dòng)態(tài)代理對(duì)象返回即可,該過程對(duì)調(diào)用方全部透明

 
 
 
 
  1. public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { 
  2.   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 
  3.         if (bean != null) { 
  4.           Object cacheKey = getCacheKey(bean.getClass(), beanName); 
  5.           if (!this.earlyProxyReferences.containsKey(cacheKey)) { 
  6.             //如果該類需要被代理,返回動(dòng)態(tài)代理對(duì)象;反之,返回原對(duì)象 
  7.             return wrapIfNecessary(bean, beanName, cacheKey); 
  8.           } 
  9.         } 
  10.         return bean; 
  11.  } 

正是利用Spring的這個(gè)擴(kuò)展點(diǎn)實(shí)現(xiàn)了動(dòng)態(tài)代理對(duì)象的替換

「destroy()和destroy-method」

bean生命周期的最后一個(gè)擴(kuò)展點(diǎn),該方法用于執(zhí)行一些bean銷毀前的準(zhǔn)備工作,比如將當(dāng)前bean持有的一些資源釋放掉


當(dāng)前文章:Spring奇技淫巧之?dāng)U展點(diǎn)的應(yīng)用
文章地址:http://m.5511xx.com/article/coipdsh.html