【小家Spring】Spring AOP原理使用的基础类打点(AopInfrastructureBean、ProxyProcessorSupport、Advised、AjType)(上)

简介: 【小家Spring】Spring AOP原理使用的基础类打点(AopInfrastructureBean、ProxyProcessorSupport、Advised、AjType)(上)

前言


Spring AOP是整个Spring框架中最重要的内容之一。为了更好的深入查看它的原理,这篇文章主要是把它在关键位置使用到的一些常用类进行打点、解释一波,有助于我们去看源代码的时候变得更加的轻松、流畅


Spring AOP相关类、组件内容庞大。此处只会介绍一些最为常用的概念进行分析~~~


Spring AOP常用类解释


image.png


AopInfrastructureBean:免被AOP代理的标记接口


AopInfrastructureBean是一个标记接口。若Bean实现了此接口,表明它是一个Spring AOP的基础类,那么这个类是不会被AOP给代理的,即使它能被切面切进去~~~


ProxyConfig:AOP配置类


用于创建代理的配置的父类,以确保所有代理创建者具有一致的属性。 它有五个属性,解释如下:


public class ProxyConfig implements Serializable {
  // 标记是否直接对目标类进行代理,而不是通过接口产生代理
  private boolean proxyTargetClass = false;
  // 标记是否对代理进行优化。true:那么在生成代理对象之后,如果对代理配置进行了修改,已经创建的代理对象也不会获取修改之后的代理配置。
  // 如果exposeProxy设置为true,即使optimize为true也会被忽略。
  private boolean optimize = false;
  // 标记是否需要阻止通过该配置创建的代理对象转换为Advised类型,默认值为false,表示代理对象可以被转换为Advised类型
  //Advised接口其实就代表了被代理的对象(此接口是Spring AOP提供,它提供了方法可以对代理进行操作,比如移除一个切面之类的),它持有了代理对象的一些属性,通过它可以对生成的代理对象的一些属性进行人为干预
  // 默认情况,我们可以这么完 Advised target = (Advised) context.getBean("opaqueTest"); 从而就可以对该代理持有的一些属性进行干预勒   若此值为true,就不能这么玩了
  boolean opaque = false;
  //标记代理对象是否应该被aop框架通过AopContext以ThreadLocal的形式暴露出去。
  //当一个代理对象需要调用它【自己】的另外一个代理方法时,这个属性将非常有用。默认是是false,以避免不必要的拦截。
  boolean exposeProxy = false;
  //标记是否需要冻结代理对象,即在代理对象生成之后,是否允许对其进行修改,默认为false.
  // 当我们不希望调用方修改转换成Advised对象之后的代理对象时,就可以设置为true 给冻结上即可
  private boolean frozen = false;
}


ProxyProcessorSupport


简单的说它就是提供为代理创建器提供了一些公共方法实现:


