最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中Spring技巧之擴展點的應(yīng)用

 更新時間:2022年04月21日 10:43:33   作者:程序員段飛?  
這篇文章主要介紹了Java中Spring技巧之擴展點的應(yīng)用,下文Spring容器的啟動流程圖展開其內(nèi)容的相關(guā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方法將當前的容器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方法將當前的容器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中進行了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)的

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

不知道大家有沒有思考過動態(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;
    }
}

將于當前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銷毀前的準備工作,比如將當前bean持有的一些資源釋放掉

總結(jié)

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

相關(guān)文章

  • 聊一聊new對象與Spring對bean的初始化的差別

    聊一聊new對象與Spring對bean的初始化的差別

    這篇文章主要介紹了聊一聊new對象與Spring對bean的初始化的差別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Java 多線程使用要點分析

    Java 多線程使用要點分析

    這篇文章主要介紹了Java 多線程使用要點分析的相關(guān)資料,Java 多線程開發(fā)需要主要的細節(jié)問題很多,這里就說下,需要的朋友可以參考下
    2016-12-12
  • Spring RestTemplate使用方法示例總結(jié)

    Spring RestTemplate使用方法示例總結(jié)

    這篇文章主要介紹了Spring RestTemplate使用方法示例總結(jié),本文通過實例代碼給大家介紹的非常詳細,感興趣的朋友一起看看吧
    2025-04-04
  • 解析Java線程同步鎖的選擇方法

    解析Java線程同步鎖的選擇方法

    本篇文章是對Java線程同步鎖的選擇方法進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • mybatis?plus?MetaObjectHandler?不生效的解決

    mybatis?plus?MetaObjectHandler?不生效的解決

    今天使用mybatis-plus自動為更新和插入操作插入更新時間和插入時間,配置了MetaObjectHandler不生效,本文就來解決一下,具有一定的 參考價值,感興趣的可以了解一下
    2023-10-10
  • iOS socket網(wǎng)絡(luò)編程實例詳解

    iOS socket網(wǎng)絡(luò)編程實例詳解

    socket是一個針對TCP和UDP編程的接口,你可以借助它建立TCP連接等。這篇文章主要介紹了iOS socket網(wǎng)絡(luò)編程 ,需要的朋友可以參考下
    2017-03-03
  • java課程設(shè)計之坦克大戰(zhàn)

    java課程設(shè)計之坦克大戰(zhàn)

    這篇文章主要為大家詳細介紹了java課程設(shè)計之坦克大戰(zhàn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • 海量數(shù)據(jù)去重排序bitmap(位圖法)在java中實現(xiàn)的兩種方法

    海量數(shù)據(jù)去重排序bitmap(位圖法)在java中實現(xiàn)的兩種方法

    今天小編就為大家分享一篇關(guān)于海量數(shù)據(jù)去重排序bitmap(位圖法)在java中實現(xiàn)的兩種方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • 解決IDEA中pom.xml文件變?yōu)榛疑膯栴}

    解決IDEA中pom.xml文件變?yōu)榛疑膯栴}

    這篇文章主要給大家介紹了如何解決IDEA中pom.xml文件變?yōu)榛疑膯栴},文中通過圖文結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-12-12
  • Java操作數(shù)據(jù)庫連接池案例講解

    Java操作數(shù)據(jù)庫連接池案例講解

    這篇文章主要介紹了Java操作數(shù)據(jù)庫連接池案例講解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08

最新評論

丹江口市| 富蕴县| 女性| 霍山县| 民县| 彰武县| 荃湾区| 巴楚县| 云浮市| 鄂托克前旗| 祥云县| 丹棱县| 海兴县| 贵港市| 元江| 广安市| 台中市| 石台县| 榆林市| 旌德县| 新丰县| 庄浪县| 南城县| 拉萨市| 乐清市| 汉川市| 大渡口区| 板桥市| 离岛区| 德令哈市| 屏南县| 溆浦县| 封丘县| 神农架林区| 报价| 房山区| 静乐县| 曲阳县| 平乡县| 泽普县| 青川县|