導讀
本篇主要針對spring aop進行源碼級解說,如有不不到位的地方敬請指出,多謝……
本文大綱如下
- spring aop 使用姿勢
- spring aop 主鏈路概覽
- spring aop 相關概念
- spring aop 源碼解讀
4.1 編程方式解讀
4.2 配置方式解讀
4.3 注解方式解讀 - spring aop不生效的探索
一、Spring AOP 使用姿勢
待被加強的目標類
public interface Sleepable {
void sleep();
void sleep2();
}
public class SleepableImpl implements Sleepable {
@Override
public void sleep() {
System.out.println("睡覺!不休息哪里有力氣學習!");
this.sleep2();
}
@Override
public void sleep2() {
System.out.println("lalala");
}
}
<!-- 定義被代理者 -->
<bean id="sleepable" class="com.youzan.study.spring.aop.SleepableImpl"/>
1.1 編程式
Advice
public class SleepAdvice2 implements MethodBeforeAdvice, AfterReturningAdvice {
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println("睡覺前要脫衣服!");
}
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
System.out.println("起床后要穿衣服!");
}
}
<!--<!–<!–<!– 定義通知內容,也就是切入點執行前后需要做的事情 –>–>–>-->
<bean id="sleepAdvice2" class="com.youzan.study.spring.aop.SleepAdvice2"/>
<!-- 定義切入點位置 -->
<bean id="sleepPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value=".*sleep"/>
</bean>
<!-- 使切入點與通知相關聯,完成切面配置 -->
<bean id="sleepHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="sleepAdvice2"/>
<property name="pointcut" ref="sleepPointcut"/>
</bean>
<!--編程方式啟用 AOP-->
<bean id="sleepableProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 代理的對象,有睡覺能力 -->
<property name="target" ref="sleepable"/>
<!-- 使用切面 -->
<property name="interceptorNames" value="sleepHelperAdvisor"/>
<!-- 代理接口,睡覺接口 -->
<property name="proxyInterfaces" value="com.youzan.study.spring.aop.Sleepable"/>
</bean>
調用姿勢
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("/"+"配置文件地址");
Sleepable sleepable = (Sleepable)context.getBean("sleepableProxy");
sleepable.sleep();
1.2 配置方式
advice同配置方式一致
<!--<!–<!–<!– 定義通知內容,也就是切入點執行前后需要做的事情 –>–>–>-->
<bean id="sleepAdvice2" class="com.youzan.study.spring.aop.SleepAdvice2"/>
<!-- 定義切入點位置 -->
<bean id="sleepPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value=".*sleep"/>
</bean>
<!-- 使切入點與通知相關聯,完成切面配置 -->
<bean id="sleepHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="sleepAdvice2"/>
<property name="pointcut" ref="sleepPointcut"/>
</bean>
<!--配置的形式啟用 AOP-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
調用姿勢
Sleepable sleepable = (Sleepable)context.getBean("sleepable");
sleepable.sleep();
1.3 注解方式
Advice
@Aspect
public class SleepAdvice{
public SleepAdvice(){
}
@Pointcut("execution(* *.sleep*())")
public void sleeppoint(){}
@Before("sleeppoint()")
public void beforeSleep(){
System.out.println("睡覺前要脫衣服!");
}
@AfterReturning("sleeppoint()")
public void afterSleep(){
System.out.println("睡醒了要穿衣服!");
}
@Around("sleeppoint()")
public void aroundLala(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("快點睡覺!!!");
pjp.proceed();
System.out.println("睡著了!!!");
}
}
<!--注解的形式啟用 AOP-->
<aop:aspectj-autoproxy proxy-target-class="false"/>
<!--<!–定義通知內容,也就是切入點執行前后需要做的事情–>-->
<bean id="sleepAdvice" class="com.youzan.study.spring.aop.SleepAdvice"/>
這里先留一個問題,針對注解方式,我們的輸出文本順序是什么?本文結束的時候有答案,讀者可先自己嘗試思考一下。
調用姿勢和配置的方式一樣
二、Spring AOP主鏈路概覽
注解方式和配置方式屬于同類,基于BeanPostProcessor,在被加強類完成實例化之后通過BeanPostProcessor進行加強。
DefaultAdvisorAutoProxyCreator 和 AnnotationAwareAspectJAutoProxyCreator 都屬于BeanPostProcessor,我們看下他們的類圖
三、核心概念
pointCut
切入點,對什么進行加強
advice
如何增強,是具體的增強動作
advisor
通知器,集成 pointCut和advice
spring aop主要有兩種實現方式,一種是jdk的動態代理,另一種是基于cglib。
四、源碼解讀
4.1 編程方式
容器啟動的時候,會將ProxyFactoryBean的實例創建完畢
獲取代理對象
當我們調用的時候
Sleepable sleepable = (Sleepable)context.getBean("sleepableProxy");
spring容器判斷ProxyFactoryBean是否創建完畢,如果創建完畢判斷是否是FacotryBean類型,如果是的話調用 ProxyFactoryBean.getObject(),這塊可以參考IOC容器部分內容,本章節不細講
下面看下ProxyFactoryBean如何getObject()
//ProxyFactoryBean
public Object getObject() throws BeansException {
//初始化Advisor chain
initializeAdvisorChain();
if (isSingleton()) {
//獲取或創建proxy 代理對象
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
- Advisor chain初始化
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
//是否已初始化
if (this.advisorChainInitialized) {
return;
}
//interceptorNames 就是spring里配置的advisor
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
//省略部分代碼
// Materialize interceptor chain from bean names.
for (String name : this.interceptorNames) {
//省略部分代碼
else {
// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
//從spring容器獲取 advisor對象
advice = this.beanFactory.getBean(name);
}
else {
// 非單例場景下創建 advisor對象
advice = new PrototypePlaceholderAdvisor(name);
}
//將advisor加入鏈中
addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
調用鏈路
|--ProxyFactoryBean.initializeAdvisorChain
|----ProxyFactoryBean.addAdvisorOnChainCreation
|------AdvisedSupport.addAdvisor
|--------AdvisedSupport.addAdvisorInternal
最后會把advisor加入到 ProxyFactoryBean的 advisors
(父類AdvisedSupport的屬性 )里面,advisor的順序由用戶在spring里的配置決定。
- 創建Proxy對象
調用鏈路
|--ProxyFactoryBean.getObject
|----ProxyFactoryBean.getSingletonInstance
|------ProxyFactoryBean.createAopProxy
|--------ProxyCreatorSupport.createAopProxy
|----------DefaultAopProxyFactory.createAopProxy
|------ProxyFactoryBean.getProxy
|--------JdkDynamicAopProxy.getProxy (或CglibAopProxy)
如何決策使用jdk還是cglib?
//DefaultAopProxyFactory
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//根據 proxytargetclass或者 optimize 的配置,或者是否有接口來決策使用jdk動態代理或者cglib
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface()) {
return new JdkDynamicAopProxy(config);
}
return CglibProxyFactory.createCglibProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
<!--編程方式啟用 AOP-->
<bean id="sleepableProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 代理的對象,有睡覺能力 -->
<property name="target" ref="sleepable"/>
<!-- 使用切面 -->
<property name="interceptorNames" value="sleepHelperAdvisor"/>
<!-- 代理接口,睡覺接口 -->
<property name="proxyInterfaces" value="com.youzan.study.spring.aop.Sleepable"/>
<!--指定使用cglib-->
<property name="optimize" value="true" />
</bean>
proxy對象的創建和調用,放到下面公共部分解讀
4.2 配置方式
相對于編程式的區別,就是不需要特意指定advisor和待加強對象之前的關系。
該方式的使用需要配置一個BeanPostProcessor即DefaultAdvisorAutoProxyCreator,當待加強類Bean實例化后會進行BeanPostProcessor的加強。
- 加強的入口
AbstractAutowireCapableBeanFactory#initializeBean
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
//省略部分代碼
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//BeanPostProcessor 加強
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//BeanPostProcessor 加強,DefaultAdvisorAutoProxyCreator在這里開始介入
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
- 獲取加強proxy鏈路
|--AbstractAutowireCapableBeanFactory.
applyBeanPostProcessorsAfterInitialization
|----AbstractAutoProxyCreator.postProcessAfterInitialization
|------AbstractAutoProxyCreator.wrapIfNecessary
|--------AbstractAutoProxyCreator.getAdvicesAndAdvisorsForBean
|--------AbstractAutoProxyCreator.createProxy
|----------ProxyFactory.getProxy
|------------DefaultAopProxyFactory.createAopProxy
|--------------JdkDynamicAopProxy.getProxy (或CglibAopProxy)
AbstractAutoProxyCreator.getAdvicesAndAdvisorsForBean 如何尋找待加強類對應的advisors呢?
//AbstractAdvisorAutoProxyCreator
protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {
//獲取當前容器所有的advisors,根據Advisor接口類型進行查找
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//獲取適合當前容器的advisors
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
//對advisor進行排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
- advisor的排序,為什么要排序呢?如果待加強類適配的不僅僅一個advisor,那么誰先誰后呢?這基于OrderComparator進行排序,而它的實現邏輯也是基于advisor的order來的。
public int compare(Object o1, Object o2) {
boolean p1 = (o1 instanceof PriorityOrdered);
boolean p2 = (o2 instanceof PriorityOrdered);
if (p1 && !p2) {
return -1;
}
else if (p2 && !p1) {
return 1;
}
// Direct evaluation instead of Integer.compareTo to avoid unnecessary object creation.
int i1 = getOrder(o1);
int i2 = getOrder(o2);
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
}
- 查找匹配的advisors
//AbstractAdvisorAutoProxyCreator
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
//尋找匹配當前類的advisor
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
//真正的匹配邏輯 在 AopUtils
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
//判斷類是否匹配
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
//獲取pointcut 的方法匹配器
MethodMatcher methodMatcher = pc.getMethodMatcher();
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class> classes = new LinkedHashSet<Class>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class<?> clazz : classes) {
//讀取待加強類所有的方法,查看是否有匹配上的
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
如果沒有找到匹配的advisor,那么認為該類不需要加強,直接返回原生的bean實例,反之走創建proxy的鏈路。
//AbstractAutoProxyCreator
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.containsKey(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//判斷如果是advisor或者advice類就加入到advisedBeans中,value=false,表示這些bean不需要進行proxy后續邏輯
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
//查找是否有匹配的advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//創建 proxy對象
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
//標記該類不需要加強,并返回普通的bean實例
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
4.3 注解方式
注解方式相比前兩種方式更為輕量,注解方式和配置方式相比編程方式對待加強類零侵入、零耦合。
注解方式原理與配置方式類似,都是基于BeanPostProcessor進行bean實例加強。但是不同的是注解方式由spring aop模塊自動向容器加入AnnotationAwareAspectJAutoProxyCreator
BeanPostProcessor ,另外advisor也是程序基于代碼注解自動提取和組裝。
使用注解
<aop:aspectj-autoproxy proxy-target-class="false"/>
相比<bean>標簽,對應的解析類也是不一樣的。spring aop模塊下的spring.handlers 里指定 解析類 AopNamespaceHandler
//AopNamespaceHandler
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
我們使用的 aspectj-autoproxy
剛好對應 AspectJAutoProxyBeanDefinitionParser。
容器注冊AnnotationAwareAspectJAutoProxyCreator BeanPostProcessor
//AspectJAutoProxyBeanDefinitionParser
public BeanDefinition parse(Element element, ParserContext parserContext) {
//注冊 AspectJAnnotationAutoProxyCreator
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
//如果有子節點進行子節點處理,暫未用到,暫時忽略
extendBeanDefinition(element, parserContext);
return null;
}
//AopNamespaceUtils
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
//生成AspectJAnnotationAutoProxyCreator 的beanDefinition信息并注冊到容器中,
//name=org.springframework.aop.config.internalAutoProxyCreator
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
//對 aspectj-autoproxy 的屬性進行組裝,比如proxy-target-class
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
接著在容器啟動的過程中 registerBeanPostProcessors() 進行實例化。
提取advisors
獲取加強proxy鏈路和配置方式一致,不同的在于注解方式獲取advisors是代碼自動提取的,AnnotationAwareAspectJAutoProxyCreator把AbstractAdvisorAutoProxyCreator的findCandidateAdvisors
覆蓋了,有了自己的實現邏輯
//AnnotationAwareAspectJAutoProxyCreator
protected List<Advisor> findCandidateAdvisors() {
//調用父類的方法,檢索容器中所有的advisor
List<Advisor> advisors = super.findCandidateAdvisors();
//構建加AspectJ注解的advisor
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
return advisors;
}
根據加@Aspect注解的bean生成advisors的調用鏈路
|--BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors
|----ReflectiveAspectJAdvisorFactory.getAdvisors
|------ReflectiveAspectJAdvisorFactory.getAdvisor
|--------new InstantiationModelAwarePointcutAdvisorImpl()
|----------InstantiationModelAwarePointcutAdvisorImpl.instantiateAdvice
|------------ReflectiveAspectJAdvisorFactory.getAdvice
//BeanFactoryAspectJAdvisorsBuilder
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = null;
//省略一大段代碼,代碼篇幅較長,可以認為 它把spring容器中的bean都拿了出來,
//然后判斷是否添加了 @Aspect 注解
//根據提取出來的 @Aspect 進行進一步的組裝,獲取到具體的Advisor并添加到 advisors中返回
List<Advisor> advisors = new LinkedList<Advisor>();
for (String aspectName : aspectNames) {
//從緩存中讀取已經生成的 advisors
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
//具體生成advisors 的邏輯
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
//ReflectiveAspectJAdvisorFactory
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
final String aspectName = maaif.getAspectMetadata().getAspectName();
validate(aspectClass);
final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(maaif);
final List<Advisor> advisors = new LinkedList<Advisor>();
//getAdvisorMethods(aspectClass) 會找到所有加注解的方法
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// 省略部分代碼,平時沒有用到這些場景,這里就不解讀了
return advisors;
}
getAdvisorMethods方法,會把所有帶有注解的方法給提取出來,提取后會對方法進行排序,因為在后面設置advice order的時候有一個聲明順序,會起到一定的優先級影響。
//ReflectiveAspectJAdvisorFactory
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new LinkedList<Method>();
ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException {
// Exclude pointcuts
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
}
});
//對方法進行排序
Collections.sort(methods, METHOD_COMPARATOR);
return methods;
}
方法的排序規則
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
按照上面的注解順序進行排序,如果不屬于上面的注解類型,排序統一為方法總數量。
ReflectiveAspectJAdvisorFactory.getAdvisor
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif,
int declarationOrderInAspect, String aspectName) {
validate(aif.getAspectMetadata().getAspectClass());
//提取 pointcut,如果為空則返回null
AspectJExpressionPointcut ajexp =
getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
if (ajexp == null) {
return null;
}
//生成InstantiationModelAwarePointcutAdvisorImpl advisor,
//advice=aif(可以認為是當前加了@Aspect的advice類), pointcut 就是根據注解提取出來的
return new InstantiationModelAwarePointcutAdvisorImpl(
this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
}
getAdvice的邏輯
//ReflectiveAspectJAdvisorFactory
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp,
MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) {
Class<?> candidateAspectClass = aif.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
//獲取當前方法注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// Check 是否是 AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
//省略部分代碼
AbstractAspectJAdvice springAdvice;
//不同的注解類型,不同的advice
switch (aspectJAnnotation.getAnnotationType()) {
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
//省略部分代碼
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
//省略部分代碼
break;
case AtAround:
springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
break;
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method " + candidateAdviceMethod);
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
//設置advice的 聲明順序,當advice order 順序一樣的時候,該排序會有一定的影響
springAdvice.setDeclarationOrder(declarationOrderInAspect);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
幾個advice類型的類圖我們看下
Advisor 優先級
Advisor的優先級邏輯,配置方式和注解方式一致。
我們的advisor已經生成完畢,advisor的優先級排序邏輯入口在AspectJAwareAdvisorAutoProxyCreator.sortAdvisors。
Advisor排序鏈路
|--AspectJAwareAdvisorAutoProxyCreator.sortAdvisors
|----PartialOrder.sort
|------PartialOrder.addNewPartialComparable
|--------PartialOrder.addDirectedLinks
|----------AspectJPrecedenceComparator.compare
|------------AspectJPrecedenceComparator.comparePrecedenceWithinAspect
排序中最為關鍵的點
PartialOrder.addNewPartialComparable 這一步,將待排序的對象包裝成PartialOrder.SortObject對象,這個對象有三個屬性
//advisor holder
PartialComparable object;
//比當前advisor order 小的Advisors
List<SortObject> smallerObjects = new LinkedList<SortObject>();
//比當前advisor order 大的Advisors
List<SortObject> biggerObjects = new LinkedList<SortObject>();
PartialOrder.sort就是針對上面處理之后的SortObjects進行排序。
排序規則首先獲取Advisor的order,小的優先級最高,如果order一樣則取 declareOrder也就前面說的聲明順序,這里需要注意的是,聲明順序并發是和我們代碼里的屬性一致,它是經過排序的,排序邏輯向上可以找下。
當Advisor的order一樣后,排序會進入到下面的邏輯
AspectJPrecedenceComparator.comparePrecedenceWithinAspect
private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) {
//兩個Advisor 是否其中一個或者全部都是 after類型的Advisor
boolean oneOrOtherIsAfterAdvice =
(AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2));
int adviceDeclarationOrderDelta = getAspectDeclarationOrder(advisor1) - getAspectDeclarationOrder(advisor2);
if (oneOrOtherIsAfterAdvice) {
//如果其中一個或者全部是 after類型的,先聲明的優先級反而低
if (adviceDeclarationOrderDelta < 0) {
return LOWER_PRECEDENCE;
}
else if (adviceDeclarationOrderDelta == 0) {
return SAME_PRECEDENCE;
}
else {
return HIGHER_PRECEDENCE;
}
}
else {
//如果不是after類型的,哪個方法先聲明則擁有更高的優先級。
if (adviceDeclarationOrderDelta < 0) {
return HIGHER_PRECEDENCE;
}
else if (adviceDeclarationOrderDelta == 0) {
return SAME_PRECEDENCE;
}
else {
return LOWER_PRECEDENCE;
}
}
}
4.4 proxy調用解讀
本小節,三種aop使用方式的proxy創建和調用邏輯相同,所以放到一起進行講解
創建proxy創建
//JdkDynamicAopProxy
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//原聲帶jdk創建proxy的api調用
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
使用的是原生的jdk 動態代理api
proxy方法調用
當我們獲得到proxy之后,然后調用業務方法的時候,執行鏈路最終到了 proxy的invoke方法。
調用鏈路
|--JdkDynamicAopProxy.invoke
|----AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice
|------DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice
|--------MethodBeforeAdviceAdapter.getInterceptor
|--------AfterReturningAdviceAdapter.getInterceptor
|----ReflectiveMethodInvocation.proceed
|------MethodBeforeAdviceInterceptor.invoke
|------AfterReturningAdviceInterceptor.invoke
JdkDynamicAopProxy.invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
//省略部分代碼
//獲取當前執行對象匹配的advice chain
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
//如果chain為空,直接執行targetd fangf
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//開始執行邏輯,并返回結果
retVal = invocation.proceed();
}
//省略部分代碼
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
獲取當前方法的advice鏈,邏輯入口
AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice
具體實現在DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class targetClass) {
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
//循環當前targetClass的advisors
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
//獲取當前advisor的pointcut
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
//根據advisor獲取interceptors
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
//判斷當前方法是否匹配當前advisor的pointcut
if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
if (mm.isRuntime()) {
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
//將當前advisor對應interceptors 加入到 interceptorList
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
//如果不是上述兩種類型,則作為Interceptor 直接加入 比如 ExposeInvocationInterceptor
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
如何根據advisor獲取interceptors ?
//DefaultAdvisorAdapterRegistry
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
adapters 在DefaultAdvisorAdapterRegistry實例化的時候完成裝配
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
這些adapters判斷是否支持當前advisor的advice,我們以MethodBeforeAdviceAdapter 為例
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
getInterceptor邏輯
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
現在我們獲取到了當前方法匹配的MethodInterceptor,最后也就是 MethodInterceptor chain。接下來看下具體的執行邏輯ReflectiveMethodInvocation.proceed()
public Object proceed() throws Throwable {
//interceptors chain執行完畢,則開始執行target的method
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//MethodInterceptor chain每執行一個,currentInterceptorIndex + 1
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
//省略代碼,本篇使用的樣例,不會走到該邏輯
}
else {
// 按照 MethodInterceptor chain執行邏輯
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
jdk的動態代理就介紹到這了,cglib方式的先不介紹了,當然本篇也并非面面俱到,如果有朋友對本篇沒有提及部分感興趣的話,可以按照這個思路自己探索一番。
有興趣的朋友可以自行研究下,這里就不介紹了。
五、Spring AOP 不生效的探索
在使用spring aop的時候,可能我們會時不時的出現aop不生效的問題,最常見的莫過于spring的事務,為什么有時候不生效呢?
通過上面的幾個章節,這個圖大家不難理解,
前提
我們有 method A 和 methodB的兩個切面
case1:調用 C.A, 方法A切面生效
case2: 調用C.B, 方法B切面生效
case3: 調用C.A, C.A調用C.B,方法A切面生效, 方法B切面失效。
通過圖中表述,當方法A切面生效的時候,調用到 目標類C的B方法,這時候調用B的對象是目標類C而非 代理對象,所以對方法B的加強會不起作用
文章開頭的問題答案如下:
輸出內容
快點睡覺!!!
睡覺前要脫衣服!
睡覺!不休息哪里有力氣學習!
lalala
睡著了!!!
睡醒了要穿衣服!
系列文章
spring源碼探索(0)-IOC容器-架構設計
spring源碼探索(1)-IOC容器-Resource
spring源碼探索(2)-IOC容器-BeanDefinition加載與注冊
spring源碼探索(3)-IOC容器-Bean的一生
spring源碼探索(4)-AOP實現原理