一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Spring源碼學習之動態代理實現流程

Spring源碼學習之動態代理實現流程

2021-08-30 11:05黃智霖-blog Java教程

這篇文章主要給大家介紹了關于Spring源碼學習之動態代理實現流程的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

注:這里不闡述Spring和AOP的一些基本概念和用法,直接進入正題。

流程

  Spring所管理的對象大體會經過確定實例化對象類型、推斷構造方法創建對象(實例化)、設置屬性、初始化等等步驟。在對象初始化階段,Spring為開發者提供了一個BeanPostProcessor接口,它會在對象初始化之前和初始化之后被調用(初始化,不是實例化,對應實例化的是InstantiationAwareBeanPostProcessor接口)。

  1. public interface BeanPostProcessor {
  2. //初始化之前
  3. Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
  4. //初始化之后
  5. Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
  6.  
  7. }

  在對象初始化之后會調用postProcessAfterInitialization方法,該方法返回一個Object。如果成功返回了一個對象,那么容器中相應beanName對應的實例就將會是這個對象。

  本文主要分析動態代理,我們著重看AnnotationAwareAspectJAutoProxyCreator。先來看一下它的繼承關系:

Spring源碼學習之動態代理實現流程

  AnnotationAwareAspectJAutoProxyCreator最終實現了BeanPostProcessor接口(也實現了InstantiationAwareBeanPostProcessor接口),可以看到繼承關系比較復雜。當前我們關注的postProcessAfterInitialization方法實現在它的父類AbstractAutoProxyCreator中(只保留了部分代碼):

  1. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  2. if (bean != null) {
  3. Object cacheKey = getCacheKey(bean.getClass(), beanName);
  4. if (!this.earlyProxyReferences.contains(cacheKey)) {
  5. return wrapIfNecessary(bean, beanName, cacheKey);
  6. }
  7. }
  8. return bean;
  9. }

  這里主要看看wrapIfNecessary方法(只保留了部分代碼):

  1. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  2. ......
  3. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  4. if (specificInterceptors != DO_NOT_PROXY) {
  5. this.advisedBeans.put(cacheKey, Boolean.TRUE);
  6. Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
  7. this.proxyTypes.put(cacheKey, proxy.getClass());
  8. return proxy;
  9. }
  10. ......
  11. }

  其中核心的是兩個方法調用,分別是getAdvicesAndAdvisorsForBean和createProxy。getAdvicesAndAdvisorsForBean會返回一個對象數組,包含aop相關的一些對象,如果是一個普通的不需要代理的對象會返回一個空Object數組,也就是DO_NOT_PROXY;createProxy方法則是創建代理類。

  先看看getAdvicesAndAdvisorsForBean方法:

  1. protected abstract Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException;

  getAdvicesAndAdvisorsForBean方法在當前類(AbstractAutoProxyCreator)中是一個抽象方法,由子類AbstractAdvisorAutoProxyCreator實現:

  1. public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
  2. @Override
  3. protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
  4. List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
  5. if (advisors.isEmpty()) {
  6. return DO_NOT_PROXY;
  7. }
  8. return advisors.toArray();
  9. }
  10. }

  代碼很清晰,我們進入findEligibleAdvisors方法,看方法名也知道它會完成尋找Advisor的工作:

  1. protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  2. //尋找Advisor
  3. List<Advisor> candidateAdvisors = findCandidateAdvisors();
  4. //針對指定的bean,過濾可用的Advisor,比如根據注解匹配
  5. List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  6. extendAdvisors(eligibleAdvisors);
  7. if (!eligibleAdvisors.isEmpty()) {
  8. eligibleAdvisors = sortAdvisors(eligibleAdvisors);
  9. }
  10. return eligibleAdvisors;
  11. }

  首先進入findCandidateAdvisors方法:

  1. protected List<Advisor> findCandidateAdvisors() {
  2. // Add all the Spring advisors found according to superclass rules.
  3. List<Advisor> advisors = super.findCandidateAdvisors();
  4. // Build Advisors for all AspectJ aspects in the bean factory.
  5. advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  6. return advisors;
  7. }

  我們這里主要看看aspectj的邏輯,所以看看aspectJAdvisorsBuilder.buildAspectJAdvisors方法(只保留了主要代碼):

  1. public List<Advisor> buildAspectJAdvisors() {
  2. List<String> aspectNames = null;
  3. ......
  4. synchronized (this) {
  5. aspectNames = this.aspectBeanNames;
  6. if (aspectNames == null) {
  7. //獲取所有管理的beanName
  8. String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
  9. //遍歷每個beanName
  10. for (String beanName : beanNames) {
  11. //從beanFactory獲取Class
  12. Class<?> beanType = this.beanFactory.getType(beanName);
  13. //檢查對應的Class是否實現Aspect注解
  14. if (this.advisorFactory.isAspect(beanType)) {
  15. //說明這個beanName對應的類是一個切面
  16. aspectNames.add(beanName);
  17. AspectMetadata amd = new AspectMetadata(beanType, beanName);
  18. if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
  19. MetadataAwareAspectInstanceFactory factory =
  20. new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
  21. //獲取Advisor,主要是解析對象中關于AOP的注解,比如Pointcut
  22. List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
  23. if (this.beanFactory.isSingleton(beanName)) {
  24. //就放入緩存,后面就不用重新解析了
  25. this.advisorsCache.put(beanName, classAdvisors);
  26. }
  27. advisors.addAll(classAdvisors);
  28. }
  29. }
  30. }
  31. this.aspectBeanNames = aspectNames;
  32. return advisors;
  33. }
  34. }
  35. ......
  36. }

  會從beanFactory中尋找所有管理的beanName,返回一個String數組,然后遍歷數組,從beanFactory中根據beanName獲取對應的Class,然后再看對應的Class是否有Aspect注解,如果有對應的注解,那么就表示這個對象是一個切面。接下來就需要進行解析,生成真正的Advisor對象,最后放入緩存。

  可以看看isAspect方法是如何判斷的:

  1. @Override
  2. public boolean isAspect(Class<?> clazz) {
  3. return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
  4. }
  5. private boolean hasAspectAnnotation(Class<?> clazz) {
  6. return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
  7. }

  邏輯很清晰,主要就是看有沒有Aspect注解。 但是這里要注意,這個buildAspectJAdvisors方法通常不是在這里調用的(”這里“的意思是postProcessAfterInitialization的流程)。回到AnnotationAwareAspectJAutoProxyCreator繼承關系圖中,它也實現了InstantiationAwareBeanPostProcessor接口,同樣在其父類AbstractAutoProxyCreator中實現了postProcessBeforeInstantiation方法,這個方法會在對象實例化(不是初始化)之前調用,在該方法的邏輯里通常會首先觸發buildAspectJAdvisors方法的執行,執行之后會把結果緩存起來。

  好了,再回到findEligibleAdvisors方法,上面代碼已經貼了,這里就不貼了。獲取到Advisor列表之后,要從中找到能用于指定類的Advisor列表,然后返回。接下來就要為指定的對象創建代理對象了,也就是AbstractAutoProxyCreator類的createProxy方法:

  1. protected Object createProxy(
  2. Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
  3.  
  4. ProxyFactory proxyFactory = new ProxyFactory();
  5. proxyFactory.copyFrom(this);
  6.  
  7. if (!proxyFactory.isProxyTargetClass()) {
  8. if (shouldProxyTargetClass(beanClass, beanName)) {
  9. proxyFactory.setProxyTargetClass(true);
  10. }
  11. else {
  12. evaluateProxyInterfaces(beanClass, proxyFactory);
  13. }
  14. }
  15.  
  16. Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
  17. for (Advisor advisor : advisors) {
  18. proxyFactory.addAdvisor(advisor);
  19. }
  20.  
  21. proxyFactory.setTargetSource(targetSource);
  22. customizeProxyFactory(proxyFactory);
  23.  
  24. proxyFactory.setFrozen(this.freezeProxy);
  25. if (advisorsPreFiltered()) {
  26. proxyFactory.setPreFiltered(true);
  27. }
  28.  
  29. return proxyFactory.getProxy(getProxyClassLoader());
  30. }

  代理對象是由ProxyFactory代理工廠創建的,我們先看看這個工廠是如何創建代理對象的,也就是proxyFactory.getProxy方法:

  1. public Object getProxy(ClassLoader classLoader) {
  2. return createAopProxy().getProxy(classLoader);
  3. }

  createAopProxy方法會返回一個AopProxy,該方法定義在ProxyFactory的父類ProxyCreatorSupport中:

  1. public class ProxyCreatorSupport extends AdvisedSupport {
  2. private AopProxyFactory aopProxyFactory;
  3. public ProxyCreatorSupport() {
  4. //設置默認的代理工廠DefaultAopProxyFactory
  5. this.aopProxyFactory = new DefaultAopProxyFactory();
  6. }
  7. public AopProxyFactory getAopProxyFactory() {
  8. //獲取代理工廠,默認就是DefaultAopProxyFactory
  9. return this.aopProxyFactory;
  10. }
  11.  
  12. protected final synchronized AopProxy createAopProxy() {
  13. //先獲取代理工廠,然后調用工廠的createAopProxy方法創建AopProxy
  14. return getAopProxyFactory().createAopProxy(this);
  15. }
  16. }

  上面貼出了關鍵代碼,getAopProxyFactory默認返回的是一個DefaultAopProxyFactory工廠類,來看看DefaultAopProxyFactory的createAopProxy方法:

  1. public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  2. if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
  3. Class<?> targetClass = config.getTargetClass();
  4. if (targetClass.isInterface()) {
  5. return new JdkDynamicAopProxy(config);
  6. }
  7. return new ObjenesisCglibAopProxy(config);
  8. }
  9. else {
  10. return new JdkDynamicAopProxy(config);
  11. }
  12. }

  代碼中有一些代理配置的判斷,這里不用關心。可以看到它提供了兩個AopProxy,分別是基于JDK的JdkDynamicAopProxy和基于cglib的ObjenesisCglibAopProxy。由于JDK提供的動態代理實現最終生成的代理類默認會繼承Proxy類,實現被代理類實現的接口,因為Java是單繼承,所以只能通過接口實現,也就限制了要使用JDK提供的動態代理,必須要基于接口。而使用cglib基于字節碼的改造則沒有這個限制,所以Spring提供了這兩種方式,根據被代理類的實際情況來選擇。

  關于每個AopProxy是如何創建代理類的,這里就先不跟了~

