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

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

AdvisorAdapter


spring aop框架对BeforeAdvice、AfterAdvice、ThrowsAdvice三种通知类型的支持实际上是借助适配器模式来实现的,这样的好处是使得框架允许用户向框架中加入自己想要支持的任何一种通知类型


的AdvisorAdapter是一个适配器接口,它定义了自己支持的Advice类型,并且能把一个Advisor适配成MethodInterceptor(这也是AOP联盟定义的借口),以下是它的定义

public interface AdvisorAdapter {
    // 判断此适配器是否支持特定的Advice  
    boolean supportsAdvice(Advice advice);  
    // 将一个Advisor适配成MethodInterceptor  
    MethodInterceptor getInterceptor(Advisor advisor);  
}


一般我们自己并不需要自己去提供此接口的实现(除非你还行适配被的Advice进来),因为Spring为我们提供了对应的实现:


image.png

实现也非常的简单,如下:


class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
  @Override
  public boolean supportsAdvice(Advice advice) {
    return (advice instanceof MethodBeforeAdvice);
  }
  @Override
  public MethodInterceptor getInterceptor(Advisor advisor) {
    MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
    return new MethodBeforeAdviceInterceptor(advice);
  }
}
// 都转为了AOP联盟的MethodInterceptor 从而实现拦截统一的拦截工作
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
  private MethodBeforeAdvice advice;
  /**
   * Create a new MethodBeforeAdviceInterceptor for the given advice.
   * @param advice the MethodBeforeAdvice to wrap
   */
  public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
    Assert.notNull(advice, "Advice must not be null");
    this.advice = advice;
  }
  @Override
  public Object invoke(MethodInvocation mi) throws Throwable {
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    // 最终调用,实现了链式调用的效果
    return mi.proceed();
  }
}


参考:AdvisorAdapterRegistry和DefaultAdvisorAdapterRegistry,GlobalAdvisorAdapterRegistry用于管理管理AdvisorAdapter的


如果我们想把自己定义的AdvisorAdapter注册到spring aop框架中,怎么办?

  1. 把我们自己写好得AdvisorAdapter放进Spring IoC容器中
  2. 配置一个AdvisorAdapterRegistrationManager,它是一个BeanPostProcessor,它会检测所有的Bean。若是AdvisorAdapter类型,就:this.advisorAdapterRegistry.registerAdvisorAdapter((AdvisorAdapter) bean);


TargetSource


该接口代表一个目标对象,在aop调用目标对象的时候,使用该接口返回真实的对象。

比如它有其中两个实现SingletonTargetSource和PrototypeTargetSource代表着每次调用返回同一个实例,和每次调用返回一个新的实例

TargetClassAware


所有的Aop代理对象或者代理工厂(proxy factory)都要实现的接口,该接口用于暴露出被代理目标对象类型;

public interface TargetClassAware {
  // 返回被代理得目标类型  AopUtils#getTargetClass(Object)
  @Nullable
  Class<?> getTargetClass();
}

AspectMetadata:Metadata for an AspectJ aspect class


表示一个切面的元数据类。