public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanClassLoaderAware, AopInfrastructureBean {
  /**
   * This should run after all other processors, so that it can just add
   * an advisor to existing proxies rather than double-proxy.
   * 【AOP的自动代理创建器必须在所有的别的processors之后执行,以确保它可以代理到所有的小伙伴们,即使需要双重代理得那种】
   */
  private int order = Ordered.LOWEST_PRECEDENCE;
  // 当然此处还是提供了方法,你可以自己set或者使用@Order来人为的改变这个顺序~~~
  public void setOrder(int order) {
    this.order = order;
  }
  @Override
  public int getOrder() {
    return this.order;
  }
  ...
  // 这是它提供的一个最为核心的方法:这里决定了如果目标类没有实现接口直接就是Cglib代理
  // 检查给定beanClass上的接口们,并交给proxyFactory处理
  protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
    // 找到该类实现的所有接口们~~~
    Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
    // 标记:是否有存在【合理的】接口~~~
    boolean hasReasonableProxyInterface = false;
    for (Class<?> ifc : targetInterfaces) {
      if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
          // 该接口必须还有方法才行,不要忘记了这步判断咯~~~~
          ifc.getMethods().length > 0) {
        hasReasonableProxyInterface = true;
        break;
      }
    }
    if (hasReasonableProxyInterface) {
      // Must allow for introductions; can't just set interfaces to the target's interfaces only.
      // 这里Spring的Doc特别强调了:不能值只把合理的接口设置进去,而是都得加入进去
      for (Class<?> ifc : targetInterfaces) {
        proxyFactory.addInterface(ifc);
      }
    }
    else {
      // 这个很明显设置true,表示使用CGLIB得方式去创建代理了~~~~
      proxyFactory.setProxyTargetClass(true);
    }
  }
  // 判断此接口类型是否属于:容器去回调的类型,这里例举处理一些接口 初始化、销毁、自动刷新、自动关闭、Aware感知等等
  protected boolean isConfigurationCallbackInterface(Class<?> ifc) {
    return (InitializingBean.class == ifc || DisposableBean.class == ifc || Closeable.class == ifc ||
        AutoCloseable.class == ifc || ObjectUtils.containsElement(ifc.getInterfaces(), Aware.class));
  }
  // 是否是如下通用的接口。若实现的是这些接口也会排除,不认为它是实现了接口的类
  protected boolean isInternalLanguageInterface(Class<?> ifc) {
    return (ifc.getName().equals("groovy.lang.GroovyObject") ||
        ifc.getName().endsWith(".cglib.proxy.Factory") ||
        ifc.getName().endsWith(".bytebuddy.MockAccess"));
  }
}


ProxyCreatorSupport


这个类应该很熟了,我们之前介绍过的三大创建代理对象的工厂ProxyFactoryBean、ProxyFactory、AspectJProxyFactory都是继承自此类的

参考:【小家Spring】面向切面编程Spring AOP创建代理的方式:ProxyFactoryBean、ProxyFactory、AspectJProxyFactory(JDK Proxy和CGLIB)


ProxyCreatorSupport用于设置和保存下面三大信息:


1.设置被代理对象target

2.设置代理接口

3.设置通知advice


ProxyCreatorSupport继承AdvisedSupport,主要提供了createAopProxy方法用来得到用来生成代理对象的AopProxy对象:

public class ProxyCreatorSupport extends AdvisedSupport {
  // new了一个aopProxyFactory 
  public ProxyCreatorSupport() {
    this.aopProxyFactory = new DefaultAopProxyFactory();
  }
  protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
      activate();
    }
    // 由此可议看出,它还是委托给了`AopProxyFactory`去做这件事~~~  它的实现类为:DefaultAopProxyFactory
    return getAopProxyFactory().createAopProxy(this);
  }
}
//DefaultAopProxyFactory#createAopProxy
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
  @Override
  public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // 对代理进行优化  或者  直接采用CGLIB动态代理  或者 
    //config.isOptimize()与config.isProxyTargetClass()默认返回都是false
    // 需要优化  强制cglib  没有实现接口等都会进入这里面来
    if (config.isOptimize() || config.isProxyTargetClass() || 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.");
      }
      // 倘若目标Class本身就是个接口,或者它已经是个JDK得代理类(Proxy的子类。所有的JDK代理类都是此类的子类),那还是用JDK的动态代理吧
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
        return new JdkDynamicAopProxy(config);
      }
      // 实用CGLIB代理方式 ObjenesisCglibAopProxy是CglibAopProxy的子类。Spring4.0之后提供的
      // 
      return new ObjenesisCglibAopProxy(config);
    }
    // 否则(一般都是有实现接口) 都会采用JDK得动态代理
    else {
      return new JdkDynamicAopProxy(config);
    }
  }
  // 如果它没有实现过接口(ifcs.length == )  或者 仅仅实现了一个接口,但是呢这个接口却是SpringProxy类型的   那就返回false
  // 总体来说,就是看看这个cofnig有没有实现过靠谱的、可以用的接口
  // SpringProxy:一个标记接口。Spring AOP产生的所有的代理类 都是它的子类~~
  private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
    Class<?>[] ifcs = config.getProxiedInterfaces();
    return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
  }
}


Objenesis是专门用于实例化一些特殊java对象的一个工具,如私有构造方法。我们知道带参数的构造等不能通过class.newInstance()实例化的,通过它可以轻松完成

