首先我们看一下@Aspect的简单实例代码
首先到Config类中添加@EnableAspectJAutoProxy注解打开AOP功能
@ComponentScan(basePackages = "com.kennor.test")
@EnableAspectJAutoProxy
public class Config {
}
自定义注解StudyTrainAnnotation用于标识连接点Joinpoint
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface StudyTrainAnnotation {
}
自定义切面StudyTrainAspect类
在切面方法studyTrain中对目标方法进行增强,具体业务逻辑是增加分数。
@Component
@Aspect
public class StudyTrainAspect {
@Pointcut("@annotation(StudyTrainAnnotation)")
public void studyTrainPointcut(){
}
@Around("studyTrainPointcut()")
public Object studyTrain(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("进行考前强化训练,强化训练后初始分数增加30分");
Object[] args = joinPoint.getArgs();
args[0] = (Integer)args[0] + 30;
Integer score = (Integer) joinPoint.proceed(args);
System.out.println("考后老师评分失误,多评10分");
score+=10;
return score;
}
}
增加Student接口
在StudentA和StudentB实现Student接口
在StudentA的examing方法中增加@StudyTrainAnnotation注解,标识StudentA的examing是需要增强的目标对象Target。
然后调用
运行结果如下:
可以看到StudentA考试成绩增加到了90分,而StudentB没有使用AOP所以仍是50分。
为了做对比,看一下StudentB和StudentA的区别
通过Debug可以看到,StudentA的引用实际上是代理对象,然后代理对象的targetSource属性保存着StudentA。接下来我们将分析一下整个流程到底是怎么样的。
接下来我们就着这个实例,分析一下源码,看看Spring底层源码是如何实现的。
首先我们看到Config类上的@EnableAspectJAutoProxy注解
可以看到EnableAspectJAutoProxy使用了@import标签导入了AspectJAutoProxyRegistrar类
而关于@import标签的处理在AnnotationConfigApplicationContext的构造方法中创建的ConfigurationClassPostProcessor中进行的,跟处理@ComponentScan注解一样,具体看下面方法注释的第4点,会将AspectJAutoProxyRegistrar注册到Spring中,这里不再赘述。
@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// 1.处理类上的@Component注解
if (configClass.getmetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
}
// Process any @PropertySource annotations
// 2.处理类上的@PropertySource注解
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getmetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
... ...
}
// Process any @ComponentScan annotations
// 3.处理类上的@ComponentScan注解
Set componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getmetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionevaluator.shouldSkip(sourceClass.getmetadata(), ConfigurationPhase.REGISTER_BEAN)) {
... ...
}
// Process any @import annotations
// 4.处理@import注解
processimports(configClass, sourceClass, getimports(sourceClass), true);
// Process any @importResource annotations
// 5.处理@importResource注解
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getmetadata(), importResource.class);
if (importResource != null) {
... ...
}
// Process individual @Bean methods
// 6.处理@Bean注解
Set beanMethods = retrieveBeanMethodmetadata(sourceClass);
for (Methodmetadata methodmetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodmetadata, configClass));
}
... ...
return null;
}
接着我们看一下AspectJAutoProxyRegistrar
可以看到AspectJAutoProxyRegistrar实现了importBeanDefinitionRegistrar接口,所以registerBeanDefinitions方法会在ApplicationContext的refresh方法中的invokeBeanFactoryPostProcessors里被调用。
在AspectJAutoProxyRegistrar的registerBeanDefinitions方法中主要是往Spring注册了AnnotationAwareAspectJAutoProxyCreator
// AOP的处理入口 // 注册AnnotationAwareAspectJAutoProxyCreator,主要用于处理@AspectJ注解 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
可以看到最终AnnotationAwareAspectJAutoProxyCreator被封装到BeanDefinition注册到Spring中。
而在AnnotationAwareAspectJAutoProxyCreator所继承的父类AbstractAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor接口
其中实现了一个很重要的方法:postProcessAfterInitialization,这里会创建返回Bean对应的代理对象。
通过方法的名称我们也可以知道postProcessAfterInitialization会在Bean初始化完成后调用,这是我们回到Bean的创建方法doCreateBean中,我们在之前的文章有提过此方法中的第5点注释处的方法就是处理生成代理对象的。
接着我们继续看一下initializeBean的具体源码
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
... ...
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 1.调用BeanPostProcessor实现类的postProcessBeforeInitialization方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 2.调用InitializingBean的afterPropertiesSet方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
... ...
if (mbd == null || !mbd.isSynthetic()) {
// 3.调用BeanPostProcessor实现类的postProcessBeforeInitialization方法
// 如果配置了代理,则AbstractAutoProxyCreator会在此处调用,生成代理对象
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
我们可以看到注释第3点处的applyBeanPostProcessorsAfterInitialization方法
最终调用到我们一开始所介绍的AnnotationAwareAspectJAutoProxyCreator父类AbstractAutoProxyCreator的postProcessAfterInitialization方法中
可以看到核心流程在wrapIfNecessary里,具体源码如下:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 判断当前bean的切面标识
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 1.根据当前beanMame对应的bean去扫描匹配bean类中的方法是否有符合Pointcut规则(@Pointcut)的切面方法(@Around、@Before、@After...)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
// 将当前Bean标识为有切面方法
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 2.创建代理对象
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;
}
首先我们看wrapIfNecessary方法中注释第1点处的getAdvicesAndAdvisorsForBean方法的具体代码
继续看findEligibleAdvisors的具体是如何获取Advisor
这里我们继续看一下aspectJAdvisorsBuilder的buildAspectJAdvisors方法
public ListbuildAspectJAdvisors() { List aspectNames = this.aspectBeanNames; if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { List advisors = new ArrayList<>(); aspectNames = new ArrayList<>(); // 获取容器中所有的beanName String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); for (String beanName : beanNames) { if (!isEligibleBean(beanName)) { continue; } // We must be careful not to instantiate beans eagerly as in this case they // would be cached by the Spring container but would not have been weaved. // 获取Class对象 Class> beanType = this.beanFactory.getType(beanName); if (beanType == null) { continue; } // 1.判断类上是否有@Aspect注解 if (this.advisorFactory.isAspect(beanType)) { aspectNames.add(beanName); // 解析封装@Aspect注解信息 Aspectmetadata amd = new Aspectmetadata(beanType, beanName); if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { metadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); // 2.获取所有切面方法封装类Advisor集合 List classAdvisors = this.advisorFactory.getAdvisors(factory); if (this.beanFactory.isSingleton(beanName)) { this.advisorsCache.put(beanName, classAdvisors); } else { this.aspectFactoryCache.put(beanName, factory); } // 3.将Advisor添加到列表中 advisors.addAll(classAdvisors); } else { // Per target or per this. if (this.beanFactory.isSingleton(beanName)) { throw new IllegalArgumentException("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton"); } metadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); this.aspectFactoryCache.put(beanName, factory); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } } this.aspectBeanNames = aspectNames; // 4.返回Advisor列表 return advisors; } } } ... ... return advisors; }
此时我们示例代码中的StudyTrainAspect会通过buildAspectJAdvisors()注释1处的判断,走到注释2处的方法里面。
@Override public ListgetAdvisors(metadataAwareAspectInstanceFactory aspectInstanceFactory) { Class> aspectClass = aspectInstanceFactory.getAspectmetadata().getAspectClass(); String aspectName = aspectInstanceFactory.getAspectmetadata().getAspectName(); validate(aspectClass); // We need to wrap the metadataAwareAspectInstanceFactory with a decorator // so that it will only instantiate once. metadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory); List advisors = new ArrayList<>(); // 1. getAdvisorMethods返回没有@Pointcut注解的方法集合 for (Method method : getAdvisorMethods(aspectClass)) { // 2. 创建Advisor Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName); if (advisor != null) { advisors.add(advisor); } } ... ... return advisors; }
首先我们getAdvisors()注释1处getAdvisorMethods方法
getAdvisorMethods获取到没有@Pointcut的方法,所以method列表中会记录到示例代码StudyTrainAspect的studyTrain方法
接着我们返回getAdvisors()注释2处。
getPointcut方法会去解析studyTrain上的@Around注解的信息。
@Nullable public static A findAnnotation(Method method, @Nullable Class annotationType) { Assert.notNull(method, "Method must not be null"); if (annotationType == null) { return null; } AnnotationCacheKey cacheKey = new AnnotationCacheKey(method, annotationType); A result = (A) findAnnotationCache.get(cacheKey); if (result == null) { Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method); // 从当前方法上寻找annotationType类型的注解信息 result = findAnnotation((AnnotatedElement) resolvedMethod, annotationType); if (result == null) { // 从当前类实现的接口中寻找annotationType类型的注解 result = searchOnInterfaces(method, annotationType, method.getDeclaringClass().getInterfaces()); } // 从父类中寻找annotationType类型的注解信息 Class> clazz = method.getDeclaringClass(); while (result == null) { ... ... } ... ... } return result; }
最后可以看到注释2处将信息封装到AspectJAnnotation中返回到getPointcut方法中,此时getPointcut注释1处获取到的aspectJAnnotation对象如下:
最后再到注释2处创建AspectJexpressionPointcut返回出去。
可以看到AspectJexpressionPointcut保存着示例代码StudyTrainAspect的studyTrain方法@Around注解的pointcut表达式:studyTrainPointcut()。
接着我们看回到getAdvisor方法的注释2处
通过入参我们可以发现这里的InstantiationModelAwarePointcutAdvisorImpl装了示例代码pointcut表达式(studyTrainPointcut())和Advice增强方法(studyTrain())等信息。
接着我们看一下InstantiationModelAwarePointcutAdvisorImpl类
可以看到这个类最终实现了Advisor接口,而且类中有几个重要的属性,我们看一下在构造方法中instantiatedAdvice属性是如何赋值的。
getAdvice具体代码如下
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJexpressionPointcut expressionPointcut,
metadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class> candidateAspectClass = aspectInstanceFactory.getAspectmetadata().getAspectClass();
validate(candidateAspectClass);
// 获取Method方法上的注解
AspectJAnnotation> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
... ...
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
// 忽略@Pointcut注解
return null;
case AtAround:
// 封装@Around注解
// AspectJAroundAdvice实现了MethodInterceptor接口
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
// 封装@Before注解
// AspectJMethodBeforeAdvice实现了MethodBeforeAdvice接口
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
// 封装@After注解
// AspectJAfterAdvice实现了MethodInterceptor接口
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
// 封装@afterReturning注解
// AspectJAfterReturningAdvice实现了AfterReturningAdvice接口
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
// 封装@afterThrowing注解
// AspectJAfterThrowingAdvice实现了MethodInterceptor接口
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
可以看到在getAdvice方法中根据注解封装成对应的Advice,其中封装Around注解和After注解的Advice实现了MethodInterceptor接口,而封装After注解的Before实现的是MethodBeforeAdvice接口。
所以在我们示例代码中StudyTrainAspect中的带有@Around注解的studyTrain方法会被封装成AspectJAroundAdvice对象
接着getAdvisor方法将Advisor返回到buildAspectJAdvisors中,buildAspectJAdvisors再将Advisor保存到列表里继续获取其他Advisor,最后将Advisor列表返回到findEligibleAdvisors。
接着我们继续看findEligibleAdvisors注释第2点处,看看Bean和Advisor是如何匹配,在我们示例代码就是StudentA的examing方法与StudyTrainAspect的studyTrain的匹配过程。
findEligibleAdvisors这块的匹配比较复杂,我们跟着断点大概看一下
上面这个方法中的FuzzyBoolean类会记录匹配结果
这里通过hasAnnotation判断examing方法是否包含StudyTraninAnnotation注解,由于examing是有添加@StudyTraninAnnotation注解的,所以会返回YES
然后将match封装到ShadowMatchImpl中返回出去
最后通过匹配,把Advisor添加到eligibleAdvisors中返回出去
接着回到findEligibleAdvisors方法中
此时就将StudentA匹配到的Advisor返回出去
接着就回到了一开始的wrapIfNecessary中
我们接下来将用注释1处获取到的Advisor用于注释2处创建StudentA的代理对象。
在createProxy方法中可以看到创建了代理工厂proxyFacotry,并且将Advisor添加到代理工厂中,然后通过proxyFacotry获取代理对象。
我们先看一下getProxy中的注释1处创建AOP代理
由于我们的StudentA实现了Student接口,所以采用JDK代理模式,因此会创建一个JDKDynamicAopProxy代理对象返回
而JDKDynamicAopProxy实现了动态代理的关键接口InvocationHandler,因此StudentA代理对象调用接口中的examing方法的时候会调用回此类的invoke方法中,这个我们在后面介绍。
接着我们先回到getProxy方法中的注释第2处,看看getProxy方法
选择JDKDynamicAopProxy对象
可以看到需要代理的接口中就包含了Student接口,接着继续往下走到Proxy.newProxyInstance方法中,接下来就是我们熟悉的动态代理相关的代码了
最后生成动态代理类返回到一开始提到的wrapIfNecessary方法中。
最后返回到doCreateBean方法中,此时exposedObject持有着StudentA的代理对象。
最后doCreateBean将exposedObject返回出去
接着进入到getSingleton中,最终studentA缓存的对象是StudentA的代理对象。
这也就是为什么在示例代码中我们获取到的StudentA是个代理对象的原因。
接着我们在前面分析的时候已经提到,StudentA代理对象调用接口中的examing方法的时候会调用代理对象的invoke方法,也就是JDKDynamicAopProxy的invoke方法。
接着我们看一下在JDKDynamicAopProxy的invoke方法中是如何调用到StudentA的examing方法和StudyTrainAspect的studyTrain方法
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
// 从advised中获取targetSource
// 代理实例就保存在targetSource的target属性中
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
... ...
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
// 获取代理示例
target = targetSource.getTarget();
Class> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 获取符合当前代理示例方法的切面执行链
List
看到注释1处继续调用proceed方法
调用到我们的@Around注解的方法studyTrain的封装类AspectJAroundAdvice的invoke方法,继续进入到AspectJAroundAdvice的invoke方法中
这时就调用到StudyTrainAspect的studyTrain方法中了
然后我们修改参数后调用了joinPoint的proceed方法
再次来到proceed方法中
此时链条已经执行完毕,进入到invokeJoinponit方法中,最后会反射调用到StudentA的examing方法
然后返回到proceed方法中
然后继续返回到StudyTrainAspect的studyTrain方法中的joinPoint.proceed处
然后执行往studyTrain继续往上返回出去
最后执行完毕。



