1.springaopåç
2.springâAOPä¸äºå¡
3.Spring注解驱动开发二狗子让我给他讲讲@EnableAspectJAutoProxy注解
4.è°è°å¯¹springaopçç解ï¼
5.spring aop代理对象创建以及调用invoke源码
6.76 张图,码分剖析 Spring AOP 源码,码分小白居然也能看懂,码分大神,码分请收下我的码分膝盖!
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æ¹æ³æ¥å¤çã
springâAOPä¸äºå¡
title: springââAOPä¸äºå¡.mddate: -- ::
categories: [Spring]
tags: [AOP,码分捉妖系数源码äºå¡]
toc: true
å ååºæºç ä¸æ¯è¾éç¹çå 个类ï¼
1ã<aop:before method="before" pointcut-ref="myMethods"/>å è£ æä¸ä¸ªadvisor
2ãAspectJAwareAdvisorAutoProxyCreatorï¼å½å®ä¾åææbeané½ä¼æ§è¡å°AspectJAwareAdvisorAutoProxyCreatorç±»
å®ä¼æ£æµbeanæ¯å¦advisor以åadviceåå¨ï¼å¦ææ就说æè¿ä¸ªbeanæåé¢ï¼æåé¢é£ä¹å°±ä¼çæ代ç
3ãjdkç代çï¼beanéé¢çææadvisorå å ¥å°proxyFactoryã
4ãjdkDynamicProxy invokeï¼æ¿å°beanéé¢çææInterceptorï¼ä¼å¾ªç¯proxyFactoryéé¢çææadvisor
éé¢æadviceï¼éé¢çadviceæ两ç§ç±»åï¼è¦ä¹æ¯adviceï¼è¦ä¹æ¯MethodInterceptorç±»åç
5ãå½ä»£ç对象è°ç¨æ¹å¼ï¼æ¯ä¸ä¸ªMethodInterceptorç±»åçç±»çé¾å¼è°ç¨è¿ç¨ï¼ç´å°å®¹å¨ç大å°åç´¢å¼ä¸è´çæ¶åè°ç¨JoinPointç®æ æ¹æ³
beforeï¼this.advice.before(),invocation.processd();
è£ é åæ°ï¼åé¢éé¢beforeæ¹æ³çmethod对象ï¼method.getParamterTypes()[0]
æç»ä¼æadviceå°è£ æMethodInterceptorç±»åç对象
ç¨åºæ§è¡çæ个ç¹å®ä½ç½®ï¼å¦ç±»å¼å§åå§ååãç±»åå§ååãç±»æ个æ¹æ³è°ç¨åãè°ç¨åãæ¹æ³æåºå¼å¸¸åãä¸ä¸ªç±»æä¸æ®µç¨åºä»£ç æ¥æä¸äºå ·æè¾¹çæ§è´¨çç¹å®ç¹ï¼è¿äºç¹ä¸çç¹å®ç¹å°±ç§°ä¸ºâè¿æ¥ç¹âãSpringä» æ¯ææ¹æ³çè¿æ¥ç¹ï¼å³ä» è½å¨æ¹æ³è°ç¨åãæ¹æ³è°ç¨åãæ¹æ³æåºå¼å¸¸æ¶ä»¥åæ¹æ³è°ç¨ååè¿äºç¨åºæ§è¡ç¹ç»å ¥å¢å¼ºãè¿æ¥ç¹ç±ä¸¤ä¸ªä¿¡æ¯ç¡®å®ï¼ç¬¬ä¸æ¯ç¨æ¹æ³è¡¨ç¤ºçç¨åºæ§è¡ç¹ï¼ç¬¬äºæ¯ç¨ç¸å¯¹ç¹è¡¨ç¤ºçæ¹ä½ã
æ¯ä¸ªç¨åºç±»é½æ¥æå¤ä¸ªè¿æ¥ç¹ï¼å¦ä¸ä¸ªæ¥æ两个æ¹æ³çç±»ï¼è¿ä¸¤ä¸ªæ¹æ³é½æ¯è¿æ¥ç¹ï¼å³è¿æ¥ç¹æ¯ç¨åºç±»ä¸å®¢è§åå¨çäºç©ãAOPéè¿âåç¹âå®ä½ç¹å®çè¿æ¥ç¹ãè¿æ¥ç¹ç¸å½äºæ°æ®åºä¸çè®°å½ï¼èåç¹ç¸å½äºæ¥è¯¢æ¡ä»¶ãåç¹åè¿æ¥ç¹ä¸æ¯ä¸å¯¹ä¸çå ³ç³»ï¼ä¸ä¸ªåç¹å¯ä»¥å¹é å¤ä¸ªè¿æ¥ç¹ãå¨Springä¸ï¼åç¹éè¿org.springframework.aop.Pointcutæ¥å£è¿è¡æè¿°ï¼å®ä½¿ç¨ç±»åæ¹æ³ä½ä¸ºè¿æ¥ç¹çæ¥è¯¢æ¡ä»¶ï¼Spring AOPçè§å解æå¼æè´è´£åç¹æ设å®çæ¥è¯¢æ¡ä»¶ï¼æ¾å°å¯¹åºçè¿æ¥ç¹ãå ¶å®ç¡®åå°è¯´ï¼ä¸è½ç§°ä¹ä¸ºæ¥è¯¢è¿æ¥ç¹ï¼å 为è¿æ¥ç¹æ¯æ¹æ³æ§è¡åãæ§è¡åçå æ¬æ¹ä½ä¿¡æ¯çå ·ä½ç¨åºæ§è¡ç¹ï¼èåç¹åªå®ä½å°æ个æ¹æ³ä¸ï¼æ以å¦æå¸æå®ä½å°å ·ä½è¿æ¥ç¹ä¸ï¼è¿éè¦æä¾æ¹ä½ä¿¡æ¯ã
å¢å¼ºæ¯ç»å ¥å°ç®æ ç±»è¿æ¥ç¹ä¸çä¸æ®µç¨åºä»£ç ï¼å¨Springä¸ï¼å¢å¼ºé¤ç¨äºæè¿°ä¸æ®µç¨åºä»£ç å¤ï¼è¿æ¥æå¦ä¸ä¸ªåè¿æ¥ç¹ç¸å ³çä¿¡æ¯ï¼è¿ä¾¿æ¯æ§è¡ç¹çæ¹ä½ãç»åæ§è¡ç¹æ¹ä½ä¿¡æ¯ååç¹ä¿¡æ¯ï¼æ们就å¯ä»¥æ¾å°ç¹å®çè¿æ¥ç¹ã
å¢å¼ºé»è¾çç»å ¥ç®æ ç±»ãå¦æ没æAOPï¼ç®æ ä¸å¡ç±»éè¦èªå·±å®ç°ææé»è¾ï¼èå¨AOPç帮å©ä¸ï¼ç®æ ä¸å¡ç±»åªå®ç°é£äºé横åé»è¾çç¨åºé»è¾ï¼èæ§è½çè§åäºå¡ç®¡ççè¿äºæ¨ªåé»è¾åå¯ä»¥ä½¿ç¨AOPå¨æç»å ¥å°ç¹å®çè¿æ¥ç¹ä¸ã
å¼ä»æ¯ä¸ç§ç¹æ®çå¢å¼ºï¼å®ä¸ºç±»æ·»å ä¸äºå±æ§åæ¹æ³ãè¿æ ·ï¼å³ä½¿ä¸ä¸ªä¸å¡ç±»åæ¬æ²¡æå®ç°æ个æ¥å£ï¼éè¿AOPçå¼ä»åè½ï¼æ们å¯ä»¥å¨æå°ä¸ºè¯¥ä¸å¡ç±»æ·»å æ¥å£çå®ç°é»è¾ï¼è®©ä¸å¡ç±»æ为è¿ä¸ªæ¥å£çå®ç°ç±»ã
ç»å ¥æ¯å°å¢å¼ºæ·»å 对ç®æ ç±»å ·ä½è¿æ¥ç¹ä¸çè¿ç¨ãAOPåä¸å°ç»å¸æºï¼å°ç®æ ç±»ãå¢å¼ºæå¼ä»éè¿AOPè¿å°ç»å¸æºå¤©è¡£æ ç¼å°ç¼ç»å°ä¸èµ·ãæ ¹æ®ä¸åçå®ç°ææ¯ï¼AOPæä¸ç§ç»å ¥çæ¹å¼ï¼
aãç¼è¯æç»å ¥ï¼è¿è¦æ±ä½¿ç¨ç¹æ®çJavaç¼è¯å¨ã
bãç±»è£ è½½æç»å ¥ï¼è¿è¦æ±ä½¿ç¨ç¹æ®çç±»è£ è½½å¨ã
cãå¨æ代çç»å ¥ï¼å¨è¿è¡æ为ç®æ 类添å å¢å¼ºçæåç±»çæ¹å¼ã
Springéç¨å¨æ代çç»å ¥ï¼èAspectJéç¨ç¼è¯æç»å ¥åç±»è£ è½½æç»å ¥ã
ä¸ä¸ªç±»è¢«AOPç»å ¥å¢å¼ºåï¼å°±äº§åºäºä¸ä¸ªç»æç±»ï¼å®æ¯èåäºåç±»åå¢å¼ºé»è¾ç代çç±»ãæ ¹æ®ä¸åç代çæ¹å¼ï¼ä»£çç±»æ¢å¯è½æ¯ååç±»å ·æç¸åæ¥å£çç±»ï¼ä¹å¯è½å°±æ¯åç±»çåç±»ï¼æ以æ们å¯ä»¥éç¨è°ç¨åç±»ç¸åçæ¹å¼è°ç¨ä»£çç±»ã
åé¢ç±åç¹åå¢å¼ºï¼å¼ä»ï¼ç»æï¼å®æ¢å æ¬äºæ¨ªåé»è¾çå®ä¹ï¼ä¹å æ¬äºè¿æ¥ç¹çå®ä¹ï¼Spring AOPå°±æ¯è´è´£å®æ½åé¢çæ¡æ¶ï¼å®å°åé¢æå®ä¹ç横åé»è¾ç»å ¥å°åé¢ææå®çè¿æ¥ç¹ä¸ã
advisorï¼ pointCut advice
ä¸ç±»åè½çå¢å¼º
aroundæ¹æ³éé¢ä»£ç åé¢
äºå¡åé¢
ç¼ååé¢
æ¥å¿åé¢
äºå¡ï¼Transactionï¼ï¼ä¸è¬æ¯æè¦åçææåçäºæ ãå¨è®¡ç®æºæ¯è¯ä¸æ¯æ访é®å¹¶å¯è½æ´æ°æ°æ®åºä¸åç§æ°æ®é¡¹çä¸ä¸ªç¨åºæ§è¡åå (unit)ãæ¯æ°æ®åºæä½çæå°å·¥ä½åå ï¼æ¯ä½ä¸ºå个é»è¾å·¥ä½åå æ§è¡çä¸ç³»åæä½ï¼è¿äºæä½ä½ä¸ºä¸ä¸ªæ´ä½ä¸èµ·åç³»ç»æ交ï¼è¦ä¹é½æ§è¡ãè¦ä¹é½ä¸æ§è¡ï¼äºå¡æ¯ä¸ç»ä¸å¯ååå²çæä½éåï¼å·¥ä½é»è¾åå ï¼ã
大è´æµç¨å½¢å¦
æ°æ®åºäºå¡æ¥æå 大ç¹æ§ï¼
äºå¡çå大ç¹æ§ï¼
äºå¡æ¯æ°æ®åºçé»è¾å·¥ä½åä½ï¼äºå¡ä¸å å«çåæä½è¦ä¹é½åï¼è¦ä¹é½ä¸å
äº å¡æ§è¡çç»æå¿ é¡»æ¯ä½¿æ°æ®åºä»ä¸ä¸ªä¸è´æ§ç¶æåå°å¦ä¸ä¸ªä¸è´æ§ç¶æãå æ¤å½æ°æ®åºåªå å«æåäºå¡æ交çç»ææ¶ï¼å°±è¯´æ°æ®åºå¤äºä¸è´æ§ç¶æãå¦ææ°æ®åºç³»ç» è¿è¡ä¸åçæ éï¼æäºäºå¡å°æªå®æ就被迫ä¸æï¼è¿äºæªå®æäºå¡å¯¹æ°æ®åºæåçä¿®æ¹æä¸é¨åå·²åå ¥ç©çæ°æ®åºï¼è¿æ¶æ°æ®åºå°±å¤äºä¸ç§ä¸æ£ç¡®çç¶æï¼æè è¯´æ¯ ä¸ä¸è´çç¶æã
ä¸ä¸ªäºå¡çæ§è¡ä¸è½å ¶å®äºå¡å¹²æ°ãå³ä¸ä¸ªäºå¡å é¨çæä½å使ç¨çæ°æ®å¯¹å ¶å®å¹¶åäºå¡æ¯é离çï¼å¹¶åæ§è¡çå个äºå¡ä¹é´ä¸è½äºç¸å¹²æ°ã
ä¹ç§°æ°¸ä¹ æ§ï¼æä¸ä¸ªäºå¡ä¸æ¦æ交ï¼å®å¯¹æ°æ®åºä¸çæ°æ®çæ¹åå°±åºè¯¥æ¯æ°¸ä¹ æ§çãæ¥ä¸æ¥çå ¶å®æä½ææ éä¸åºè¯¥å¯¹å ¶æ§è¡ç»ææä»»ä½å½±åã
个人ç解ï¼äºå¡å¨Springä¸æ¯åå©AOPææ¯æ¥å®ç°çï¼å¯ä»¥ä½ä¸ºAOPä¸çä¸ä¸ªäºå¡åé¢ãspringæºç 对äºå¡çå¤çé»è¾ï¼èªå·±ç 究å§ï¼
ORMæ¡æ¶ä¸ä»¥Mybatis为ä¾ï¼äºå¡å¤çå°±æ¯ç¨å°äºä¸ä¸ªç±»Transactionï¼é¨åæºç å¦ä¸
å¯ä»¥çåºTransaction管ççå°±æ¯ä¸ä¸ªconnectionï¼èconnectionæ们å¾æ¸ æ¥æ¯ä¸ç¨æ·ä¼è¯æé©çã
é£ä¹å ³ç³»å°±æ¯Transaction 管çConnection ï¼èconnectionä¸ ç¨æ·sessionä¸å¯¹ä¸åå¨ã
å¨springBootä¸ï¼åªéè¦å å ¥POMå°±å¯ä»¥äºï¼é å注解使ç¨å³å¯ã
æ¥ä¸æ¥å°±æ¯äºå¡çæ§å¶äºã
é¦å äºå¡æå å¤§ä¼ æå±æ§ï¼
å ¶ä¸æ常è§çï¼ç¨å¾æå¤å°± PROPAGATION_REQUIREDãPROPAGATION_REQUIRES_NEWã PROPAGATION_NESTED è¿ä¸ç§ãäºå¡çä¼ æå±æ§æ¯ spring ç¹æçï¼æ¯ spring ç¨æ¥æ§å¶æ¹æ³äºå¡çä¸ç§æ段ï¼è¯´ç´ç½ç¹å°±æ¯ç¨æ¥æ§å¶æ¹æ³æ¯å¦ä½¿ç¨åä¸äºå¡çä¸ç§å±æ§ï¼ä»¥åæç §ä»ä¹è§ååæ»çä¸ç§æ段ã
ä¸é¢ç¨ä»£ç æ¼ç¤ºè¿ä¸ç§å±æ§çæºå¶ï¼
äºå¡çé»è®¤å±æ§å°±æ¯requiredï¼éè¿Transactional.javaä¸çPropagation propagation() default Propagation.REQUIRED; å¯ä»¥çåºã
è¿ç§æ åµå°±æ¯äºå¡1ï¼äºå¡2 é½å å ¥å°äºäºå¡0ä¸ãä¸ç®¡æ¯1ï¼2åªä¸ªäºå¡æåºå¼å¸¸ï¼äºå¡0é½ä¼åæ»ãæ°æ®æ·»å ä¼å¤±è´¥ã
è¿ç§æ åµå°±æ¯ï¼
äºå¡0ï¼requiredï¼ {
äºå¡1 ï¼REQUIRES_NEWï¼
äºå¡2
}
æ¤æ¶ã
æ åµaï¼
1ãå¦æåªæ¯äºå¡2åºç°äºå¼å¸¸ï¼é£ä¹äºå¡1ä¼æ交ï¼äºå¡2å å ¥å°äºå¡0ä¸ä¼åæ»ã
2ãå¦æåªæ¯äºå¡1åºç°äºå¼å¸¸ï¼é£ä¹äºå¡1ä¼åæ»ï¼åä¸å±äºå¡0æå¼å¸¸ï¼äºå¡2ä¼å å ¥å°äºå¡0ä¸ï¼è¿æ¶é½ä¼åæ»ã
æ åµbï¼
å¦æäºå¡1ï¼äºå¡2é½æ¯REQUIRES_NEWä¼ æå±æ§ãé£ä¹ç»æå°±æ¯ï¼
1ãå¦æäºå¡1ï¼æåºäºå¼å¸¸ï¼é£ä¹äºå¡2æ¯ä¸ä¼æ§è¡çï¼é£ä¹äºå¡0å¿ ç¶åæ»ã
2ãå¦æäºå¡2ï¼æåºå¼å¸¸ï¼é£ä¹äºå¡1ä¼æ交ï¼è¡¨ä¸ä¼ææ°æ®ãäºå¡2æå¼å¸¸åæ»å¹¶æåºï¼äºå¡0åæ»ã
NESTEDå±æ§å ¶å®å°±æ¯å建äºåæ»ç¹ï¼æå¼å¸¸æ¶ï¼ä¼åæ»å°æå®çåæ»ç¹ã
å¨è¿éè¿ä»£ç æµè¯ï¼åºç°ä¸ç§æ åµæ¯ï¼æ 论äºå¡1ï¼äºå¡2åªä¸ªæå¼å¸¸ï¼æ°æ®é½ä¸ä¼æå ¥æåï¼åå æ¯ï¼ä¸è®ºæ¯äºå¡1è¿æ¯äºå¡2é½ä¼åäºå¡0æåºå¼å¸¸ï¼äºå¡0æè·å°å¼å¸¸åï¼æ§è¡rollback()æ¹æ³ï¼è¿å°±æä½æäºï¼äºå¡çå ¨é¨åæ»ã
å¦ææ³è¦äºå¡1åäºå¡2 æ³è¦æ ¹æ®èªå·±çåæ»ç¹åæ»ï¼é£ä¹äºå¡0å¿ é¡»èªå·±å¤çå¼å¸¸ï¼ä¸è®©springæè·å°è¿ä¸ªå¼å¸¸ï¼é£ä¹å°±æ»¡è¶³äºãæ代ç æ¹æè¿ç§ï¼
Jack大佬æä¾äºï¼ä¼ªä»£ç åææ³ã
æç §Springæºç çäºå¡å¤çé»è¾ï¼ä¼ªä»£ç 大è´ä¸ºï¼
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()方法中,直接调用了重载的opengl鼠标事件源码registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法。在重载的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中,传入了AnnotationAwareAspectJAutoProxyCreator.class对象。
在registerOrEscalateApcAsRequired()方法中,接收到的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新特性教程》和《亿级流量下的分布式限流解决方案》,都是面试必备的资料。
最后,如果你觉得这篇文章对你有帮助,怎么找到app源码别忘了点个赞,给个在看和转发,让更多的人看到,一起学习,一起进步!
è°è°å¯¹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代理对象创建以及调用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调用的是目标方法而非代理对象的方法。
二、gigaget 开发源码代理对象创建及invoke源码分析图
代理创建流程始于@EnableAspectJAutoProxy注解注册的AspectJAutoProxyRegistrar,此注册器在解析import注解时执行registerBeanDefinitions方法。该方法注册了在bean实例化前调用的InstantiationAwareBeanPostProcessor类型的bean后置处理器,此处理器在实例化前解析AOP,非循环依赖在初始化后调用postProcessAfterInitialization()创建动态代理。
匹配Advisor集合:首先筛选Advisor列表,匹配规则涉及类级别和方法级别的筛选,通过Aspect匹配实现。同时,Advisor排序确保调用顺序遵循通知类型。创建代理对象遵循ProxyTargetClass参数与目标类接口的配置,选择JDK或cglib动态代理。
代理方法调用:由于存储的是代理对象,方法调用实际指向代理。exposeProxy = true配置下,代理对象暴露到线程变量中。代理对象执行方法调用遵循责任链模式,按顺序执行前置、目标方法、后置等通知。
张图,剖析 Spring AOP 源码,小白居然也能看懂,大神,请收下我的膝盖!
本文将简要介绍AOP(面向切面编程)的基础知识与使用方法,并深入剖析Spring AOP源码。首先,我们需要理解AOP的基本概念。
1. **基础知识
**1.1 **什么是AOP?
**AOP全称为Aspect Oriented Programming,即面向切面编程。AOP的思想中,周边功能(如性能统计、android源码sdk下载日志记录、事务管理等)被定义为切面,核心功能与切面功能独立开发,然后将两者“编织”在一起,这就是AOP的核心。
AOP能够将与业务无关、却为业务模块共同调用的逻辑封装,减少系统重复代码,降低模块间的耦合度,有利于系统的可扩展性和可维护性。
1.2 **AOP基础概念
**解释较为官方,以下用“方言”解释:AOP包括五种通知分类。
1.3 **AOP简单示例
**创建`Louzai`类,添加`LouzaiAspect`切面,并在`applicationContext.xml`中配置。程序入口处添加`"睡觉"`方法并添加前置和后置通知。接下来,我们将探讨Spring内部如何实现这一过程。
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提供多种增强类型,包括前置、后置、异常、最终和环绕增强。
文章最后建议读者关注学习资源,通过扫描二维码获取更多知识和学习资料。