基于Objenesis的CglibAopProxy扩展,用于创建代理实例,没有调用类的构造器(厉害了)


Advised

Advice: 通知拦截器

Advisor: 通知 + 切入点的适配器

Advised: 包含所有的Advised 和 Advice


该接口用于保存一个代理的相关配置。比如保存了这个代理相关的拦截器、通知、增强器等等。

所有的代理对象都实现了该接口(我们就能够通过一个代理对象获取这个代理对象怎么被代理出来的相关信息)



不管是JDKproxy,还是cglib proxy,代理出来的对象都实现了org.springframework.aop.framework.Advised接口;


public interface Advised extends TargetClassAware {
  boolean isFrozen();
  boolean isProxyTargetClass();
  //返回呗代理了的接口们
  Class<?>[] getProxiedInterfaces();
  // 检查这个指定的接口是否被代理了。。。
  boolean isInterfaceProxied(Class<?> intf);
  // 设置一个源。只有isFrozen为false才能调用此方法
  void setTargetSource(TargetSource targetSource);
  TargetSource getTargetSource();
  void setExposeProxy(boolean exposeProxy);
  boolean isExposeProxy();
  // 默认是false,和ClassFilter接口有关,暂时不做讨论
  void setPreFiltered(boolean preFiltered);
  boolean isPreFiltered();
  // 拿到作用在当前代理商得所有通知(和切面的适配器)
  Advisor[] getAdvisors();
  //相当于在通知(拦截器)链的最后一个加入一个新的
  void addAdvisor(Advisor advisor) throws AopConfigException;
  void addAdvisor(int pos, Advisor advisor) throws AopConfigException;
  boolean removeAdvisor(Advisor advisor);
  // 按照角标移除一个通知
  void removeAdvisor(int index) throws AopConfigException;
  int indexOf(Advisor advisor);
  boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;
  // 增加通知得相关方法  采用了适配器的模式
  // 最终都会变成一个DefaultIntroductionAdvisor(包装Advice的)
  void addAdvice(Advice advice) throws AopConfigException;
  void addAdvice(int pos, Advice advice) throws AopConfigException;
  boolean removeAdvice(Advice advice);
  int indexOf(Advice advice);
  String toProxyConfigString();
}


下面看看基础实现AdvisedSupport


AdvisedSupport


它最重要的一个方法是:提供getInterceptorsAndDynamicInterceptionAdvice方法用来获取对应代理方法对应有效的拦截器链


AdvisedSupport本身不会提供创建代理的任何方法,专注于生成拦截器链。委托给ProxyCreatorSupport去创建代理对象

