欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2022年04月21日 10:43:33   作者:程序員段飛?  
這篇文章主要介紹了Java中Spring技巧之?dāng)U展點(diǎn)的應(yīng)用,下文Spring容器的啟動(dòng)流程圖展開其內(nèi)容的相關(guān)資料,具有一定的參考價(jià)值,需要的小伙伴可以參考一下

前言:

最近在看公司項(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í)例化及初始化過(guò)程)

解決方法:利用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)的特殊解析器

正是通過(guò)這些特殊的解析器才使得對(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 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方法中,進(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);
        }
    }
}

我們看到是在BeanPostProcessorpostProcessBeforeInitialization中進(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底層是通過(guò)動(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ì)象

不知道大家有沒(méi)有思考過(guò)動(dòng)態(tài)代理是如何**「在調(diào)用方無(wú)感知情況下替換原始對(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ì)象返回即可,該過(guò)程對(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持有的一些資源釋放掉

總結(jié)

到此這篇關(guān)于Java中Spring技巧之?dāng)U展點(diǎn)的應(yīng)用的文章就介紹到這了,更多相關(guān)Spring擴(kuò)展點(diǎn)應(yīng)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Swagger的使用教程詳解

    Swagger的使用教程詳解

    Swagger是一個(gè)強(qiáng)大的API文檔工具,它能夠簡(jiǎn)化API文檔的編寫和維護(hù)工作,提供了一種方便的方式來(lái)描述、展示和測(cè)試RESTful風(fēng)格的Web服務(wù)接口,本文介紹了Swagger的安裝配置和使用方法,并提供了示例代碼,感興趣的朋友一起學(xué)習(xí)吧
    2023-06-06
  • Java簡(jiǎn)單實(shí)現(xiàn)調(diào)用命令行并獲取執(zhí)行結(jié)果示例

    Java簡(jiǎn)單實(shí)現(xiàn)調(diào)用命令行并獲取執(zhí)行結(jié)果示例

    這篇文章主要介紹了Java簡(jiǎn)單實(shí)現(xiàn)調(diào)用命令行并獲取執(zhí)行結(jié)果,結(jié)合實(shí)例形式分析了Java調(diào)用ping命令并獲取執(zhí)行結(jié)果相關(guān)操作技巧,需要的朋友可以參考下
    2018-08-08
  • Java高級(jí)特性(基礎(chǔ))

    Java高級(jí)特性(基礎(chǔ))

    這篇文章主要介紹了Java高級(jí)特性(基礎(chǔ)),需要的朋友可以參考下
    2017-04-04
  • Springboot入門案例及部署項(xiàng)目的詳細(xì)過(guò)程

    Springboot入門案例及部署項(xiàng)目的詳細(xì)過(guò)程

    Spring Boot是由Pivotal團(tuán)隊(duì)提供的全新框架,其設(shè)計(jì)目的是用來(lái)簡(jiǎn)化新Spring應(yīng)用的初始搭建以及開發(fā)過(guò)程,本文給大家分享一個(gè)入門案例使用Springboot1.5.9搭建,具體配置部署過(guò)程跟隨小編一起看看吧
    2021-07-07
  • Java中鍵盤輸入的幾種常見方式小結(jié)

    Java中鍵盤輸入的幾種常見方式小結(jié)

    本文主要介紹了Java中鍵盤輸入的幾種常見方式小結(jié),主要是三種方式IO流、Scanner類、BufferedReader寫入,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • 前置++和后置++ 運(yùn)算的詳解及實(shí)例代碼

    前置++和后置++ 運(yùn)算的詳解及實(shí)例代碼

    這篇文章主要介紹了前置++和后置++ 的相關(guān)資料,并附示例代碼,幫助大家學(xué)習(xí)參考,需要的朋友可以參考下
    2016-09-09
  • Java使用IntelliJ IDEA連接MySQL的詳細(xì)教程

    Java使用IntelliJ IDEA連接MySQL的詳細(xì)教程

    這篇文章主要給大家介紹了關(guān)于Java使用IntelliJ IDEA連接MySQL的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Spring?Boot?集成接口管理工具?Knife4j

    Spring?Boot?集成接口管理工具?Knife4j

    這篇文章主要介紹了Spring?Boot?集成接口管理工具?Knife4j,首先通過(guò)創(chuàng)建一個(gè)?Spring?Boot?項(xiàng)目展開主題,需要的小伙伴可以參考一下
    2022-05-05
  • Nacos框架服務(wù)注冊(cè)實(shí)現(xiàn)流程

    Nacos框架服務(wù)注冊(cè)實(shí)現(xiàn)流程

    這篇文章主要介紹了SpringCloud服務(wù)注冊(cè)之nacos實(shí)現(xiàn)過(guò)程,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • SpringBoot整合RabbitMQ實(shí)現(xiàn)RPC遠(yuǎn)程調(diào)用功能

    SpringBoot整合RabbitMQ實(shí)現(xiàn)RPC遠(yuǎn)程調(diào)用功能

    在分布式系統(tǒng)中,RPC(Remote?Procedure?Call)是一種常用的通信機(jī)制,它可以讓不同的節(jié)點(diǎn)之間像調(diào)用本地函數(shù)一樣進(jìn)行函數(shù)調(diào)用,隱藏了底層的網(wǎng)絡(luò)通信細(xì)節(jié),通過(guò)本教程,你可以了解RPC的基本原理以及如何使用Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的RPC客戶端和服務(wù)端
    2023-06-06

最新評(píng)論