【小家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包下几个重要的类




相关文章
|
7天前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
11天前
|
Java
Java的aop是如何实现的?原理是什么?
Java的aop是如何实现的?原理是什么?
15 4
|
21天前
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理
|
2月前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
23 0
Spring高手之路22——AOP切面类的封装与解析
|
2月前
|
Java Spring XML
掌握面向切面编程的秘密武器:Spring AOP 让你的代码优雅转身,横切关注点再也不是难题!
【8月更文挑战第31天】面向切面编程(AOP)通过切面封装横切关注点,如日志记录、事务管理等,使业务逻辑更清晰。Spring AOP提供强大工具,无需在业务代码中硬编码这些功能。本文将深入探讨Spring AOP的概念、工作原理及实际应用,展示如何通过基于注解的配置创建切面,优化代码结构并提高可维护性。通过示例说明如何定义切面类、通知方法及其应用时机,实现方法调用前后的日志记录,展示AOP在分离关注点和添加新功能方面的优势。
38 0
|
2月前
|
缓存 安全 Java
Spring AOP 中两种代理类型的限制
【8月更文挑战第22天】
16 0
|
2月前
|
Java Spring
|
Java Spring
Spring原理学习系列之六:IOC原理之BeanDefinition注册
本文主要介绍了BeanDefinition以及BeanDefinition的注册,BeanDefinition是Spring处理Bean的统一的数据结构,BeanDefinitionRegistry的实现类对BeanDefinition完成了注册操作,注册最终结果保存在beanDefinitionMap这个ConcurrentHashMap中。今天的内容就到这里了,我们下次再会了哦。
Spring原理学习系列之六:IOC原理之BeanDefinition注册
|
7天前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
2月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
下一篇
无影云桌面