源码分析基于spring 4.3.x
这是我第三次看spring的源码了
思路清晰了很多,也对博客内容做了很多修改。
一个小栗子
定义一个服务接口
package com.spring.start.service;
public interface IBlogService {
int getBlogCount();
}
接口实现类
package com.spring.start.service;
public class BlogService implements IBlogService {
@Override
public int getBlogCount() {
int count = 123;
System.out.println("blog count : " + count);
return count;
}
}
定义一个切面(Aspect)
@Aspect
public class LogAspect {
@Around("execution(public * com.spring.start..*.*.*(..))")
public Object methodAroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("log1 : start method");
Object result = joinPoint.proceed(joinPoint.getArgs());
System.out.println("log2 : end method");
return result;
}
@Around("execution(public * com.spring.start..*.*.*(..))")
public Object methodAroundLog2(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("log2 : start method");
Object result = joinPoint.proceed(joinPoint.getArgs());
System.out.println("log2 : end method");
return result;
}
}
切面类中定义了两个通知(Advice)methodAroundLog和methodAroundLog2,对com.spring.start下所有子包中所有类的所有pubic方法进行拦截,并输出写简单的log信息。
来看看配置文件application.xml
<!-- 开启aop -->
<aop:aspectj-autoproxy/>
<!-- 定义切面 -->
<bean id="logAspect" class="com.spring.start.aop.LogAspect"></bean>
<!-- 定义service -->
<bean id="blogService" class="com.spring.start.service.BlogService"></bean>
测试方法
public static void main(String[] args) {
ApplicationContext beanFactory = new ClassPathXmlApplicationContext("application.xml");
IBlogService blogService = beanFactory.getBean("blogService", IBlogService.class);
blogService.getBlogCount();
}
输出结果:
log1 : start method
log2 : start method
blog count : 123
log2 : end method
log2 : end method
可以看到aop已成功拦截到了方法,并输出了对应的log。
一开始,先明确几个概念
aspect:切面,一个切面可以包括多个切入点和通知,而且标签内部的通知和切入点定义是无序的
advice:通知,表示一个method执行前或执行后的动作。上面栗子中定义了两个环绕通知
pointcut:切入点,表示根据method的名字或者正则表达式去拦截一个method。
advisor:只有一个通知和一个切入点的切面,可以看做一种特殊的aspect。
开始阅读源码前,我比较关注的几个问题:
-
<aop:aspectj-autoproxy/>
的作用 - spring如何根据Aspect注解创建切面
- spring如何根据切面信息创建代理对象
- 上面定义的两个通知methodAroundLog和methodAroundLog2,spring是如何进行链式调用的
<aop:aspectj-autoproxy/>
的作用
aspectj-autoproxy是spring自定义的标签。我们知道,在spring中自定义标签,需要编写一个继承于NamespaceHandlerSupport的类来实现标签解析工作。
在spring源码中搜索一下,就可以发现aspectj-autoproxy的解析类是AopNamespaceHandler:
public void init() {
this.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
this.registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
而AspectJAutoProxyBeanDefinitionParser类负责对aspectj-autoproxy标签进行解析:
public BeanDefinition parse(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
return null;
}
这里AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary 会调用到AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
registerOrEscalateApcAsRequired就是把AnnotationAwareAspectJAutoProxyCreator注入到spring上下文环境中,
。
AnnotationAwareAspectJAutoProxyCreator是一个关键的类,继承了BeanPostProcessor接口,它负责创建切面。
创建advisor
来看看AbstractAutoProxyCreator.postProcessAfterInitialization
public Object postProcessAfterInitialization(Object bean, String beanName) ... {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
主要逻辑在wrapIfNecessary:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
...
// 创建Advices和Advisors
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理对象
Object proxy = createProxy(bean.getClass(),
beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
getAdvicesAndAdvisorsForBean正是提供给子类创建通知的方法,该方法会调用子类AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean,再调用的它的findEligibleAdvisors方法
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 创建Advisors
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 过滤Advisors
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 扩充
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
这是一个非常重要的方法,实现了几个关键步骤
- findCandidateAdvisors 查找Advisors(第一次会创建)
- findAdvisorsThatCanApply 根据目标bean的class过滤一部分的Advisors
- extendAdvisors 扩充Advisors,spring会根据需要添加一些内部的Advisors
- sortAdvisors 对Advisors排序
findCandidateAdvisors 查找Advisors
findCandidateAdvisors方法负责找到所有的Advisors,该方法会调用到子类AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
// 添加父类的advisors
List<Advisor> advisors = super.findCandidateAdvisors();
// 1-aspectJAdvisorsBuilder.buildAspectJAdvisors
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
return advisors;
}
1-aspectJAdvisorsBuilder.buildAspectJAdvisors是创建Advisor的关键,来看看BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
// 获取所以的bean
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
Class<?> beanType = this.beanFactory.getType(beanName);
// 如果有Aspect注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
// 获取Aspect信息
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 创建AspectInstanceFactory
MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 2-advisorFactory.getAdvisors
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
} else {
...
}
}
}
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
// 查询缓存 添加到结果
...
return advisors;
}
PerClauseKind是aspect的初始化模式,这里只展示了SINGLETON模式的创建, 可以参考 aspect api
这里可以看到一个简单的单例模式,如果当前的aspectBeanNames为null,会创建Advisors,并保存在advisorsCache中,以后每次都从advisorsCache取出advisors。
可以看到,如果一个类有Aspect注解,就会创建AspectInstanceFactory,并通过AspectJAdvisorFactory创建Advisors
而2-advisorFactory.getAdvisors将会调用到ReflectiveAspectJAdvisorFactory.getAdvisors
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 切面类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// 使用装饰器LazySingletonAspectInstanceFactoryDecorator保证MetadataAwareAspectInstanceFactory只创建一次
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new LinkedList<Advisor>();
for (Method method : getAdvisorMethods(aspectClass)) {
// 创建Advisor
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
...
return advisors;
}
getAdvisorMethods获取所有没有Pointcut注解的方法,有Pointcut注解的方法不可能是Advisor。
// 创建Advisor
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
...
// 获取切入点Pointcut
AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 创建Advisor,Advisor中包含了pointcut和adviceMethod
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
这里创建了InstantiationModelAwarePointcutAdvisorImpl(Advisor),该类中有拦截类declaringClass,拦截方法aspectJAdviceMethod等信息,最重要的是declaredPointcut(Pointcut)和instantiatedAdvice(Advice)。
先看看切入点Pointcut的创建
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 获取该方法的Before, Around, After, AfterReturning, AfterThrowing, Pointcut注解
AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 生成AspectJExpressionPointcut,该类Expression属性记录了pointcut表达式
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
ajexp.setBeanFactory(this.beanFactory);
return ajexp;
}
Advice的创建需查看InstantiationModelAwarePointcutAdvisorImpl构造方法:
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
...
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
...
}
else {
this.pointcut = this.declaredPointcut;
this.lazy = false;
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
instantiateAdvice调用了ReflectiveAspectJAdvisorFactory.getAdvice
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 获取拦截类
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
// 获取拦截方法上的注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
...
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
// pointcut注解不处理
return null;
...
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
}
...
return springAdvice;
}
这里针对Around/Before/After/AfterReturning/AfterThrowing创建了对应的Advice。
findAdvisorsThatCanApply 过滤Advisors
findAdvisorsThatCanApply方法,会过滤部分的Advisors
这里会检查目标bean的class和class中是否有方法可以匹配Advisor,如果没有则过滤。代码比较繁琐,不展开了。
extendAdvisors(eligibleAdvisors) 扩充Advisors
看看AspectJAwareAdvisorAutoProxyCreator.extendAdvisors
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not required
if (!advisors.isEmpty()) {
...
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
// 添加ExposeInvocationInterceptor
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
spring会在advisors 列表开始位置添加ExposeInvocationInterceptor。
创建代理对象
我们知道,spring通过动态代理类实现aop,有jdk动态代理和cglib两种方法。
如果要使用jdk动态代理,被代理类必须实现一个接口。
为了避免在这里额外介绍cglib,我在上面的小栗子中让spring生成的BlogService实现了一个接口,这样我们来看一下jdk动态代理如何实现aop。
这里来看看代理对象的创建过程AbstractAutoProxyCreator.createProxy(第三个参数就是Advices信息)
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 存储Advisor
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
buildAdvisors只是做一些检查,转换处理,如将Advices转换成Advisor。
proxyFactory.addAdvisor
这里将Advisor添加到proxyFactory中,proxyFactory类似于一个上下文,存放着Advisor。
proxyFactory.getProxy到调用父类ProxyCreatorSupport.createAopProxy
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 3-createAopProxy
return getAopProxyFactory().createAopProxy(this);
}
3-createAopProxy中参数是this,proxyFactory将自身作为参数,调用DefaultAopProxyFactory.createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
...
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
可以看到,spring会根据用户配置和目标bean是否有实现接口,来决定使用JdkDynamicAopProxy或ObjenesisCglibAopProxy
来看看JdkDynamicAopProxy.getProxy
public Object getProxy(ClassLoader classLoader) {
...
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 构建代理对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
注意:Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)
第三个参数是JdkDynamicAopProxy.this,JdkDynamicAopProxy实现了InvocationHandler。
链式调用
JdkDynamicAopProxy实现了InvocationHandler,看一下关键的invoke方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取所有拦截器
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 获取拦截链
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 4-调用拦截链
retVal = invocation.proceed();
}
this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)
获取拦截器链,
它会从缓存中查询,缓存没有时通过DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice会创建调用链
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, Class<?> targetClass) {
...
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 检查class是否匹配
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
// 检查method 是否匹配
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
// 运行时检查
if (mm.isRuntime()) {
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
}
return interceptorList;
}
这里通过poingcut检查是否能使用Advice,这部分不深入。
registry.getInterceptors(advisor)
将Advice转化为MethodInterceptor方法拦截器,DefaultAdvisorAdapterRegistry.getInterceptors:
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()]);
}
DefaultAdvisorAdapterRegistry.adapters有三个
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
它们会将MethodBeforeAdvice,AfterReturningAdvice,ThrowsAdvice转化为MethodInterceptor(他们没有实现MethodInterceptor接口,其他Advice都实现了MethodInterceptor接口)
回到4-调用拦截链,ReflectiveMethodInvocation.proceed
public Object proceed() throws Throwable {
// 是否到拦截器链尾了
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获取下一个拦截器,currentInterceptorIndex初始值是-1
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 是否为动态拦截器
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
...
}
else {
// 直接调用
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
可以看到,proceed方法会获取下一个拦截器,并调用它们的invoke方法。
注意,invoke会将ReflectiveMethodInvocation自身作为参数。
调用链以ExposeInvocationInterceptor开头,ExposeInvocationInterceptor只是简单的配置和恢复上下文
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
// 设置上下文
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation); // 恢复上下文
}
}
mi.proceed()
会重新调用到ReflectiveMethodInvocation.proceed(),然后调用到下一个拦截器。
看看AspectJAroundAdvice的实现
public Object invoke(MethodInvocation mi) throws Throwable {
...
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
// MethodInvocation转化为ProceedingJoin
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
return invokeAdviceMethod(pjp, jpm, null, null);
}
protected Object invokeAdviceMethod(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable t) throws Throwable {
// argBinding绑定参数
return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}
protected Object[] argBinding(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable ex) {
...
int numBound = 0;
if (this.joinPointArgumentIndex != -1) {
adviceInvocationArgs[this.joinPointArgumentIndex] = jp;
}
...
return adviceInvocationArgs;
}
argBinding负责绑定参数,会把JoinPoint作为通知方法的第一个参数。
invokeAdviceMethodWithGivenArgs会调用到aspectJAdviceMethod.invoke,就是执行Around通知。
在环绕通知中
@Around("...")
public Object methodAroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = joinPoint.proceed(joinPoint.getArgs());
return result;
}
由于第一个参数就是JoinPoint,所以joinPoint.proceed(joinPoint.getArgs());`就可以调用下一个拦截器,这样才能继续调用拦截器链。
Before通知会调用MethodBeforeAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable {
// 调用before通知
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
// 继续调用拦截器链
return mi.proceed();
}
After通知会调用AspectJAfterThrowingAdvice
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed(); // 先调用拦截器链
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
// 调用after通知
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
到这里,spring aop的源码解析就完成了。
这部分还是挺复杂的,需要耐心点看源码。
网友评论