<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring奇技淫巧之?dāng)U展點(diǎn)的應(yīng)用

          共 10558字,需瀏覽 22分鐘

           ·

          2021-04-14 17:12

          ?

          最近在看公司項(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í)需要很長時(shí)間(大部分時(shí)間耗費(fèi)在xml中數(shù)百個(gè)單例非懶加載的bean的實(shí)例化及初始化過程)

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

          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ī)的配置項(xiàng)比如

          <context:component-scan base-package="com.zhou" />

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

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

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

          在這個(gè)解析器的解析方法中,注冊(cè)了很多特殊的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為例,看看這個(gè)特殊的bean做了什么

          public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
            implements InstantiationAwareBeanPostProcessorBeanFactoryAwareSerializable 
          {
               
                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方法中,進(jìn)行了屬性注入

          「invokeAware」

          實(shí)現(xiàn)BeanFactoryAware接口的類,會(huì)由容器執(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」

          實(shí)現(xiàn)ApplicationContextAware接口的類,會(huì)由容器執(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中進(jìn)行了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底層是通過動(dòng)態(tài)代理實(shí)現(xiàn)的

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

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

          ?

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

          ?
          <aop:aspectj-autoproxy/>

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

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

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

          將于當(dāng)前bean對(duì)應(yīng)的動(dòng)態(tài)代理對(duì)象返回即可,該過程對(duì)調(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)) {
                      //如果該類需要被代理,返回動(dòng)態(tài)代理對(duì)象;反之,返回原對(duì)象
                      return wrapIfNecessary(bean, beanName, cacheKey);
                    }
                  }
                  return bean;
           }
          }

          正是利用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持有的一些資源釋放掉

          最后

          「寫文章畫圖不易,喜歡的話,希望幫忙點(diǎn)贊,轉(zhuǎn)發(fā)下哈,謝謝」

          微信搜索:月伴飛魚,交個(gè)朋友

          公眾號(hào)后臺(tái)回復(fù)666,獲得免費(fèi)電子書籍,必讀經(jīng)典書籍這里全都有

          參考書籍:

          • Spring技術(shù)內(nèi)幕

          • Spring源碼深度解析

          社招一年半面經(jīng)分享(含阿里美團(tuán)頭條京東滴滴)


          條件語句的多層嵌套問題優(yōu)化,助你寫出不讓同事吐槽的代碼


          ConcurrentHashMap核心原理,這次徹底給整明白了

          瀏覽 38
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  99色| 欧美操逼手机视频 | 免费黄色电影在线网站 | 九九色在线播放 | 俺来俺也去www色在线观看 |