1.【Spring注解驱动开发】二狗子让我给他讲讲@EnableAspectJAutoProxy注解
2.Spring源码插播一个创建代理对象的码解wrapIfNecessary()方法
3.å¦ä½ç解SpringçAOPï¼
4.springaopåç
5.è°è°å¯¹springaopçç解ï¼
6.76 张图,剖析 Spring AOP 源码,码解小白居然也能看懂,码解大神,码解请收下我的码解膝盖!
【Spring注解驱动开发】二狗子让我给他讲讲@EnableAspectJAutoProxy注解
在配置类上添加@EnableAspectJAutoProxy注解,码解做小程序要源码能够开启注解版的码解AOP功能。这意味着,码解如果在AOP中要启用注解版的码解AOP功能,就需要在配置类上添加@EnableAspectJAutoProxy注解。码解让我们来看看@EnableAspectJAutoProxy注解的码解源码,如下所示。码解
从源码可以看出,码解@EnableAspectJAutoProxy注解使用@Import注解引入了AspectJAutoProxyRegister.class对象。码解那么,码解AspectJAutoProxyRegistrar是做什么的呢?我们点击到AspectJAutoProxyRegistrar类的源码中,如下所示。
可以看到AspectJAutoProxyRegistrar类实现了ImportBeanDefinitionRegistrar接口。我们回顾ImportBeanDefinitionRegistrar接口的定义,如下所示。
通过ImportBeanDefinitionRegistrar接口,我们可以实现将自定义的组件添加到IOC容器中。也就是说,@EnableAspectJAutoProxy注解使用AspectJAutoProxyRegistrar对象自定义组件,并将相应的组件添加到IOC容器中。
在AspectJAutoProxyRegistrar类的registerBeanDefinitions()方法中设置断点,我们以debug的方法来运行AopTest类的testAop()方法。当程序运行到断点位置时,我们可以看到程序已经暂停,IDEA的左下角显示了方法的调用栈。
在registerBeanDefinitions()方法中,首先调用AopConfigUtils类的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法来注册registry。在registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中,直接调用了重载的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法。在重载的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中,传入了AnnotationAwareAspectJAutoProxyCreator.class对象。
在registerOrEscalateApcAsRequired()方法中,接收到的巴西slot源码Class对象的类型为:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator。然后,我们继续跟进代码。
在registerOrEscalateApcAsRequired()方法中,首先判断registry是否包含org.springframework.aop.config.internalAutoProxyCreator类型的bean。接下来,我们继续看代码。
最终,AopConfigUtils类的registerOrEscalateApcAsRequired()方法中,会通过registry调用registerBeanDefinition()方法注册组件,并注册的bean的名称为org.springframework.aop.config.internalAutoProxyCreator。
接下来,我们继续看AspectJAutoProxyRegistrar类的registerBeanDefinitions()源码。我们通过AnnotationConfigUtils类的attributesFor方法来获取@EnableAspectJAutoProxy注解的信息。接下来,我们继续判断proxyTargetClass属性的值是否为true,如果为true则调用AopConfigUtils类的forceAutoProxyCreatorToUseClassProxying()方法;继续判断exposeProxy属性的值是否为true,如果为true则调用AopConfigUtils类的forceAutoProxyCreatorToExposeProxy()方法。
综上所述,向Spring的配置类上添加@EnableAspectJAutoProxy注解后,会向IOC容器中注册AnnotationAwareAspectJAutoProxyCreator。
了解了这些之后,我们就可以关注「冰河技术」微信公众号,后台回复不同的关键字获取相应的PDF文档。这些文档都是由冰河原创并整理的超硬核教程,包括《深入浅出Java 种设计模式》、《Java8新特性教程》和《亿级流量下的分布式限流解决方案》,都是面试必备的资料。
最后,如果你觉得这篇文章对你有帮助,别忘了点个赞,给个在看和转发,让更多的人看到,一起学习,一起进步!
Spring源码插播一个创建代理对象的wrapIfNecessary()方法
在深入探讨Spring源码中创建代理对象的`wrapIfNecessary()`方法之前,先简要回顾其作用。`wrapIfNecessary()`方法主要任务是倒卖源码利润基于一系列条件判断,决定是否为Bean创建代理对象,从而实现AOP(面向切面编程)的功能。下面,我们将逐步解析这一方法的内部逻辑。
`wrapIfNecessary()`方法的执行流程可以分为以下阶段:
1. **条件判断**:
- **已处理Bean**:首先检查传入的Bean是否已处理过,即在`targetSourcedBeans`集合中是否存在该Bean的记录。
- **已创建代理**:接着检查`advisedBeans`集合中是否已有该Bean的代理对象缓存,以确认是否需要再次创建代理。
- **自定义Bean**:通过`isInfrastructureClass()`方法判断是否为Spring自带的Bean,排除此类无需代理的情况。
- **无需代理**:如果上述任一条件满足,则直接返回传入的Bean对象,无需创建代理。
2. **代理创建**:
- **获取Advices和Advisors**:如果上述条件均不满足,则调用`getAdvicesAndAdvisorsForBean()`方法获取当前Bean的Advices和Advisors信息。
- **判断适配**:通过`findEligibleAdvisors()`方法从候选通知器中筛选出适合当前Bean的Advisors,确保这些Advisors可以应用到当前Bean。
- **实现逻辑**:通过`findCandidateAdvisors()`和`findAdvisorsThatCanApply()`方法进一步筛选、拓展、排序Advisors,最终获取到实际需要应用的Adviser集合。
3. **代理构建**:
- **决策**:根据获取的Advisors判断是否需要创建代理。若结果非`DO_NOT_PROXY`,则调用`createProxy()`方法创建代理对象,并缓存以备后续使用。
- **过程**:在创建代理过程中,`exposeTargetClass()`方法设置Bean的属性,`shouldProxyTargetClass()`方法决定使用JDK动态代理还是CGLIB动态代理,`evaluateProxyInterfaces()`方法添加代理接口,最终通过`getProxy()`方法构建代理对象。
4. **优化与扩展**:
- **Advisors排序**:调用`sortAdvisors()`方法对Advisors进行排序,优化代理逻辑执行顺序。
- **扩展与定制**:通过`extendAdvisors()`方法提供扩展点,允许对目标Advisor进行进一步定制。
5. **构建代理对象**:
- **代理工厂**:通过`AopProxyFactory`初始化代理工厂,并在构建代理对象时,考虑接口添加、阿帕奇源码搭建回调函数配置等,最终通过`createProxy()`方法生成可调用的代理对象。
通过这一系列复杂而有序的过程,`wrapIfNecessary()`方法实现了根据特定条件判断是否创建代理对象,并构建出适用于面向切面编程场景的代理对象,进而增强了应用程序的功能性和灵活性。
å¦ä½ç解SpringçAOPï¼
SpringçAOPé¢ååé¢ç¼ç¨ï¼å°±æ¯æ¨ªåçï¼æ¯å¦ç¨åºè¿è¡æ¶é½è¦å»ºæ¥å¿ï¼ç¸å½äºSQLç触åå¨ãSpringæ¯ä¸ä¸ªå¼æ¾æºä»£ç ç设计å±é¢æ¡æ¶ï¼ä»è§£å³çæ¯ä¸å¡é»è¾å±åå ¶ä»åå±çæ¾è¦åé®é¢ï¼å æ¤å®å°é¢åæ¥å£çç¼ç¨ææ³è´¯ç©¿æ´ä¸ªç³»ç»åºç¨ãSpringæ¯äº å¹´å ´èµ·çä¸ä¸ªè½»é级çJava å¼åæ¡æ¶ï¼ç±Rod Johnsonå建ãç®åæ¥è¯´ï¼Springæ¯ä¸ä¸ªåå±çJavaSE/EEfull-stack(ä¸ç«å¼) è½»é级å¼æºæ¡æ¶ã
Springç¹ç¹ï¼
1ãæ¹ä¾¿è§£è¦ï¼ç®åå¼å
éè¿Springæä¾çIoC容å¨ï¼æ们å¯ä»¥å°å¯¹è±¡ä¹é´çä¾èµå ³ç³»äº¤ç±Springè¿è¡æ§å¶ï¼é¿å 硬ç¼ç æé æçè¿åº¦ç¨åºè¦åãæäºSpringï¼ç¨æ·ä¸å¿ å为åå®ä¾æ¨¡å¼ç±»ãå±æ§æ件解æçè¿äºå¾åºå±çéæ±ç¼å代ç ï¼å¯ä»¥æ´ä¸æ³¨äºä¸å±çåºç¨ã
2ãAOPç¼ç¨çæ¯æ
éè¿Springæä¾çAOPåè½ï¼æ¹ä¾¿è¿è¡é¢ååé¢çç¼ç¨ï¼è®¸å¤ä¸å®¹æç¨ä¼ ç»OOPå®ç°çåè½å¯ä»¥éè¿AOPè½»æ¾åºä»ã
3ã声æå¼äºå¡çæ¯æ
å¨Springä¸ï¼æ们å¯ä»¥ä»åè°ç¦é·çäºå¡ç®¡ç代ç ä¸è§£è±åºæ¥ï¼éè¿å£°æå¼æ¹å¼çµæ´»å°è¿è¡äºå¡ç管çï¼æé«å¼åæçåè´¨éã
4ãæ¹ä¾¿ç¨åºçæµè¯
å¯ä»¥ç¨é容å¨ä¾èµçç¼ç¨æ¹å¼è¿è¡å ä¹ææçæµè¯å·¥ä½ï¼å¨Springéï¼æµè¯ä¸åæ¯æè´µçæä½ï¼èæ¯éæå¯åçäºæ ãä¾å¦:Spring对Junit4æ¯æï¼å¯ä»¥éè¿æ³¨è§£æ¹ä¾¿çæµè¯Springç¨åºã
5ãæ¹ä¾¿éæåç§ä¼ç§æ¡æ¶
Springä¸ææ¥åç§ä¼ç§çå¼æºæ¡æ¶ï¼ç¸åï¼Springå¯ä»¥éä½åç§æ¡æ¶ç使ç¨é¾åº¦ï¼Springæä¾äºå¯¹åç§ä¼ç§æ¡æ¶(å¦Struts,HibernateãHessianãQuartz)ççç´æ¥æ¯æã
6ãéä½Java EE APIç使ç¨é¾åº¦
Spring对å¾å¤é¾ç¨çJava EE API(å¦JDBCï¼JavaMailï¼è¿ç¨è°ç¨ç)æä¾äºä¸ä¸ªèèçå°è£ å±ï¼éè¿Springçç®æå°è£ ï¼è¿äºJava EE APIç使ç¨é¾åº¦å¤§ä¸ºéä½ã
7ãJava æºç æ¯ç»å ¸å¦ä¹ èä¾
Springçæºç 设计精å¦ãç»ææ¸ æ°ãå å¿ç¬è¿ï¼å¤å¤ä½ç°ç大å¸å¯¹Java设计模å¼çµæ´»è¿ç¨ä»¥å对Javaææ¯çé«æ·±é 诣ãSpringæ¡æ¶æºç æ çæ¯Javaææ¯çæä½³å®è·µèä¾ãå¦ææ³å¨çæ¶é´å è¿ éæé«èªå·±çJavaææ¯æ°´å¹³ååºç¨å¼åæ°´å¹³ï¼å¦ä¹ åç 究Springæºç å°ä¼ä½¿ä½ æ¶å°ææ³ä¸å°çææã
springaopåç
åçï¼sping aopæ¯å¯ä»¥éè¿é¢ç¼è¯æ¹å¼åè¿è¡æå¨æ代çå®ç°å¨ä¸ä¿®æ¹æºä»£ç çæ åµä¸ç»ç¨åºå¨æç»ä¸æ·»å åè½çä¸ç§ææ¯ãAOP设计模å¼ååä¸å¦è¿½æ±çæ¯è°ç¨è å被è°ç¨è ä¹é´ç解è¦ï¼AOP å¯ä»¥è¯´ä¹æ¯è¿ç§ç®æ çä¸ç§å®ç°ãå ¶åççç¸å ³ææ¯ï¼
AOPæ¯OOPç延ç»ï¼æ¯Aspect Oriented Programmingç缩åï¼æææ¯é¢ååé¢ç¼ç¨ãAOPï¼è¿éçAOPæçæ¯é¢ååé¢ç¼ç¨ææ³ï¼èä¸æ¯Spring AOPï¼ä¸»è¦ççå®ç°ææ¯ä¸»è¦æSpring AOPåAspectJã
AspectJçåºå±ææ¯æ¯éæ代çï¼å³ç¨ä¸ç§AspectJæ¯æçç¹å®è¯è¨ç¼ååé¢ï¼éè¿ä¸ä¸ªå½ä»¤æ¥ç¼è¯ï¼çæä¸ä¸ªæ°ç代çç±»ï¼è¯¥ä»£çç±»å¢å¼ºäºä¸å¡ç±»ï¼è¿æ¯å¨ç¼è¯æ¶å¢å¼ºï¼ç¸å¯¹äºä¸é¢è¯´çè¿è¡æ¶å¢å¼ºï¼ç¼è¯æ¶å¢å¼ºçæ§è½æ´å¥½ã
Spring AOPéç¨çæ¯å¨æ代çï¼å¨è¿è¡æé´å¯¹ä¸å¡æ¹æ³è¿è¡å¢å¼ºï¼æ以ä¸ä¼çææ°ç±»ï¼å¯¹äºå¨æ代çææ¯ï¼Spring AOPæä¾äºå¯¹JDKå¨æ代ççæ¯æ以åCGLibçæ¯æã
JDKå¨æ代çåªè½ä¸ºæ¥å£å建å¨æ代çå®ä¾ï¼èä¸è½å¯¹ç±»å建å¨æ代çãéè¦è·å¾è¢«ç®æ ç±»çæ¥å£ä¿¡æ¯ï¼åºç¨Javaçåå°ææ¯ï¼ï¼çæä¸ä¸ªå®ç°äºä»£çæ¥å£çå¨æ代çç±»ï¼åèç ï¼ï¼åéè¿åå°æºå¶è·å¾å¨æ代çç±»çæé å½æ°ï¼å©ç¨æé å½æ°çæå¨æ代çç±»çå®ä¾å¯¹è±¡ï¼å¨è°ç¨å ·ä½æ¹æ³åè°ç¨invokeHandleræ¹æ³æ¥å¤çã
è°è°å¯¹springaopçç解ï¼
SpringçAOPå¦ä½ç解,å¨ä¸å¡éçä½ç¨æ¯ä»ä¹?
1ãAOPç¼ç¨çæ¯æéè¿Springæä¾çAOPåè½ï¼æ¹ä¾¿è¿è¡é¢ååé¢çç¼ç¨ï¼è®¸å¤ä¸å®¹æç¨ä¼ ç»OOPå®ç°çåè½å¯ä»¥éè¿AOPè½»æ¾åºä»ã
2ãAOPï¼é¢ååé¢ï¼æ¯ä¸ç§ç¼ç¨ææ³ï¼OOPç延ç»ãå°ç³»ç»ä¸éæ ¸å¿çä¸å¡æååºæ¥ï¼è¿è¡åç¬å¤çãæ¯å¦äºå¡ãæ¥å¿åå®å ¨çãè¿ä¸ªç®åæ¥è¯´å°±æ¯å¯ä»¥å¨ä¸æ®µç¨åºä¹åæè ä¹ååä¸äºäºã
3ãå®ä¹å¢å¼ºå¤çï¼å¢å¼ºå¤çå°±æ¯å¨AOPæ¡æ¶ä¸ºæ®éä¸å¡ç»ä»¶ç»å ¥çå¤çå¨ä½æ以è¿è¡AOPç¼ç¨çå ³é®å°±æ¯å®ä¹åå ¥ç¹åå®ä¹å¢å¼ºå¤çï¼ä¸æ¦å®ä¹äºåéçåå ¥ç¹åå¢å¼ºå¤çï¼AOPæ¡æ¶å°èªå¨çæAOP代çï¼å³ï¼ä»£ç对象çæ¹æ³=å¢å¼ºå¤ç+被代ç对象çæ¹æ³ã
Springä¸çAOPæä¹ç解
åé¢ç¼ç¨ï¼å°±æ¯å¨ä½ 项ç®åæçåè½åºç¡ä¸ï¼éè¿AOPå»æ·»å æ°çåè½ï¼è¿äºåè½æ¯å»ºç«å¨åæåè½çåºç¡ä¸çï¼èä¸åæçåè½å¹¶ä¸ç¥éä½ å·²ç»æ·»å äºæ°çåè½ã
IoCå°±æ¯å¯¹è±¡çå建ï¼ä¾èµé½ç±Springåé ç½®æ件æ§å¶ï¼AOPå°±æ¯ç»ä¸çç»ä¸äºç±»ä¼¼çæ¹æ³å ä¸åæ ·çåè½ï¼æ¯å¦æ¥å¿ï¼äºå¡ãSpringæ¡æ¶æ¯ä¸ä¸ªåå±æ¶æï¼ç±7个å®ä¹è¯å¥½ç模åç»æã
å¨AOPä¸æå 个æ¦å¿µï¼âæ¹é¢ï¼Aspectï¼ï¼ä¸ä¸ªå ³æ³¨ç¹ç模ååï¼è¿ä¸ªå ³æ³¨ç¹å®ç°å¯è½å¦å¤æ¨ªåå¤ä¸ªå¯¹è±¡ãäºå¡ç®¡çæ¯J2EEåºç¨ä¸ä¸ä¸ªå¾å¥½ç横åå ³æ³¨ç¹ä¾åãæ¹é¢ç¨SpringçAdvisorææ¦æªå¨å®ç°ã
AOPï¼é¢ååé¢ï¼æ¯ä¸ç§ç¼ç¨ææ³ï¼OOPç延ç»ãå°ç³»ç»ä¸éæ ¸å¿çä¸å¡æååºæ¥ï¼è¿è¡åç¬å¤çãæ¯å¦äºå¡ãæ¥å¿åå®å ¨çãè¿ä¸ªç®åæ¥è¯´å°±æ¯å¯ä»¥å¨ä¸æ®µç¨åºä¹åæè ä¹ååä¸äºäºã
SpringAOPæ¯ç¼ç¨æ¡æ¶AOPæ¯OOPç延ç»ï¼æ¯AspectOrientedProgrammingç缩åï¼æææ¯é¢åæ¹é¢ç¼ç¨ãAOPå®é æ¯GoF设计模å¼ç延ç»ï¼è®¾è®¡æ¨¡å¼ååä¸å¦è¿½æ±çæ¯è°ç¨è å被è°ç¨è ä¹é´ç解è¦ï¼AOPå¯ä»¥è¯´ä¹æ¯è¿ç§ç®æ çä¸ç§å®ç°ã
æ¬äººæä¸æSpringä¸çAOPç解æä¸ç§æ¹æ³çæ¦æªå¨ï¼å¯è½ææçé¢ï¼ä¸»è¦æ¯æ¹ä¾¿ç解ï¼ã个人éä¿ç解ï¼å°±å¥½æ¯ä½ å»èªå¨å款æºåé±ï¼è¾¹ä¸è£ äºä¸ªæå头å¨çè§çã
è¯·ä½ è°è°å¯¹springçç解?springçåºæ¬æææ¯âæ¥å¤©ï¼æ¥å£âï¼å¼ç³å¯æâéæ¥âãspringè¿å¯ä½âè·³ââè·³è·â解ï¼å¼ç³å¯æâ弹簧ï¼åæ¡ââæ³æ°´âï¼æ¯å¯æ°åè¯ãspringè·å¸¦æ延ç»æ§çä»è¯æ¶ï¼åé¢è¦å å®å è¯theã
Springæ¯ä¸ä¸ªå¼æ¾æºä»£ç çJ2EEåºç¨ç¨åºæ¡æ¶ï¼ç±RodJohnsonåèµ·ï¼æ¯é对beanççå½å¨æè¿è¡ç®¡ççè½»é级容å¨ï¼lightweightcontainerï¼ã
Springæ¡æ¶æ¦è¿°Coreå°è£ å æ¯æ¡æ¶çæåºç¡é¨åï¼æä¾IoCåä¾èµæ³¨å ¥ç¹æ§ãè¿éçåºç¡æ¦å¿µæ¯BeanFactoryï¼å®æä¾å¯¹Factory模å¼çç»å ¸å®ç°æ¥æ¶é¤å¯¹ç¨åºæ§åä¾æ¨¡å¼çéè¦ï¼å¹¶çæ£å°å è®¸ä½ ä»ç¨åºé»è¾ä¸å离åºä¾èµå ³ç³»åé ç½®ã
ç®è¿°ä½ 对Springæ¡æ¶IOCåAOPçç解ãIoCå°±æ¯å¯¹è±¡çå建ï¼ä¾èµé½ç±Springåé ç½®æ件æ§å¶ï¼AOPå°±æ¯ç»ä¸çç»ä¸äºç±»ä¼¼çæ¹æ³å ä¸åæ ·çåè½ï¼æ¯å¦æ¥å¿ï¼äºå¡ãSpringæ¡æ¶æ¯ä¸ä¸ªåå±æ¶æï¼ç±7个å®ä¹è¯å¥½ç模åç»æã
iocå°±æ¯æ§å¶å转ï¼å¯ä»¥ç解为å½spring被å è½½å¯å¨åï¼å¨springé ç½®çbeané½ä¼è¢«è¿ä¸ªæ¡æ¶é¢å å®ä¾åï¼ä½ç¨äºä¸ºåä¾ï¼ï¼ç¶åå¨ä½ éè¦çè¿ä¸ªå¯¹è±¡çæ¶åç´æ¥æ·»å æ³¨å ¥å°±å¯ä»¥è°ç¨è¿ä¸ªå¯¹è±¡äºè¿æ ·å¯ä»¥å¤§å¤§éä½äºç±»ä¹é´çè¦å度ã
AOPï¼é¢ååé¢ï¼æ¯ä¸ç§ç¼ç¨ææ³ï¼OOPç延ç»ãå°ç³»ç»ä¸éæ ¸å¿çä¸å¡æååºæ¥ï¼è¿è¡åç¬å¤çãæ¯å¦äºå¡ãæ¥å¿åå®å ¨çãè¿ä¸ªç®åæ¥è¯´å°±æ¯å¯ä»¥å¨ä¸æ®µç¨åºä¹åæè ä¹ååä¸äºäºã
AOPæ¯OOPç延ç»ï¼æ¯è½¯ä»¶å¼åä¸çä¸ä¸ªçç¹ï¼ä¹æ¯Springæ¡æ¶ä¸çä¸ä¸ªéè¦å 容ï¼æ¯å½æ°å¼ç¼ç¨çä¸ç§è¡çèåã
æçç解iocå°±æ¯èªå¨å建对象çè¿ç¨ã以åæ¯éæ¶ç¨ï¼éæ¶newï¼ç¨äºiocå°±å°è¿ä¸ªäºä»¶äº¤ç»ç¨åºï¼èªå¨å¨å建对象ãaopå°±æ¯äºç©çæ§å¶ï¼æ¯å¦ä¸ä¸ªæ交æä½æ²¡æå®æï¼åèªå¨åæ»ã
è¿ä¸ªç¬¬ä¸æ¹æçå°±æ¯Springç容å¨ãIoCå¦è§£ï¼ä¾èµæ³¨å ¥ï¼DependencyInjectionï¼ï¼è°ç¨ç±»å¯¹è¢«è°ç¨ç±»çä¾èµå ³ç³»ç±ç¬¬ä¸æ¹æ³¨å ¥ï¼ä»¥ç§»é¤è°ç¨ç±»å¯¹è¢«è°ç¨ç±»çå¼ç¨ã
张图,剖析 Spring AOP 源码,小白居然也能看懂,大神,请收下我的膝盖!
本文将简要介绍AOP(面向切面编程)的基础知识与使用方法,并深入剖析Spring AOP源码。首先,我们需要理解AOP的基本概念。
1. **基础知识
**1.1 **什么是AOP?
**AOP全称为Aspect Oriented Programming,即面向切面编程。AOP的思想中,周边功能(如性能统计、日志记录、事务管理等)被定义为切面,核心功能与切面功能独立开发,然后将两者“编织”在一起,这就是AOP的核心。
AOP能够将与业务无关、却为业务模块共同调用的逻辑封装,减少系统重复代码,降低模块间的耦合度,有利于系统的可扩展性和可维护性。
1.2 **AOP基础概念
**解释较为官方,以下用“方言”解释:AOP包括五种通知分类。
1.3 **AOP简单示例
**创建`Louzai`类,添加`LouzaiAspect`切面,并在`applicationContext.xml`中配置。程序入口处添加`"睡觉"`方法并添加前置和后置通知。接下来,我们将探讨Spring内部如何实现这一过程。云豹2023源码
1.4 **Spring AOP工作流程
**为了便于理解后面的源码,我们将整体介绍源码执行流程。整个Spring AOP源码分为三块,结合示例进行讲解。
第一块是前置处理,创建`Louzai`Bean前,遍历所有切面信息并存储在缓存中。第二块是后置处理,创建`Louzai`Bean时,主要处理两件事。第三块是执行切面,通过“责任链+递归”执行切面。
2. **源码解读
**注意:Spring版本为5.2..RELEASE,否则代码可能不同!这里,我们将从原理部分开始,逐步深入源码。
2.1 **代码入口
**从`getBean()`函数开始,进入创建Bean的逻辑。
2.2 **前置处理
**主要任务是遍历切面信息并存储。
这是重点!请务必注意!获取切面信息流程结束,后续操作都从缓存`advisorsCache`获取。
2.2.1 **判断是否为切面
**执行逻辑为:判断是否包含切面信息。
2.2.2 **获取切面列表
**进入`getAdvice()`,生成切面信息。
2.3 **后置处理
**主要从缓存拿切面,与`Louzai`方法匹配,创建AOP代理对象。
进入`doCreateBean()`,执行后续逻辑。
2.3.1 **获取切面
**首先,查看如何获取`Louzai`的切面列表。
进入`buildAspectJAdvisors()`,方法用于存储切面信息至缓存`advisorsCache`。随后回到`findEligibleAdvisors()`,从缓存获取所有切面信息。
2.3.2 **创建代理对象
**有了`Louzai`的切面列表,开始创建AOP代理对象。
这是重点!请仔细阅读!这里有两种创建AOP代理对象方式,我们选择使用Cglib。
2.4 **切面执行
**通过“责任链+递归”执行切面与方法。
这部分逻辑非常复杂!接下来是“执行切面”最核心的逻辑,简述设计思路。
2.4.1 **第一次递归
**数组第一个对象执行`invoke()`,参数为`CglibMethodInvocation`。
执行完毕后,继续执行`CglibMethodInvocation`的`process()`。
2.4.2 **第二次递归
**数组第二个对象执行`invoke()`。
2.4.3 **第三次递归
**数组第三个对象执行`invoke()`。
执行完毕,退出递归,查看`invokeJoinpoint()`执行逻辑,即执行主方法。回到第三次递归入口,继续执行后续切面。
切面执行逻辑已演示,直接查看执行方法。
流程结束时,依次退出递归。
2.4.4 **设计思路
**这部分代码研究了大半天,因为这里不是纯粹的责任链模式。
纯粹的责任链模式中,对象内部有一个自身的`next`对象,执行当前对象方法后,启动`next`对象执行,直至最后一个`next`对象执行完毕,或中途因条件中断执行,责任链退出。
这里`CglibMethodInvocation`对象内部无`next`对象,通过`interceptorsAndDynamicMethodMatchers`数组控制执行顺序,依次执行数组中的对象,直至最后一个对象执行完毕,责任链退出。
这属于责任链,实现方式不同,后续会详细剖析。下面讨论类之间的关系。
主对象为`CglibMethodInvocation`,继承于`ReflectiveMethodInvocation`,`process()`的核心逻辑在`ReflectiveMethodInvocation`中。
`ReflectiveMethodInvocation`的`process()`控制整个责任链的执行。
`ReflectiveMethodInvocation`的`process()`方法中,包含一个长度为3的数组`interceptorsAndDynamicMethodMatchers`,存储了3个对象,分别为`ExposeInvocationInterceptor`、`MethodBeforeAdviceInterceptor`、`AfterReturningAdviceInterceptor`。
注意!这3个对象都继承了`MethodInterceptor`接口。
每次`invoke()`调用时,都会执行`CglibMethodInvocation`的`process()`。
是否有些困惑?别着急,我将再次帮你梳理。
对象与方法的关系:
可能有同学疑惑,`invoke()`的参数为`MethodInvocation`,没错!但`CglibMethodInvocation`也继承了`MethodInvocation`,可自行查看。
执行逻辑:
设计巧妙之处在于,纯粹的责任链模式中,`next`对象需要保证类型一致。但这里3个对象内部没有`next`成员,不能直接使用责任链模式。怎么办呢?就单独设计了`CglibMethodInvocation.process()`,通过无限递归`process()`实现责任链逻辑。
这就是我们为什么要研究源码,学习优秀的设计思路!
3. **总结
**本文首先介绍了AOP的基本概念与原理,通过示例展示了AOP的应用。之后深入剖析了Spring AOP源码,分为三部分。
本文是Spring源码解析的第三篇,感觉是难度较大的一篇。图解代码花费了6个小时,整个过程都沉浸在代码的解析中。
难度不在于抠图,而是“切面执行”的设计思路,即使流程能走通,将设计思想总结并清晰表达给读者,需要极大的耐心与理解能力。
今天的源码解析到此结束,有关Spring源码的学习,大家还想了解哪些内容,欢迎留言给楼仔。
SpringIoc和Aop底层原理
文章内容
本文深入解析Spring框架中的Ioc和Aop底层原理。
首先,Ioc(依赖注入)通过Spring配置文件实现对象的创建,而不是传统的new方式。实现Ioc,主要有两种方法:配置文件和注解。Ioc底层原理包括:使用xml配置文件创建类,通过dom4j解析配置,工厂设计模式配合使用,以及反射技术。通过Ioc,开发者只需修改bean配置属性,就能更换UserService类,有效降低类间的耦合度。
与DI(依赖注入)相比,Ioc更加关注控制反转,将对象创建权交由Spring管理;而DI则着重于在对象内部注入属性值。Ioc与DI相辅相成,DI必须在Ioc的基础上进行操作,即先创建对象后进行属性注入。
文章接下来解释了Spring整合web项目原理,包括加载Spring核心配置文件、服务器启动时动态加载配置和创建对象,以及使用ServletContext和监听器实现这一过程。具体操作包括为每个项目创建ServletContext对象、监听对象创建事件,并在contextInitialized()方法中加载配置文件和创建对象,最后将对象存储在ServletContext域对象中以便于获取。
Aop(面向切面编程)在Spring中实现,通过动态代理扩展功能,无需修改源代码。动态代理分为两种情况:有接口时使用jdk动态代理,无接口时使用cglib动态代理。Aop提供多种增强类型,包括前置、后置、异常、最终和环绕增强。
文章最后建议读者关注学习资源,通过扫描二维码获取更多知识和学习资料。
spring aop代理对象创建以及调用invoke源码
深入解析Spring AOP代理对象创建及调用invoke源码
一、代理对象创建与invoke源码概览
1.1 代理对象创建源码概览
Spring AOP代理对象的创建时机主要在实例化后或初始化后。具体流程涉及BeanPostProcessor.postProcessAfterInitialization()方法。正常情况下,代理对象创建与单例池内的代理对象一致,确保方法调用实际指向代理对象。
1.2 invoke执行目标方法源码概览
目标对象方法调用后,因为代理对象存储于单例池,实际调用的是代理对象的增强方法。这种方式实现了方法调用的动态代理。
1.3 exposeProxy = true使用说明
1.3.1 不使用(exposeProxy = true)
不使用配置时,目标方法内部调用被拦截增强的方法,不会再次触发AOP。
1.3.2 使用(exposeProxy = true)
启用此配置后,执行目标方法时,AOP增强将再次激活,从而触发重复执行。
1.3.3 cglib与JDK代理区别
cglib通过继承实现代理,方法调用指向代理对象,因此内嵌方法会重复调用增强逻辑;
JDK代理通过反射,方法调用直接指向目标对象,内嵌方法不会重复调用。
关于Spring中cglib不会重复调用的解释:测试表明,使用Spring5.版本,强制使用cglib配置时,案例中方法调用与代理对象方法调用之间并无重复,原因是Spring调用的是目标方法而非代理对象的方法。
二、代理对象创建及invoke源码分析图
代理创建流程始于@EnableAspectJAutoProxy注解注册的AspectJAutoProxyRegistrar,此注册器在解析import注解时执行registerBeanDefinitions方法。该方法注册了在bean实例化前调用的InstantiationAwareBeanPostProcessor类型的bean后置处理器,此处理器在实例化前解析AOP,非循环依赖在初始化后调用postProcessAfterInitialization()创建动态代理。
匹配Advisor集合:首先筛选Advisor列表,匹配规则涉及类级别和方法级别的筛选,通过Aspect匹配实现。同时,Advisor排序确保调用顺序遵循通知类型。创建代理对象遵循ProxyTargetClass参数与目标类接口的配置,选择JDK或cglib动态代理。
代理方法调用:由于存储的是代理对象,方法调用实际指向代理。exposeProxy = true配置下,代理对象暴露到线程变量中。代理对象执行方法调用遵循责任链模式,按顺序执行前置、目标方法、后置等通知。