public class AdvisedSupport extends ProxyConfig implements Advised {
  @Override
  public void addAdvisor(Advisor advisor) {
    int pos = this.advisors.size();
    addAdvisor(pos, advisor);
  }
  @Override
  public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
    if (advisor instanceof IntroductionAdvisor) {
      validateIntroductionAdvisor((IntroductionAdvisor) advisor);
    }
    addAdvisorInternal(pos, advisor);
  } 
  // advice最终都会备转换成一个`Advisor`(DefaultPointcutAdvisor  表示切面+通知),它使用的切面为Pointcut.TRUE
  // Pointcut.TRUE:表示啥都返回true,也就是说这个增强通知将作用于所有的方法上/所有的方法
  // 若要自己指定切面(比如切点表达式),使用它的另一个构造函数:public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice)
  @Override
  public void addAdvice(Advice advice) throws AopConfigException {
    int pos = this.advisors.size();
    addAdvice(pos, advice);
  }
  @Override
  public void addAdvice(int pos, Advice advice) throws AopConfigException {
    Assert.notNull(advice, "Advice must not be null");
    if (advice instanceof IntroductionInfo) {
      // We don't need an IntroductionAdvisor for this kind of introduction:
      // It's fully self-describing.
      addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
    }
    else if (advice instanceof DynamicIntroductionAdvice) {
      // We need an IntroductionAdvisor for this kind of introduction.
      throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
    }
    else {
      addAdvisor(pos, new DefaultPointcutAdvisor(advice));
    }
  }
  // 这里需要注意的是:setTarget最终的效果其实也是转换成了TargetSource
  // 也就是说Spring最终代理的  是放进去TargetSource让它去处理
  public void setTarget(Object target) {
    setTargetSource(new SingletonTargetSource(target));
  }
  @Override
  public void setTargetSource(@Nullable TargetSource targetSource) {
    this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
  }
    ... 其它实现略过,基本都是实现Advised接口的内容
  //将之前注入到advisorChain中的advisors转换为MethodInterceptor和InterceptorAndDynamicMethodMatcher集合(放置了这两种类型的数据)
  // 这些MethodInterceptor们最终在执行目标方法的时候  都是会执行的
  public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    // 以这个Method生成一个key,准备缓存 
    // 此处小技巧:当你的key比较复杂事,可以用类来处理。然后重写它的equals、hashCode、toString、compare等方法
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
      // 这个方法最终在这 DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
      //DefaultAdvisorChainFactory:生成通知器链的工厂,实现了interceptor链的获取过程
      cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
          this, method, targetClass);
      // 此处为了提供效率,相当于把该方法对应的拦截器们都缓存起来,加速后续调用得速度
      this.methodCache.put(cacheKey, cached);
    }
    return cached;
  }
}
//DefaultAdvisorChainFactory:生成拦截器链
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
  @Override
  public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
    // 拿到代理里面所有的通知们:getAdvisors
    List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    for (Advisor advisor : config.getAdvisors()) {
      if (advisor instanceof PointcutAdvisor) {
        // Add it conditionally.
        PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
        if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
          MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
          MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
          if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
            // 动态匹配
            if (mm.isRuntime()) {
              // Creating a new object instance in the getInterceptors() method
              // isn't a problem as we normally cache created chains.
              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;
  }
}
相关文章
|
4天前
|
运维 Java 程序员
Spring5深入浅出篇:基于注解实现的AOP
# Spring5 AOP 深入理解:注解实现 本文介绍了基于注解的AOP编程步骤,包括原始对象、额外功能、切点和组装切面。步骤1-3旨在构建切面,与传统AOP相似。示例代码展示了如何使用`@Around`定义切面和执行逻辑。配置中,通过`@Aspect`和`@Around`注解定义切点,并在Spring配置中启用AOP自动代理。 进一步讨论了切点复用,避免重复代码以提高代码维护性。通过`@Pointcut`定义通用切点表达式,然后在多个通知中引用。此外,解释了AOP底层实现的两种动态代理方式:JDK动态代理和Cglib字节码增强,默认使用JDK,可通过配置切换到Cglib
|
4天前
|
XML Java 数据格式
Spring使用AOP 的其他方式
Spring使用AOP 的其他方式
14 2
|
4天前
|
XML Java 数据格式
Spring 项目如何使用AOP
Spring 项目如何使用AOP
18 2
|
9天前
|
Java 开发者 Spring
Spring AOP的切点是通过使用AspectJ的切点表达式语言来定义的。
【5月更文挑战第1天】Spring AOP的切点是通过使用AspectJ的切点表达式语言来定义的。
22 5
|
9天前
|
XML Java 数据格式
Spring AOP
【5月更文挑战第1天】Spring AOP
25 5
|
3月前
|
Java 数据库连接 应用服务中间件
Spring5源码(39)-Aop事物管理简介及编程式事物实现
Spring5源码(39)-Aop事物管理简介及编程式事物实现
26 0
|
4月前
AOP&面向切面编程
AOP&面向切面编程
56 0
|
4月前
|
Java 程序员 Maven
Spring AOP入门指南:轻松掌握面向切面编程的基础知识
Spring AOP入门指南:轻松掌握面向切面编程的基础知识
|
4月前
|
数据库
AOP(面向切面编程)的基本概念和原理
AOP(面向切面编程)的基本概念和原理
88 0
|
6月前
|
缓存 监控 Java
Spring框架之AOP(面向切面编程)
Spring框架之AOP(面向切面编程)
34 0