云原生应用架构设计与开发实战WM

118 阅读3分钟

前言

复制下哉ZY-》 : https://www.97yrbl.com/t-1389.html

AOP是我们使用Spring时较为常用的功能,今天让我们来看看其中的玄机

@EnableAspectJAutoProxy

项目中使用AOP的时候,都必须在某个类上标注@EnableAspectJAutoProxy,代表开启AOP,这个开启AOP是什么意思呢?

@Aspect
@Component
@Slf4j
@EnableAspectJAutoProxy
public class AspectTest {
}
复制代码

点击进去EnableAspectJAutoProxy,会发现EnableAspectJAutoProxy import 了AspectJAutoProxyRegistrar类

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;
​
    boolean exposeProxy() default false;
}
复制代码

在之前的Spring文章中,我曾写过,@Import这个注解可以引入三种类型的类

  • ImportSelector类型
  • ImportBeanDefinitionRegistrar类型
  • 普通类

不管哪种类型,都是注册BeanDefinition的一种方式,此处Import的是ImportBeanDefinitionRegistrar,这个类注册了AnnotationAwareAspectJAutoProxyCreator这个BeanDefinition

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
      BeanDefinitionRegistry registry, @Nullable Object source) {
​
   return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
复制代码

看看AnnotationAwareAspectJAutoProxyCreator这个类的继承图,会发现它只是在原有Spring-AOP的基础上做了注解方面的扩展。需要特别注意的是,该类实现了BeanPostProcessor,对Spring源码比较熟悉的同学应该知道实现这个类意味着什么,说明AOP是在Spring原有Bean生命周期上加东西,并没有逃脱Spring的牢笼

一些基础知识

Advice与Advisor

我们经常会看到Advice、Advisor,他们有什么区别呢?

Advice是通知,Advisor是增强器,每个Advisor都会持有一个Advice

public interface Advisor {
  
   Advice EMPTY_ADVICE = new Advice() {};
   // 比如这个接口,可以获取Advisor持有的Advice
   Advice getAdvice();
   boolean isPerInstance();
​
}
复制代码
AopInfrastructureBean
// Spring内部的这个接口没有任何实现,只是一个标记接口,如果Spring中的类实现了这个接口,就会被标记为Spring的基础设施类
// 不会被自动代理
public interface AopInfrastructureBean {
​
}
​
// 在AbstractAutoProxyCreator这个类中,有一个方法,判断某个类需不需要被代理
// 如果是Advice、Pointcut、Advisor、AopInfrastructureBean的子类,则不需要被代理
protected boolean isInfrastructureClass(Class<?> beanClass) {
    boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
        Pointcut.class.isAssignableFrom(beanClass) ||
        Advisor.class.isAssignableFrom(beanClass) ||
        AopInfrastructureBean.class.isAssignableFrom(beanClass);
    if (retVal && logger.isTraceEnabled()) {
      logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
    }
    return retVal;
}
复制代码
Pointcut

Pointcut作为Spring AOP最顶级的抽象,主要负责对系统相应Joinpoint的捕获,如果把Joinpoint比做数据,那么Pointcut就是查询条件,一个Pointcut可以对应多个Joinpoint。ClassFilter和MethodMatcher分别限定在不同级别上对于Joinpoint的匹配,ClassFilter是类级别,MethodMatcher是方法级别,使用AOP的同学应该都清楚,AOP主要支持方法级别的匹配,所以类级别的匹配功能较为简单

public interface Pointcut {
​
  ClassFilter getClassFilter();
  MethodMatcher getMethodMatcher();
  Pointcut TRUE = TruePointcut.INSTANCE;
​
}
​
​
public interface ClassFilter {
​
  // 给定的类是否匹配
  boolean matches(Class<?> clazz);
  ClassFilter TRUE = TrueClassFilter.INSTANCE;
​
}
​
​
public interface MethodMatcher {
​
  // 在这里有一个静态切入点和动态切入点的概念
  // 静态切入点:只进行一次检测
  // 动态切入点:每次切入都检测
  boolean matches(Method method, Class<?> targetClass);
  // 判断静态切入点和动态切入点的标志,return true表示动态
  boolean isRuntime();
  boolean matches(Method method, Class<?> targetClass, Object... args);
  MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
​
}
复制代码
IntroductionAdvisor

为AOP提供类级别的拦截

public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
​
   ClassFilter getClassFilter();
​
   void validateInterfaces() throws IllegalArgumentException;
}
​
public interface IntroductionInfo {
  // 这个接口可以定义AOP适用的类,不适用的类,可以不进行AOP拦截
  Class<?>[] getInterfaces();
​
}
复制代码
PointcutAdvisor

为AOP提供方法级别的拦截

public interface PointcutAdvisor extends Advisor {
​
   Pointcut getPointcut();
​
}
复制代码

单纯看以上几个类,可能会很懵,下面是AOP过程中获取拦截器链的代码,结合这些代码感受一下AOP是如何对Advisor进行筛选的

@Override
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) {
      // 如果advisor是PointcutAdvisor的实例
      if (advisor instanceof PointcutAdvisor) {
         PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
         // 如果是预先筛选过或者advisor适用于目标类
         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);
            }
            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));
               }
            }
         }
      }
      // 如果advisor是IntroductionAdvisor的实例
      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;
}