public class AspectMetadata implements Serializable {
  private final String aspectName;
  private final Class<?> aspectClass;
  // AjType这个字段非常的关键,它表示有非常非常多得关于这个切面的一些数据、方法(位于org.aspectj下)
  private transient AjType<?> ajType;
  // 解析切入点表达式用的,但是真正的解析工作为委托给`org.aspectj.weaver.tools.PointcutExpression`来解析的
  //若是单例:则是Pointcut.TRUE  否则为AspectJExpressionPointcut
  private final Pointcut perClausePointcut;
  public AspectMetadata(Class<?> aspectClass, String aspectName) {
    this.aspectName = aspectName;
    Class<?> currClass = aspectClass;
    AjType<?> ajType = null;
    // 此处会一直遍历到顶层知道Object  直到找到有一个是Aspect切面就行,然后保存起来
    // 因此我们的切面写在父类上 也是欧克的
    while (currClass != Object.class) {
      AjType<?> ajTypeToCheck = AjTypeSystem.getAjType(currClass);
      if (ajTypeToCheck.isAspect()) {
        ajType = ajTypeToCheck;
        break;
      }
      currClass = currClass.getSuperclass();
    }
    // 由此可见,我们传进来的Class必须是个切面或者切面的子类的~~~
    if (ajType == null) {
      throw new IllegalArgumentException("Class '" + aspectClass.getName() + "' is not an @AspectJ aspect");
    }
    // 显然Spring AOP目前也不支持优先级的声明。。。
    if (ajType.getDeclarePrecedence().length > 0) {
      throw new IllegalArgumentException("DeclarePrecendence not presently supported in Spring AOP");
    }
    this.aspectClass = ajType.getJavaClass();
    this.ajType = ajType;
    // 切面的处在类型:PerClauseKind  由此可议看出,Spring的AOP目前只支持下面4种 
    switch (this.ajType.getPerClause().getKind()) {
      case SINGLETON:
        // 如国是单例,这个表达式返回这个常量
        this.perClausePointcut = Pointcut.TRUE;
        return;
      case PERTARGET:
      case PERTHIS:
        // PERTARGET和PERTHIS处理方式一样  返回的是AspectJExpressionPointcut
        AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
        ajexp.setLocation(aspectClass.getName());
        //设置好 切点表达式
        ajexp.setExpression(findPerClause(aspectClass));
        ajexp.setPointcutDeclarationScope(aspectClass);
        this.perClausePointcut = ajexp;
        return;
      case PERTYPEWITHIN:
        // Works with a type pattern
        // 组成的、合成得切点表达式~~~
        this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass)));
        return;
      default:
        // 其余的Spring AOP暂时不支持
        throw new AopConfigException(
            "PerClause " + ajType.getPerClause().getKind() + " not supported by Spring AOP for " + aspectClass);
    }
  }
  private String findPerClause(Class<?> aspectClass) {
    String str = aspectClass.getAnnotation(Aspect.class).value();
    str = str.substring(str.indexOf('(') + 1);
    str = str.substring(0, str.length() - 1);
    return str;
  }
  ...
  public Pointcut getPerClausePointcut() {
    return this.perClausePointcut;
  }
  // 判断perThis或者perTarger,最单实例、多实例处理
  public boolean isPerThisOrPerTarget() {
    PerClauseKind kind = getAjType().getPerClause().getKind();
    return (kind == PerClauseKind.PERTARGET || kind == PerClauseKind.PERTHIS);
  }
  // 是否是within的
  public boolean isPerTypeWithin() {
    PerClauseKind kind = getAjType().getPerClause().getKind();
    return (kind == PerClauseKind.PERTYPEWITHIN);
  }
  // 只要不是单例的,就都属于Lazy懒加载,延迟实例化的类型~~~~
  public boolean isLazilyInstantiated() {
    return (isPerThisOrPerTarget() || isPerTypeWithin());
  }
}


Spring AOP切面实例化模型


Spring AOP支持AspectJ的singleton、perthis、pertarget、pertypewithin实例化模型(目前不支持percflow、percflowbelow) 参见枚举类PerClauseKind


  1. singleton:即切面只会有一个实例;
  2. perthis:每个切入点表达式匹配的连接点对应的AOP对象(代理对象)都会创建一个新切面实例;
  3. pertarget:每个切入点表达式匹配的连接点对应的目标对象都会创建一个新的切面实例
  4. pertypewithin:


默认是singleton实例化模型,Schema风格只支持singleton实例化模型,而@AspectJ风格支持这三种实例化模型


singleton:使用@Aspect()指定,即默认就是单例实例化模式,在此就不演示示例了

perthis:每个切入点表达式匹配的连接点对应的AOP代理对象都会创建一个新的切面实例,使用@Aspect("perthis(切入点表达式)")指定切入点表达式;

// 他将为每个被切入点表达式匹配上的代理对象,都创建一个新的切面实例(此处允许HelloService是接口)
@Aspect("perthis(this(com.fsx.HelloService))") 


pertarget:每个切入点表达式匹配的连接点对应的目标对象都会创建一个新的切面实例,使用@Aspect("pertarget(切入点表达式)")指定切入点表达式; 此处要求HelloService不能是接口


另外需要注意一点:若在Spring内要使用perthis和pertarget,请把切面的Scope定义为:prototype

AspectInstanceFactory:切面工厂


专门为切面创建实例的工厂(因为切面也不一定是单例的,也支持各种多例形式。上面已有说明)


// 它实现了Order接口哦~~~~支持排序的
public interface AspectInstanceFactory extends Ordered {
  //Create an instance of this factory's aspect.
  Object getAspectInstance();
  //Expose the aspect class loader that this factory uses.
  @Nullable
  ClassLoader getAspectClassLoader();
}


它的实现类如下:


image.png


SimpleAspectInstanceFactory:根据切面的aspectClass,调用空构造函数反射.newInstance()创建一个实例(备注:构造函数private的也没有关系)

SingletonAspectInstanceFactory:这个就更简单了,因为已经持有aspectInstance得引用了,直接return即可


MetadataAwareAspectInstanceFactory


AspectInstanceFactory的子接口。提供了获取AspectMetadata的方法

public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactory {
  AspectMetadata getAspectMetadata();
  // Spring4.3提供  和beanFactory.getSingletonMutex()  否则一般都是this
  Object getAspectCreationMutex();
}


