Spring源码(12)-- Aop源码
Aop
切面编程包括切面(Aspect),连接点(Joinpoint)、通知(Advice)、切点(Pointcut)、引入(Introduction)
通知(Advice)又分为前置通知,后置通知,返回通知,环绕通知,异常通知等。
AOP 基础知识:
详情见: https://blog.csdn.net/sinat_32502451/article/details/142291052
Aop 注解:
@Aspect表明整个类是一个切面。
@Pointcut注解声明一个切点。
@Before:前置通知,在方法执行前执行。
@After:后置通知, 在方法执行后执行。
@AfterThrowing:异常通知, 在方法抛出异常后执行。
@AfterReturning :返回通知,在方法成功返回后执行。
@Around:环绕通知。可以在方法的前后执行逻辑。
Aop 示例:
可以在 com.example.demo.controller. 这个文件夹下创建一个 Controller 类,通过 http请求调用接口,触发AOP逻辑。
通过以下的这个示例,学习 @Aspect 、@Pointcut 、@Before、 @After、 @AfterReturning 、@Around 的运用及源码。
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AopExample {
/**
* 定义切点 切点为 com.example.demo..controller 下所有的类
*
* 第一个 * 表示任意类,
* 第二个 * 表示任意方法。
* .. 表示匹配任意数量任意类型的参数。
*/
@Pointcut("execution(* com.example.demo..controller.*.*(..))")
public void pointcut() {
log.info("AopExample pointcut ..");
}
/**
* 前置通知
*/
@Before(value = "pointcut()")
public void aopBefore(JoinPoint joinPoint ) {
log.info("AopExample aopBefore ..");
}
/**
* 后置通知
*/
@After(value = "pointcut()")
public void aopAfter(JoinPoint joinPoint ) {
log.info("AopExample aopAfter ..");
}
/**
* 返回通知
*/
@AfterReturning(value = "pointcut()")
public void aopAfterReturning(JoinPoint joinPoint) throws Throwable {
log.info("AopExample aopAfterReturning ..");
}
/**
* 异常通知
*/
@AfterThrowing(value = "pointcut()")
public void aopAfterThrowing(JoinPoint joinPoint) throws Throwable {
log.info("AopExample aopAfterThrowing ..");
}
/**
* 环绕通知
*/
@Around(value = "pointcut()")
public Object aopAround(ProceedingJoinPoint joinPoint) throws Throwable {
String className = joinPoint.getTarget().getClass().getName();
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取方法路径及方法名称
String methodName = className + "#" + signature.getMethod().getName();
log.info("AopExample class aopAround start.methodName:{}", methodName);
//在这里,会执行pointcut对应的方法
Object proceed = joinPoint.proceed();
log.info("AopExample class aopAround end.");
return proceed;
}
}
1.Aspect (切面)
切面(Aspect) 。
代码: org.aspectj.lang.annotation.Aspect
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Aspect {
/**
* 表达式
*/
public String value() default "";
}
- AbstractAspectJAdvisorFactory:
代码:org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
判断提供的方法上是否有 @Aspect 注解。如果给定方法本身不直接存在注解,则遍历其超方法(即从超类和接口)。
在Spring启动时就会进行判断。
/**
* 判断是否为 Aspect(切面)。
*/
@Override
public boolean isAspect(Class<?> clazz) {
return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
/**
* 判断是否有 @Aspect 注解。
*/
private boolean hasAspectAnnotation(Class<?> clazz) {
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}
2.JoinPoint(连接点)
JoinPoint(连接点)可以获取类的信息,包括类名、方法名、参数等(joinPoint.getArgs()), 还可以执行目标对象方法的逻辑(joinPoint.proceed())。
代码: org.aspectj.lang.JoinPoint
/**
* 提供对连接点可用状态及其静态信息的反射访问。
* 此信息可使用thisJoinPoint从advice中获得。
* 这种反射信息的主要用途是用于跟踪和记录应用程序。
*/
public interface JoinPoint {
String toString();
/**
* 返回连接点的缩写字符串表示形式。
*/
String toShortString();
/**
* 返回连接点的扩展字符串表示形式。
*/
String toLongString();
/**
* 返回当前正在执行的对象。
*/
Object getThis();
/**
* 返回目标对象。
*/
Object getTarget();
/**
* 返回此连接点处的参数。
*/
Object[] getArgs();
/**
*
* 返回连接点处的签名。
*/
Signature getSignature();
/**
* 返回与连接点对应的源位置。
*/
SourceLocation getSourceLocation();
/**
* 返回一个表示连接点类型的字符串。
*/
String getKind();
/**
* 此辅助对象仅包含有关连接点的静态信息。
*/
public interface StaticPart {
Signature getSignature();
SourceLocation getSourceLocation();
String getKind();
/**
* 返回此 JoinPoint.StaticPart 的id。
*/
int getId();
String toString();
String toShortString();
String toLongString();
}
public interface EnclosingStaticPart extends StaticPart {}
/**
* 返回一个封装此连接点静态部分的对象。
*/
StaticPart getStaticPart();
/**
* getKind()的合法返回值
*/
static String METHOD_EXECUTION = "method-execution";
static String METHOD_CALL = "method-call";
static String CONSTRUCTOR_EXECUTION = "constructor-execution";
static String CONSTRUCTOR_CALL = "constructor-call";
static String FIELD_GET = "field-get";
static String FIELD_SET = "field-set";
static String STATICINITIALIZATION = "staticinitialization";
static String PREINITIALIZATION = "preinitialization";
static String INITIALIZATION = "initialization";
static String EXCEPTION_HANDLER = "exception-handler";
static String SYNCHRONIZATION_LOCK = "lock";
static String SYNCHRONIZATION_UNLOCK = "unlock";
static String ADVICE_EXECUTION = "adviceexecution";
}
Invocation
Invocation 继承了 Joinpoint 接口。
Invocation 接口表示程序中一个的调用。调用是一个连接点,可以被拦截器拦截。
public interface Invocation extends Joinpoint {
/**
* 以数组对象的格式,返回方法参数。可以更改此数组中的元素值以更改参数。
*/
Object[] getArguments();
}
MethodInvocation
MethodInvocation是继承了Invocation的, 而 Invocation 又继承Joinpoint(连接点)。
MethodInvocation 是对方法调用的描述,在方法调用时提供给拦截器。方法调用是一个连接点,可以被方法拦截器拦截。
MethodInvocation 在Aop 的各种通知中经常被作为方法参数使用。通过 MethodInvocation 来执行目标对象的方法。
public interface MethodInvocation extends Invocation {
/**
* 获取被调用的方法。
*/
Method getMethod();
}
3.Pointcut (切点)
- @Pointcut 注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Pointcut {
/**
* 切入点表达式,允许“”这个空值作为抽象切入点的默认值
*/
String value() default "";
/**
* 在没有调试信息的情况下编译时,或者在运行时解析切入点时,切入点中使用的任何参数的名称都不可用。
*/
String argNames() default "";
}
- Pointcut 接口:
代码: org.springframework.aop.Pointcut
Pointcut(切入点)由 ClassFilter 和 MethodMatcher 组成。
ClassFilter是类级别的匹配,MethodMatcher是方法级别的匹配。
/**
* Spring切入点抽象。
* 切入点由 ClassFilter 和 MethodMatcher 组成。
* 这些基本术语和Pointcut本身都可以组合在一起,形成组合。
*
*/
public interface Pointcut {
/**
* 返回 ClassFilter。
*
*/
ClassFilter getClassFilter();
/**
* 返回 MethodMatcher.
*
*/
MethodMatcher getMethodMatcher();
/**
* 匹配的规范Pointcut实例。
*/
Pointcut TRUE = TruePointcut.INSTANCE;
}
4.Advice
Advice 是通知的接口。
Advice 的实现可以是任何类型的通知,例如拦截器。
代码: org.aopalliance.aop.Advice
public interface Advice {
}
Interceptor
Interceptor 是拦截器的接口。Interceptor 实现了 Advice。
public interface Interceptor extends Advice {
}
MethodInterceptor
MethodInterceptor 是一个拦截器接口,可以在目标方法调用的前后执行额外的处理,应用非常广泛。
Aop 的各种通知 AspectJMethodBeforeAdvice、 AspectJAfterAdvice、AspectJAroundAdvice 等,
以及 TransactionInterceptor 都是通过 MethodInterceptor实现的。
此处的invoke()方法参数是 MethodInvocation, MethodInvocation是继承了Invocation的, 而 Invocation 又继承Joinpoint(连接点)。
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
/**
* 实现此方法以在调用前后执行额外的处理。此处的方法参数是 MethodInvocation, MethodInvocation是间接继承了Joinpoint(连接点)的。
*/
Object invoke(MethodInvocation invocation) throws Throwable;
}
AbstractAspectJAdvice
Advice 抽象类。
AOP的基类,包装 AspectJ切面的Advice方法。
代码: org.springframework.aop.aspectj.AbstractAspectJAdvice#invokeAdviceMethod
invokeAdviceMethod() 这个方法,调用的频率非常高。
// 通过JoinPoint(连接点),调用各种 Advice 方法。
protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
@Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// 调用 advice 方法。
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();
}
}
AspectJMethodBeforeAdvice
前置通知,添加了 @Before 注解就会调用,在方法执行后执行。
AspectJMethodBeforeAdvice 实现了 MethodBeforeAdvice 接口。
代码: org.springframework.aop.aspectj.AspectJMethodBeforeAdvice
可以看到,这里面就调用了 AbstractAspectJAdvice 抽象类里的 invokeAdviceMethod() 方法。
/**
* 在调用方法之前调用的通知。
*
*/
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
public AspectJMethodBeforeAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
@Override
public boolean isBeforeAdvice() {
return true;
}
@Override
public boolean isAfterAdvice() {
return false;
}
}
AspectJAfterAdvice
后置通知,添加了 @After 注解就会调用,在方法执行后执行。
代码: org.springframework.aop.aspectj.AspectJAfterAdvice
可以看到,这里面也调用了 AbstractAspectJAdvice 抽象类里的 invokeAdviceMethod() 方法。
/**
* Spring AOP Advice。在Advice方法后包装AspectJ
*
*/
@SuppressWarnings("serial")
public class AspectJAfterAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
public AspectJAfterAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
//调用目标对象的目标方法。
return mi.proceed();
}
finally {
//调用AbstractAspectJAdvice 抽象类里的 invokeAdviceMethod() 方法。
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
@Override
public boolean isBeforeAdvice() {
return false;
}
@Override
public boolean isAfterAdvice() {
return true;
}
}
AfterReturningAdvice
@AfterReturning 是返回通知,在方法成功返回后执行。
代码: org.springframework.aop.AfterReturningAdvice
仅在正常方法返回时调用此 Advice,而在抛出异常时则不调用。这样的 Advice 可以看到返回值,但无法更改它。
/**
* 仅在正常方法返回时调用此 Advice,而在抛出异常时则不调用。这样的 Advice 可以看到返回值,但无法更改它。
*
*/
public interface AfterReturningAdvice extends AfterAdvice {
/**
* 给定方法成功返回后的回调。
*/
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
AspectJAroundAdvice
@Around 是环绕通知,在方法的前后都会调用。
添加了 @Around 的方法,会调用 AspectJAroundAdvice的 invoke() 方法。
代码: org.springframework.aop.aspectj.AspectJAroundAdvice
/**
* Spring AOP 环绕通知(MethodInterceptor),它封装了AspectJ Advice方法。
*
*
*/
@SuppressWarnings("serial")
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable {
public AspectJAroundAdvice(
Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJAroundAdviceMethod, pointcut, aif);
}
@Override
public boolean isBeforeAdvice() {
return false;
}
@Override
public boolean isAfterAdvice() {
return false;
}
@Override
protected boolean supportsProceedingJoinPoint() {
return true;
}
@Override
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;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
//调用通知的方法。
return invokeAdviceMethod(pjp, jpm, null, null);
}
/**
* 返回当前调用的ProceedingJoinPoint,如果它还没有绑定到线程,则延迟实例化它。
*/
protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) {
return new MethodInvocationProceedingJoinPoint(rmi);
}
}
5.Advisor
- Advisor = Pointcut + Advice
Advisor 相当于 Pointcut 加上 Advice 。
此接口不供Spring用户使用,但允许支持不同类型的Advice。
代码: org.springframework.aop.Advisor
/**
* 基础接口,用于维持AOP通知(在连接点采取的行动)和确定通知适用性的过滤器(如切入点pointCut)。
*
*/
public interface Advisor {
/**
* 如果尚未配置正确的通知,则从getAdvice()返回空通知的常用占位符。
*/
Advice EMPTY_ADVICE = new Advice() {};
/**
* 返回此切面的通知部分。通知可以是拦截通知、事前通知、抛出通知等
*/
Advice getAdvice();
/**
* 返回此通知是与特定实例相关联(例如,创建混入)还是与从同一Spring bean工厂获得的通知类的所有实例共享。
*/
boolean isPerInstance();
}
- AspectJAdvisorFactory:
Advisor的工厂。
代码: org.springframework.aop.aspectj.annotation.AspectJAdvisorFactory
/**
* 用于工厂的接口,可以从用AspectJ注解的类中创建Spring AOP Advisors。
*
*/
public interface AspectJAdvisorFactory {
/**
* 确定给定的类是否是一个切面。
*/
boolean isAspect(Class<?> clazz);
/**
* 校验给定的类是否为有效的AspectJ切面类。
*/
void validate(Class<?> aspectClass) throws AopConfigException;
/**
* 为指定切面实例上所有带注解的 AspectJ方法构建Spring AOP Advisors。
*/
List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory);
/**
* 为给定的AspectJ通知方法构建一个Spring AOP Advisor。
*/
@Nullable
Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrder, String aspectName);
/**
* 为给定的AspectJ通知方法构建Spring AOP通知。
*/
@Nullable
Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName);
}
BeanFactoryAspectJAdvisorsBuilder
在Spring 启动时,会查找AspectJ注解的切面bean, 并构建 Advisors。
代码: org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
AspectJAdvisorFactory 接口代码: org.springframework.aop.aspectj.annotation.AspectJAdvisorFactory
/**
* 在当前bean工厂中查找AspectJ注解的切面bean,并返回代表它们的Spring AOP Advisors列表。
* 为每个AspectJ通知方法创建一个Spring Advisor。
*/
public List<Advisor> buildAspectJAdvisors() {
// aspectBeanNames 是指带有@Aspect注解的类名
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
//双重检查
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
//根据类的路径,获取 Class 类型。
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
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);
//在这里,会获取 Advisors
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 (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;
}
- getAdvisors:
在Spring 启动时,会获取 Advisors 。
代码: org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
//切面名称
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
//校验给定的类是否为有效的AspectJ切面。
validate(aspectClass);
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), 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.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new ArrayList<>();
ReflectionUtils.doWithMethods(aspectClass, method -> {
// Exclude pointcuts
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
});
methods.sort(METHOD_COMPARATOR);
return methods;
}