1.入口
- spring版本:5.3.x
- AOP基本概念及使用
1.1 通过注解的方式开启aop功能
在一个配置类上使用@EnableAspectJAutoProxy
注解,开启AOP功能。
java
@EnableAspectJAutoProxy
@Configuration
public class AppConfig {}
我们看下@EnableAspectJAutoProxy
的代码:
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
我们看到在这个注解中,它引入了@Import(AspectJAutoProxyRegistrar.class)
类,通过类名可以判断,这个类是用来注册AspectJ代理。然后我们再看下该类的代码:
java
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 我们主要关心这行代码
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// 剩余的代码都是一些属性赋值,暂时不关心
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
再进入AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)
方法:
java
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) { // 又调用了另外一个方法,顺着再看
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 就是这里了,注册了一个类到spring容器中
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
我们看到最终其实调用了registerOrEscalateApcAsRequired()
方法,并将AnnotationAwareAspectJAutoProxyCreator.class
作为一个入参传入,看下该方法:
可以看到,最终就是将AnnotationAwareAspectJAutoProxyCreator.class
注册到spring容器中,该类就是AOP的入口类了,细节稍后细谈。
1.2通过配置xml的方式开启aop功能
在配置文件中添加如下配置,开启AOP功能:
xml
<!-- 启用aop -->
<aop:aspectj-autoproxy />
该标签,不是spring的默认标签,属于自定义标签。在配置文件的头声明中肯定有引入aop xml的校验文件: 然后在spring-aop的jar包中,有一个spring.handlers文件,通过上面的头声明,可以找到<aop:aspectj-autoproxy />
标签的解析类:
xml
http://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
找到该类后,进入该类AopNamespaceHandler
:
java
public class AopNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
// 主要看这行代码,就是我们xml中声明的标签
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
我们主要看aspectj-autoproxy
标签的注册逻辑,它注册了AspectJAutoProxyBeanDefinitionParser
解析类。进入该类,主要看parse()
方法: 是不是和"注解"方式开启AOP有点像了。再进入该方法: 这里它调用了AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary()
方法。和前面"注解"的逻辑就都一样了,就是将AnnotationAwareAspectJAutoProxyCreator
注册到spring容器中。
1.3 初识入口类
从前两点,知道了AnnotationAwareAspectJAutoProxyCreator
就是aop的入口类,先看一下他的继承结构:
可以看到该类实现了SmartInstantiationAwareBeanPostProcessor
,它是一个BeanPostProcessor
,也就是说在bean的初始化过程中,它是可以编辑、修改bean的。AOP初始化也就是从这里开始的:BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName)
2.AOP源码之旅
先导:几个重要、关键类:
- 个人经验,这一小节不要一开始就试图死记硬背,记住类结构。开始有个印象即可,后面看源码,理解源码逻辑的同时,再结合起来看(双屏真香~_~),边理解、边记忆,这样当你看懂源码的时候,这些类结构也记得7788了。
- 在spring中,Advisor是持有增强(advice)和切点(pointCut)的对象:
- Advisor的继承结构:
- 几种增强类型的类结构:
- 连接点(个人理解,组合调用advice,然后调用目标方法,起"连接"作用。即连接"增强"和"目标方法")结构:
2.1 AOP-获取"增强"
从前一章节,已经知晓入口类就是AnnotationAwareAspectJAutoProxyCreator
,它实现了BeanPostProcessor
接口。在spring初始化bean的流程中,就会调用其postProcessAfterInitialization()
方法,该方法就是aop的入口了。于是乎,我们就从AnnotationAwareAspectJAutoProxyCreator
类的该方法开始,它在其父类AbstractAutoProxyCreator
中实现了该方法:
java
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 根据给定bean的class和name构建一个key。格式:beanName,若是beanFactory加一个前缀&
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 将需要增强的类,装饰成代理类
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
进入wrapIfNecessary()
方法:
java
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 已经处理过,则直接返回
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 特殊类、指定的bean、已经创建代理的bean 无需"增强"
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 基础设施类(就是关于几个Advices、Pointcut的类) 或者 指定bean 不处理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)){
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 获取适合当前bean的增强:返回的是List<Advisor>
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()
方法,获取增强。然后再通过createProxy()
方法创建代理对象。我们先看获取增强的逻辑:
java
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
该方法是在父类AbstractAdvisorAutoProxyCreator
中实现,就只调用了findEligibleAdvisors()
方法,进入该方法,一探究竟:
java
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 在spring容器中寻找所有的advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 筛选适合当前bean的advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors); // 扩展接口
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors); // 排序(根据Order注解来的)
}
return eligibleAdvisors;
}
在findEligibleAdvisors()
方法中,它先是查找spring容器中所有"增强",然后再筛选符合当前bean的"增强"。我们先看findCandidateAdvisors()
查找所有增强的方法,因为我们注入容器的实例对象是AnnotationAwareAspectJAutoProxyCreator
,所以调用的是该类的此方法:
java
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 根据父类规则,获取其所有advisor(父类加载的是配置文件中声明的AOP,即实现了 Advisor 的类)
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
// 寻找基于注解@Aspect的切面
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
可以看到该方法先调用了父类AbstractAdvisorAutoProxyCreator
同名方法获取增强,先看一下父类获取增强的逻辑:
java
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
父类是利用一个辅助类BeanFactoryAdvisorRetrievalHelper
来获取增强,进入该方法:
java
public List<Advisor> findAdvisorBeans() {
// 判断缓存中是否已经有advisor
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 获取容器中所有Advisor的beanName。此时容器中的advisor都是通过xml声明的。
// 通过注解声明的还没加载进来,也不会实现Advisor接口
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) { // 默认返回true,可以覆盖方法
if (this.beanFactory.isCurrentlyInCreation(name)) { // 过滤正在创建中的bean
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
// 直接从容器中获取Advisor
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
}
}
throw ex;
}
}
}
}
return advisors;
}
这里获取增强的逻辑比较简单,对照着写的注释理解,一目了然。从父类获取完增强后,然后我们返回AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors()
方法继续看子类获取增强的逻辑this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
进入该方法:
java
/**
* 返回所有添加了Aspect注解的bean,并返回advice方法
*/
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) { // 缓存中没有,才重新加载
synchronized (this) {
aspectNames = this.aspectBeanNames; // 单例双重检测
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
/* 获取容器中所有的beanName */
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 循环beanName
for (String beanName : beanNames) {
// 不合法的bean则略过,由子类定义规则,默认返回true
if (!isEligibleBean(beanName)) {
continue;
}
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
// 是否存在Aspect注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// 切面是单例模式
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 解析标记AspectJ注解类中的 增强方法
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
// 若bean是单例,则直接缓存增强
this.advisorsCache.put(beanName, classAdvisors);
}
else {
// 若bean不是单例,每次都要新获取,则缓存工厂类
this.aspectFactoryCache.put(beanName, factory);
}
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;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
// 走缓存获取增强
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
这个方法的代码看着有点多,它是用于解析基于@Aspect
注解的切面,主要流程如下:
- 判断缓存,是否已经加载过基于
@Aspect
注解的切面。若存在缓存,则直接从缓存中取增强。 - 缓存不存在,则获取spring IOC容器中所有的beanName。
- 循环所有beanName,判断对应的类是否存在
@Aspect
注解。 - 存在
@Aspect
注解,则解析其声明的增强、切点,然后缓存。 其主要流程,并不复杂。在这个方法中,我们重点学习解析增强的逻辑:
java
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 解析标记了AspectJ注解的类,获取增强
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
可以看到,它首先用beanFactory
和beanName
构建了一个MetadataAwareAspectInstanceFactory
对象,然后将其作为参数,调用了AspectJAdvisorFactory.getAdvisors()
方法,真正实现该方法的是其子类ReflectiveAspectJAdvisorFactory
。我们直接看ReflectiveAspectJAdvisorFactory.getAdvisors()
:
java
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
/* 获取标记为 AspectJ 的class */
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
/* 获取标记为 AspectJ 的class name */
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
/* 对标记为 AspectJ 的类进行基本的验证 */
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 获取本类及其父类的所有方法(排除了@point方法、抽象方法),并循环
for (Method method : getAdvisorMethods(aspectClass)) {
// 构建增强
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// 如果寻找的增强器不为空而且又配置了增强延迟初始化,那么需要加入同步实例化增强器
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
// DeclareParents 注解作用:用来"给被代理对象添加一些方法"
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
这里我们先看获取类所有方法的逻辑getAdvisorMethods(aspectClass)
:
java
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
List<Method> methods = new ArrayList<>();
// 获取类(父类)的所有方法,排除了@Pointcut注解的方法
ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
if (methods.size() > 1) {
methods.sort(adviceMethodComparator); // 排序
}
return methods;
}
该方法,主要就是获取类的所有方法,然后对方法进行排序。我们关注一下排序的逻辑,调用的是List自带的sort()
方法,传入一个Comparator
对象,关键是这个Comparator
对象:
java
private static final Comparator<Method> adviceMethodComparator;
static {
// 按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class的顺序排序
Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
new InstanceComparator<>(Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
(Converter<Method, Annotation>) method -> {
AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (ann != null ? ann.getAnnotation() : null);
});
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
}
在这里,将方法按"增强"的类型,排了一下序,这里就是对"增强"进行了第一次排序。 然后我们返回getAdvisors()
方法,接着看构建增强的方法getAdvisor()
:
java
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect, String aspectName) {
// 对切面类,进行基础验证
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 获取切点信息
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod,aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 根据切点信息,生成advisor
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
获取切点信息getPointCut()
方法主要是解析注解上的信息(增强类型、切点表达式等),封装成AspectJExpressionPointcut
对象,没有特殊的逻辑。这里我们主要看下返回实例InstantiationModelAwarePointcutAdvisorImpl
对象(它是advisor的子类)的构造过程:
java
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut, Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
// 是否延迟加载
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it's not a dynamic pointcut, it may be optimized out // by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// A singleton aspect.
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 实例化advice对象,会根据不通的环绕方式,封装成不同的advice
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
构造函数中主要是给成员属性赋值,主要看下instantiatedAdvice
对象的赋值:
java
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
继续进入this.aspectJAdvisorFactory.getAdvice()
方法:
java
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;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
// 根据不同的注解类型封装不同的advice
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
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;
}
在该方法中可以看到根据增强的类型不通,将增强分别注册成了:AspectJAroundAdvice、AspectJAfterAdvice、 AspectJMethodBeforeAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice
.另外这里我们需要关注下springAdvice.calculateArgumentBindings()
方法:
java
public final void calculateArgumentBindings() {
// The simple case... nothing to bind.
// 没有入参,直接返回
if (this.argumentsIntrospected || this.parameterTypes.length == 0) {
return;
}
int numUnboundArgs = this.parameterTypes.length;
Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
if (maybeBindJoinPoint(parameterTypes[0]) // 绑定了参数 JoinPoint
|| maybeBindProceedingJoinPoint(parameterTypes[0]) // 绑定了参数:ProceedingJoinPoint
|| maybeBindJoinPointStaticPart(parameterTypes[0])) { // 绑定了参数:JoinPoint.StaticPart
// 注意该参数只能放在第一个位置,否则会报错。注意他们是aspectj包中的对象,不是spring的
numUnboundArgs--;
}
if (numUnboundArgs > 0) { // 绑定其他我们自定义的参数
// need to bind arguments by name as returned from the pointcut match
bindArgumentsByName(numUnboundArgs);
}
this.argumentsIntrospected = true;
}
在这个方法中,我们就可以通过源码的方式知道,增强方法传参数时,如果入参有JoinPoint
参数,那么它必须放在第一个入参。到这里,我们就已经知道spring是如何构建一个advisor对象的了。代码逻辑中,还有"延迟加载的增强"、"引介增强"的逻辑,由于平时也没用到过,就暂时都没研究了。我们再返回到getAdvisors()
方法,可以看到它获取到advisor
的List对象也就直接返回了。接着我们返回上一层继续看findEligibleAdvisors()
方法,再回顾一下:
java
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 在spring容器中寻找所有的advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 寻找适合当前bean的advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors); // 扩展接口
if (!eligibleAdvisors.isEmpty()) {
// 排序(根据Order注解来排)
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
在得到容器中所有的advisor后,接着看findAdvisorsThatCanApply()
方法,筛选适合当前bean的Advisor
:
java
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
// 使用了ThreadLocal保证线程安全
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 寻找适合当前bean的增强
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
可以看到spring将筛选的步骤,交给了AopUtils
类来做,进入该方法:
java
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
// 判断 引介增强(DeclareParents注解声明的增强) 是否符合增强当前bean
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
// "引介增强" 前面已经判断过了,直接跳过
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 判断增强是否符合当前bean
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
判断增强是否符合当前bean主要是通过canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions)
方法:
java
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) { // 引介增强
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
//在前面是初始化成 InstantiationModelAwarePointcutAdvisorImpl对象,它是PointcutAdvisor的子类
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
// 如果增强没有设置切点信息,我们假设这个增强是适合当前bean的
return true;
}
}
再进入canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions)
(重载)方法:
java
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
// 最终判断,是由aspectJ jar进行逻辑判断的
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {// 方法级别上判断,是否符和当前bean
return true;
}
}
}
return false;
}
可以看到判断"增强"是否适合当前bean,主要是利用PointCut
接口获取ClassFilter
和MethodMatcher
实例,然后调用其matches()
方法进行判断。但最终的实现用的是aspectJ三方jar包的功能。这里主要学习spring的源码逻辑,具体逻辑,就不细究了,感兴趣的可以搜索相关资料看看(目前个人没啥兴趣~_~)。至此已经筛选出符合当前bean的增强了。然后再次返回findEligibleAdvisors()
方法,再次对增强,排了一次序,但这次是根据@Order
来排的。ok,至此成功获取符合当前bean的增强了。
2.2 创建代理对象
- 本文主要学习基于java接口动态代理的AOP。在看spring如何创建代理对象前,先回顾一下java的动态代理:动态代理
- 前面我们已经获取到了适合当前bean的增强对象。接下来就是创建代理对象了,接着返回看
AbstractAutoProxyCreator.wrapIfNecessary()
方法,看其中创建代理对象的方法:
java
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this); // 复制当前类的属性
if (proxyFactory.isProxyTargetClass()) {
// 基于JDK动态代理
if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
// 获取类的接口,并将接口赋值到代理工厂类中
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// No proxyTargetClass flag enforced, let's apply our default checks...
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
/*将所有增强都装饰成advisor(除了自己写的增强,还有部分公共增强,默认是没有公共的增强的)*/
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors); // 加入增强
proxyFactory.setTargetSource(targetSource); // 设置要代理的类
customizeProxyFactory(proxyFactory); // 定制化代理类(可扩展接口)
/*用来控制代理工厂被配置之后,是否还允许修改通知。默认值为false(即在代理被配置后,不允许修改代理的配置)*/
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
}
// 通过工厂类创建代理对象
return proxyFactory.getProxy(classLoader);
}
可以看到代理类是通过工厂类创建的,我们先看下proxyFactory
的继承结构:
源码中对Advised
类的释义是:AOP代理工厂的父类,该工厂必须含有一个配置清单,清单含有Interceptors
和其他advice, Advisors,和代理接口。我们接着看工厂类创建代理的过程proxyFactory.getProxy()
方法:
java
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
接着看createAopProxy()
方法:
java
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
先是调用getAopProxyFactory()
方法获取AOP代理工厂类,其实就是DefaultAopProxyFactory
类,接着看该类的createAopProxy()
方法:
java
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!NativeDetector.inNativeImage() &&
// 用来控制通过CGLIB创建的代理使用激进的优化策略。除非完全了解AOP代理处理优化,否则不推荐用户使用这个设置。目前这个属性只用于CGLIB代理
(config.isOptimize()
// 这个属性为true时,目标类本身被代理而不是目标类的接口。true,创建CGLIB代理。设置方式:<aop:aspectj-autoproxy- proxy-target-class="true"/>
|| config.isProxyTargetClass()
// 是否存在代理类(没有实现接口,创建CGLIB代理;)
|| 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() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
// 符合一定条件,创建JDK动态代理
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
可以看到返回了一个JdkDynamicAopProxy
实例,然后看下该类的继承结构:
java
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable{}
看到没!它实现了InvocationHandler
接口,是不是熟悉的感觉了。那么该类必定会有一个invoke()
方法和getProxy()
方法。我们先看下它的getProxy()
方法:
java
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 返回代理对象
return Proxy.newProxyInstance(determineClassLoader(classLoader),this.proxiedInterfaces, this);
}
看到这行返回代理对象的代码,是不是和我们自己编写、基于接口的java动态代理的逻辑一毛一样了了。然后我们再看下它的构造函数,了解一下他的结构:
java
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
// 代理的接口
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces); // 是否有equal和hashCode方法
}
这里主要赋值了advised
属性和proxiedInterfaces
,这里我们再回顾一下Advised
对象释义:它AOP代理工厂的父类,该工厂必须含有一个配置清单,清单含有Interceptors 和其他 advice, Advisors,和代理接口。这样就创建好一个代理对象了。
2.3 调用一个方法的增强流程
通过上一节,我们已经获取到了代理对象JdkDynamicAopProxy
,那么当我们调用一个方法时,必定是先执行JdkDynamicAopProxy.invoke()
方法:
java
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
// ...
// 省略了一些无关主流程的代码
// ...
Object retVal;
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 获取适合当前方法的拦截器链(即增强),会把advisor封装成MethodInterceptor对象
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
// 如果没有发现任何拦截器,则直接调用切点方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 将拦截器封装在ReflectiveMethodInvocation
// 以便使用其proceed方法,进行递归调用
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
整体流程:
- 获取适合当前方法的拦截器链(即增强)
- 调用拦截器链,返回执行结果
先看this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)
获取拦截器链的逻辑:
java
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
又将"获取拦截器链"的功能委托给了advisorChainFactory
对象,进入该类:
java
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors(); // 增强对象
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) { // 循环增强
// 由切点驱动的增强(我们大部分的切面增强,应该都是这个)
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 再次校验了增强是否符和当前bean
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
// 如果增强适合当前方法,将增强装饰成拦截器(MethodInterceptor)
if (match) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
// 引介增强
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
获取拦截链的流程,我们主要看下将advisor
适配成MethodInterceptor
的逻辑:registry.getInterceptors(advisor)
。spring是将它委托了给DefaultAdvisorAdapterRegistry
类,进入该类:
java
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
// 实现了MethodInterceptor接口的,直接添加(AspectJAroundAdvice、AspectJAfterAdvice、AspectJAfterThrowingAdvice)
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
// 没有实现MethodInterceptor接口的,利用适配器适配(AspectJMethodBeforeAdvice、AspectJAfterReturningAdvice)
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[0]);
}
没有实现MethodInterceptor接口的增强类型,被适配之后的类:
原始增强类 | 适配后的类 |
---|---|
AspectJMethodBeforeAdvice | MethodBeforeAdviceInterceptor |
AspectJAfterReturningAdvice | AfterReturningAdviceInterceptor |
将Advisor
装饰成MethodInterceptor
(拦截器)后,接着就是执行拦截器(增强)了。它先是初始化了一个ReflectiveMethodInvocation
对象:
java
protected ReflectiveMethodInvocation(
Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy; // 代理对象
this.target = target; // 真正的bean对象
this.targetClass = targetClass; // 目标类的class对象
this.method = BridgeMethodResolver.findBridgedMethod(method); // 要执行的目标方法
// 目标方法的参数
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
// 拦截器链
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
接着我们看下ReflectiveMethodInvocation
类的继承结构:
可以看到ReflectiveMethodInvocation
其实是一个Joinpoint
。看到这里,可以在再仔细回忆、思考一下spring中连接点Joinpint
的含义。我也是学习到这里才对连接点的含义逐渐清晰,之前看别人的解释,总是一知半解。另外AspectJ jar包中也有一个JoinPoint
类,看代码的时候注意区别一下,别搞混淆了(我就混淆了,好一会才反应过来)。
接着看真正执行拦截器(增强)的方法ReflectiveMethodInvocation.proceed()
:
java
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 执行完所有增强后,执行"目标"方法
if (this.currentInterceptorIndex==this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 取出下一个"增强"
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
// 动态匹配调用
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
} else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
// 不匹配则不执行当前拦截器,执行下一个
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 普通拦截器,直接调用拦截器。
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
我们的增强一般都是普通"拦截器",都是直接调用MethodInterceptor.invoke
,我们的增强对象在前面说过,要不实现了MethodInterceptor
接口,要不已经被适配成了MethodInterceptor
子类。我们按照增强类型,一个一个看过来:
- @Around 对应
AspectJAroundAdvice
类: 直接看该类的invoke()
方法:
java
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
// 注意注意,就是在这一步,把spring的Joinpoint对象转化为了Aspectj的JoinPoint对象
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
return invokeAdviceMethod(pjp, jpm, null, null); // 调用增强方法
}
我们再接着看调用增强的方法invokeAdviceMethod()
,它是在父类AbstractAspectJAdvice
中实现的:
java
protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
@Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}
它先是调用argBinding()
方法获取目标方法的参数列表,然后将其作为入参,调用invokeAdviceMethodWithGivenArgs()
方法:
java
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// 执行增强方法
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
没有特殊、复杂的逻辑。执行到这里,它就会调用环绕增强,比如我们前面的例子:
这里需要注意,环绕通知的增强方法,第一个入参必须是ProceedingJoinPoint
,在执行完前置逻辑后,调用point.proceed()
方法,继续调用下一个增强。要不然程序就在这里中断了。
- @Before 对应
AspectJMethodBeforeAdvice
,但未实现MethodInterceptor
接口,被装饰为MethodBeforeAdviceInterceptor
类,直接看他的invoke()
方法:
java
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
可以看到它直接先是调用的advice.before
方法,即增强内容AspectJMethodBeforeAdvice.before()
方法:
java
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
它和AspectJAroundAdvice
一样,都是通过调用父类AbstractAspectJAdvice.invokeAdviceMethod()
方法,来执行增强方法的。执行完增强方法后,再调用mi.proceed()
方法,递归继续执行下一个增强。
- @After 对应
AspectJAfterAdvice
类,直接看他的invoke()
方法:
java
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
可以看到它是直接调用了mi.proceed()
方法,先递归执行下一个增强,然后在finally
中再执行增强方法。
- @AfterReturning 对应
AspectJAfterReturningAdvice
类,但未实现MethodInterceptor
接口,被装饰为AfterReturningAdviceInterceptor
类,直接看他的invoke()
方法:
java
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
可以看到,它是先直接调用mi.proceed()
方法,先递归执行下一个增强,然后再执行增强方法this.advice.afterReturning()
:
java
public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {
if (shouldInvokeOnReturnValueOf(method, returnValue)) {
invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
}
}
可以看到后置通知,它可以将"目标方法"的返回值,传入后置增强方法中的。
- @AfterThrowing 对应
AspectJAfterThrowingAdvice
类,直接看他的invoke()
方法:
java
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
可以看到,它是先直接调用mi.proceed()
方法递归执行下一个增强。假如目标方法执行过程中,抛出异常了,就会调用其增强方法。
- 看源码过程中,发现还有一个增强
ThrowsAdviceInterceptor
,看其效果和AspectJAfterThrowingAdvice
一样。要求增强类实现ThrowsAdvice
接口。至今个人没有用过。感兴趣的小伙伴可以研究一下。 - 看完5种增强类型的源码,也可以看出他们的执行顺序必定是:Around或Before >> AfterReturning >> AfterThrowing >> After
3.总结
以上就是spring AOP基于java动态代理的源码。spring源码被称为"面对对象"语言的典范,带着"面对对象"的思想去读spring的源码也会另一番收获。我在读spring源码时,常常看着看着就不知道跳到那个类去了,所以针对各个类画时序图就非常重要了,各位也可以尝试。下面是我在阅读时,关于各个流程画的时序图,供参考:
个人理解,如有错误欢迎评论区指正。也希望有小伙伴可以一起交流讨论、欢迎评论区留言。
网页上由于查看类的继承结构,方法跳转等诸多限制,阅读源码,强烈建议在IDE中阅读。本人阅读spring源码的记录:gitee.com/longshunche...
参考图书:郝佳前辈的《spring源码深度解析》