SimpleMetadataAwareAspectInstanceFactory和SingletonMetadataAwareAspectInstanceFactory已经直接关联到AspectMetadata,所以直接return即可。

LazySingletonAspectInstanceFactoryDecorator也只是个简单的装饰而已。


BeanFactoryAspectInstanceFactory


这个就和Bean工厂有关了。比较重要


public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInstanceFactory, Serializable {
  // 持有对Bean工厂的引用
  private final BeanFactory beanFactory;
  // 需要处理的名称
  private final String name;
  private final AspectMetadata aspectMetadata;
  // 传了Name,type可议不传,内部判断出来
  public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name) {
    this(beanFactory, name, null);
  }
  public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name, @Nullable Class<?> type) {
    this.beanFactory = beanFactory;
    this.name = name;
    Class<?> resolvedType = type;
    // 若没传type,就去Bean工厂里看看它的Type是啥  type不能为null~~~~
    if (type == null) {
      resolvedType = beanFactory.getType(name);
      Assert.notNull(resolvedType, "Unresolvable bean type - explicitly specify the aspect class");
    }
    // 包装成切面元数据类
    this.aspectMetadata = new AspectMetadata(resolvedType, name);
  }
  // 此处:切面实例 是从Bean工厂里获取的  需要注意
  // 若是多例的,请注意Scope的值
  @Override
  public Object getAspectInstance() {
    return this.beanFactory.getBean(this.name);
  }
  @Override
  @Nullable
  public ClassLoader getAspectClassLoader() {
    return (this.beanFactory instanceof ConfigurableBeanFactory ?
        ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
        ClassUtils.getDefaultClassLoader());
  }
  @Override
  public AspectMetadata getAspectMetadata() {
    return this.aspectMetadata;
  }
  @Override
  @Nullable
  public Object getAspectCreationMutex() {
    if (this.beanFactory.isSingleton(this.name)) {
      // Rely on singleton semantics provided by the factory -> no local lock.
      return null;
    }
    else if (this.beanFactory instanceof ConfigurableBeanFactory) {
      // No singleton guarantees from the factory -> let's lock locally but
      // reuse the factory's singleton lock, just in case a lazy dependency
      // of our advice bean happens to trigger the singleton lock implicitly...
      return ((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex();
    }
    else {
      return this;
    }
  }
  @Override
  public int getOrder() {
    Class<?> type = this.beanFactory.getType(this.name);
    if (type != null) {
      if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {
        return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();
      }
      // 若没实现接口,就拿注解的值
      return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE);
    }
    return Ordered.LOWEST_PRECEDENCE;
  }
}


PrototypeAspectInstanceFactory:多例专用的工厂 若是多例的,推荐使用


public class PrototypeAspectInstanceFactory extends BeanFactoryAspectInstanceFactory implements Serializable {
  public PrototypeAspectInstanceFactory(BeanFactory beanFactory, String name) {
    super(beanFactory, name);
    // 若是单例,直接报错了
    if (!beanFactory.isPrototype(name)) {
      throw new IllegalArgumentException(
          "Cannot use PrototypeAspectInstanceFactory with bean named '" + name + "': not a prototype");
    }
  }
}

下面介绍下aspectj这个jar包下几个重要的类




相关文章
|
3月前
|
缓存 Java 开发者
【Spring】原理:Bean的作用域与生命周期
本文将围绕 Spring Bean 的作用域与生命周期展开深度剖析,系统梳理作用域的类型与应用场景、生命周期的关键阶段与扩展点,并结合实际案例揭示其底层实现原理,为开发者提供从理论到实践的完整指导。
494 22
|
3月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
1219 0
|
3月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
429 0
|
2月前
|
XML Java 数据格式
《深入理解Spring》:AOP面向切面编程深度解析
Spring AOP通过代理模式实现面向切面编程,将日志、事务等横切关注点与业务逻辑分离。支持注解、XML和编程式配置,提供五种通知类型及丰富切点表达式,助力构建高内聚、低耦合的可维护系统。
|
2月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
2月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
394 2
|
4月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
|
4月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
Java Spring
Spring原理学习系列之五:IOC原理之Bean加载
其实很多同学都想通过阅读框架的源码以汲取框架设计思想以及编程营养,Spring框架其实就是个很好的框架源码学习对象。我们都知道Bean是Spring框架的最小操作单元,Spring框架通过对于Bean的统一管理实现其IOC以及AOP等核心的框架功能,那么Spring框架是如何把Bean加载到环境中来进行管理的呢?本文将围绕这个话题进行详细的阐述,并配合Spring框架的源码解析。
Spring原理学习系列之五:IOC原理之Bean加载