總結

  總的來說,動態代理是實現AOP的重要手段,Spring提供的動態代理主要依靠其提供的BeanPostProcessor,也稱之為后置處理器。除了BeanPostProcessor之外,還有InstantiationAwareBeanPostProcessor(也繼承了BeanPostProcessor),它們會在bean的生命周期的特定階段被調用,以開放給開發者處理和調整對象的入口或者手段。動態代理依托后置處理器,在后置處理器的邏輯中使用AopProxy創建了被代理對象的代理類,然后代替原有類存入Spring的bean工廠中,之后根據beanName獲取的實例對象就不再是原對象實例,而是代理類。而AopProxy是由AopProxyFactory接口生成,目前該接口只有DefaultAopProxyFactory實現類,其提供了兩種AopProxy,分別基于原生JDK提供的動態代理和cgib,根據實際情況選擇。

Spring源碼學習之動態代理實現流程

到此這篇關于Spring源碼學習之動態代理實現流程的文章就介紹到這了,更多相關Spring動態代理實現內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/huangzhilin2015/article/details/115255075

延伸 · 閱讀

精彩推薦
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7472021-02-04
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
主站蜘蛛池模板: 亚洲色图图| 第一福利在线观看永久视频 | 极品美女aⅴ高清在线观看 极品ts赵恩静和直男激战啪啪 | 极品美女穴 | freexxxx性护士第一次 | 偷偷狠狠的日日高清完整视频 | 国产精品原创永久在线观看 | 久青草国产在视频在线观看 | 亚洲精品午夜视频 | 国产在线观看91 | 男人女人叉叉叉 | 四影虎库最新2021 | 欧美日韩国产亚洲一区二区三区 | 欧美精品1区 | 国产免费一区二区三区 | 日韩不卡一区二区 | 五月色天在线视频综合观看 | 国产色图片 | 9热在线精品视频观看 | 三级黄片毛片 | 亚洲123区 | 天天射寡妇射 | 精品久久久久久久久久久久久久久 | 免费大秀视频在线播放 | 色婷婷久久综合中文久久一本` | 国产福利在线免费观看 | 动漫人物差差插曲漫画 | 欧美1区| 欧美福利二区 | 湿好紧太硬了我太爽了 | 继攵催眠女乱h调教 | 亚洲一卡2卡三卡4卡5卡组 | 天天做天天爱天天爽综合网 | 免费看成年视频网页 | 草莓视频首页 | 日本视频高清免费观看xxx | 4444亚洲国产成人精品 | 亚久久伊人精品青青草原2020 | 亚洲日本va中文字幕 | 国产成人精品一区二三区2022 | www.色啪啪.com|