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

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

介绍org.aspectj包下的几个类(单独导入的Jar包)


AjTypeSystem:从@Aspect的Class到AjType的工具类


public class AjTypeSystem {
    // 每个切面都给缓存上   注意:此处使用的是WeakReference 一定程度上节约内存
    private static Map<Class, WeakReference<AjType>> ajTypes = 
      Collections.synchronizedMap(new WeakHashMap<Class,WeakReference<AjType>>());
    public static <T> AjType<T> getAjType(Class<T> fromClass) {
      WeakReference<AjType> weakRefToAjType =  ajTypes.get(fromClass);
      if (weakRefToAjType!=null) {
        AjType<T> theAjType = weakRefToAjType.get();
        if (theAjType != null) {
          return theAjType;
        } else {
          // 其实只有这一步操作:new AjTypeImpl~~~  AjTypeImpl就相当于代理了Class的很多事情~~~~
          theAjType = new AjTypeImpl<T>(fromClass);
          ajTypes.put(fromClass, new WeakReference<AjType>(theAjType));
          return theAjType;
        }
      }
      // neither key nor value was found
      AjType<T> theAjType =  new AjTypeImpl<T>(fromClass);
      ajTypes.put(fromClass, new WeakReference<AjType>(theAjType));
      return theAjType;
    }
}


AjType


// 它继承自Java得Type和AnnotatedElement  它自己还提供了非常非常多的方法,基本都是获取元数据的一些方法,等到具体使用到的时候再来看也可以
public interface AjType<T> extends Type, AnnotatedElement {
  ...
}


AjTypeImpl


AjTypeImpl是AjType的唯一实现类,因为方法实在是太多了,因此下面我只展示一些觉得比较有意思的方法实现:


public class AjTypeImpl<T> implements AjType<T> {
  private static final String ajcMagic = "ajc$";
  // 它真正传进来的,只是这个class,它是一个标注了@Aspect注解的Class类
  private Class<T> clazz;
  private Pointcut[] declaredPointcuts = null;
  private Pointcut[] pointcuts = null;
  private Advice[] declaredAdvice = null;
  private Advice[] advice = null;
  private InterTypeMethodDeclaration[] declaredITDMethods = null;
  private InterTypeMethodDeclaration[] itdMethods = null;
  private InterTypeFieldDeclaration[] declaredITDFields = null;
  private InterTypeFieldDeclaration[] itdFields = null;
  private InterTypeConstructorDeclaration[] itdCons = null;
  private InterTypeConstructorDeclaration[] declaredITDCons = null;
  // 唯一的一个构造函数
  public AjTypeImpl(Class<T> fromClass) {
    this.clazz = fromClass;
  }
  // 这个方法有意思的地方在于:它把所有的接口类,都变成AjType类型了
  public AjType<?>[] getInterfaces() {
    Class<?>[] baseInterfaces = clazz.getInterfaces();
    return toAjTypeArray(baseInterfaces);
  }
  private AjType<?>[] toAjTypeArray(Class<?>[] classes) {
    AjType<?>[] ajtypes = new AjType<?>[classes.length];
    for (int i = 0; i < ajtypes.length; i++) {
      ajtypes[i] = AjTypeSystem.getAjType(classes[i]);
    }
    return ajtypes;
  }
  // 就是把clazz返回出去
  public Class<T> getJavaClass() {
    return clazz;
  }
  public AjType<? super T> getSupertype() {
    Class<? super T> superclass = clazz.getSuperclass();
    return superclass==null ? null : (AjType<? super T>) new AjTypeImpl(superclass);
  }
  // 判断是否是切面,就看是否有这个注解~~
  public boolean isAspect() {
    return clazz.getAnnotation(Aspect.class) != null;
  }
  // 这个方法很重要:PerClause AspectJ切面的表现形式
  // 备注:虽然有这么多(参考这个类PerClauseKind),但是Spring AOP只支持前三种~~~
  public PerClause getPerClause() {
    if (isAspect()) {
      Aspect aspectAnn = clazz.getAnnotation(Aspect.class);
      String perClause = aspectAnn.value();
      if (perClause.equals("")) {
        // 如果自己没写,但是存在父类的话并且父类是切面,那就以父类的为准~~~~
        if (getSupertype().isAspect()) {
          return getSupertype().getPerClause();
        } 
        // 不写默认是单例的,下面的就不一一解释了
        return new PerClauseImpl(PerClauseKind.SINGLETON);
      } else if (perClause.startsWith("perthis(")) {
        return new PointcutBasedPerClauseImpl(PerClauseKind.PERTHIS,perClause.substring("perthis(".length(),perClause.length() - 1));
      } else if (perClause.startsWith("pertarget(")) {
        return new PointcutBasedPerClauseImpl(PerClauseKind.PERTARGET,perClause.substring("pertarget(".length(),perClause.length() - 1));       
      } else if (perClause.startsWith("percflow(")) {
        return new PointcutBasedPerClauseImpl(PerClauseKind.PERCFLOW,perClause.substring("percflow(".length(),perClause.length() - 1));               
      } else if (perClause.startsWith("percflowbelow(")) {
        return new PointcutBasedPerClauseImpl(PerClauseKind.PERCFLOWBELOW,perClause.substring("percflowbelow(".length(),perClause.length() - 1));
      } else if (perClause.startsWith("pertypewithin")) {
        return new TypePatternBasedPerClauseImpl(PerClauseKind.PERTYPEWITHIN,perClause.substring("pertypewithin(".length(),perClause.length() - 1));        
      } else {
        throw new IllegalStateException("Per-clause not recognized: " + perClause);
      }
    } else {
      return null;
    }
  }
  public AjType<?>[] getAjTypes() {
    Class[] classes = clazz.getClasses();
    return toAjTypeArray(classes);
  }
  public Field getDeclaredField(String name) throws NoSuchFieldException {
    Field f =  clazz.getDeclaredField(name);
    if (f.getName().startsWith(ajcMagic)) throw new NoSuchFieldException(name);
    return f;
  }
  // 这个有点意思:表示标注了@Before、@Around注解的并不算真的方法了,不会给与返回了
  public Method[] getMethods() {
    Method[] methods = clazz.getMethods();
    List<Method> filteredMethods = new ArrayList<Method>();
    for (Method method : methods) {
      if (isReallyAMethod(method)) filteredMethods.add(method);
    }
    Method[] ret = new Method[filteredMethods.size()];
    filteredMethods.toArray(ret);
    return ret;
  }
  private boolean isReallyAMethod(Method method) {
    if (method.getName().startsWith(ajcMagic)) return false;
    if (method.getAnnotations().length==0) return true;
    if (method.isAnnotationPresent(org.aspectj.lang.annotation.Pointcut.class)) return false;
    if (method.isAnnotationPresent(Before.class)) return false;
    if (method.isAnnotationPresent(After.class)) return false;
    if (method.isAnnotationPresent(AfterReturning.class)) return false;
    if (method.isAnnotationPresent(AfterThrowing.class)) return false;
    if (method.isAnnotationPresent(Around.class)) return false;
    return true;
  }
  // 拿到所有的Pointcut方法  并且保存缓存起来
  public Pointcut[] getDeclaredPointcuts() {
    if (declaredPointcuts != null) return declaredPointcuts;
    List<Pointcut> pointcuts = new ArrayList<Pointcut>();
    Method[] methods = clazz.getDeclaredMethods();
    for (Method method : methods) {
      Pointcut pc = asPointcut(method);
      if (pc != null) pointcuts.add(pc);
    }
    Pointcut[] ret = new Pointcut[pointcuts.size()];
    pointcuts.toArray(ret);
    declaredPointcuts = ret;
    return ret;
  }
  // 标注有org.aspectj.lang.annotation.Pointcut这个注解的方法。  相当于解析这个注解吧,最终包装成一个PointcutImpl
  // 主义:Spring-aop也有个接口Pointcut,这里也有一个Pointcut接口  注意别弄混了
  private Pointcut asPointcut(Method method) {
    org.aspectj.lang.annotation.Pointcut pcAnn = method.getAnnotation(org.aspectj.lang.annotation.Pointcut.class);
    if (pcAnn != null) {
      String name = method.getName();
      if (name.startsWith(ajcMagic)) {
        // extract real name
        int nameStart = name.indexOf("$$");
        name = name.substring(nameStart +2,name.length());
        int nextDollar = name.indexOf("$");
        if (nextDollar != -1) name = name.substring(0,nextDollar);
      }
      return new PointcutImpl(name,pcAnn.value(),method,AjTypeSystem.getAjType(method.getDeclaringClass()),pcAnn.argNames());
    } else {
      return null;
    }
  }
  // 最终返回的对象为AdviceImpl实现类
  public Advice[] getDeclaredAdvice(AdviceKind... ofType) { ... }
  public Advice[] getAdvice(AdviceKind... ofType) { ... }
  private void initDeclaredAdvice() {
    Method[] methods = clazz.getDeclaredMethods();
    List<Advice> adviceList = new ArrayList<Advice>();
    for (Method method : methods) {
      Advice advice = asAdvice(method);
      if (advice != null) adviceList.add(advice);
    }
    declaredAdvice = new Advice[adviceList.size()];
    adviceList.toArray(declaredAdvice);
  }
  // 标注了各个注解的 做对应的处理
  private Advice asAdvice(Method method) {
    if (method.getAnnotations().length == 0) return null;
    Before beforeAnn = method.getAnnotation(Before.class);
    if (beforeAnn != null) return new AdviceImpl(method,beforeAnn.value(),AdviceKind.BEFORE);
    After afterAnn = method.getAnnotation(After.class);
    if (afterAnn != null) return new AdviceImpl(method,afterAnn.value(),AdviceKind.AFTER);
    AfterReturning afterReturningAnn = method.getAnnotation(AfterReturning.class);
    if (afterReturningAnn != null) {
      // 如果没有自己指定注解pointcut()的值,那就取值为value的值吧~~~
      String pcExpr = afterReturningAnn.pointcut();
      if (pcExpr.equals("")) pcExpr = afterReturningAnn.value();
      // 会把方法的返回值放进去、下同。。。   这就是@After和@AfterReturning的区别的原理
      // 它可议自定义自己的切点表达式咯
      return new AdviceImpl(method,pcExpr,AdviceKind.AFTER_RETURNING,afterReturningAnn.returning());
    }
    AfterThrowing afterThrowingAnn = method.getAnnotation(AfterThrowing.class);
    if (afterThrowingAnn != null) {
      String pcExpr = afterThrowingAnn.pointcut();
      if (pcExpr == null) pcExpr = afterThrowingAnn.value();
      return new AdviceImpl(method,pcExpr,AdviceKind.AFTER_THROWING,afterThrowingAnn.throwing());
    }
    Around aroundAnn = method.getAnnotation(Around.class);
    if (aroundAnn != null) return new AdviceImpl(method,aroundAnn.value(),AdviceKind.AROUND);
    return null;
  }
  // 必须不是切面才行哦~~~~
  public boolean isLocalClass() {
    return clazz.isLocalClass() && !isAspect();
  }
  public boolean isMemberClass() {
    return clazz.isMemberClass() && !isAspect();
  }
  // 内部类也是能作为切面哒  哈哈
  public boolean isMemberAspect() {
    return clazz.isMemberClass() && isAspect();
  }
  public String toString() { return getName(); }
}


总结


工欲善其事必先利其器,任何负责的框架、业务也好。都是由一部分一部分的组件组合而成的。本文主旨就是单独把组件拆出来讲解,逐个击破~~


相关文章
|
3月前
|
缓存 Java 开发者
【Spring】原理:Bean的作用域与生命周期
本文将围绕 Spring Bean 的作用域与生命周期展开深度剖析,系统梳理作用域的类型与应用场景、生命周期的关键阶段与扩展点,并结合实际案例揭示其底层实现原理,为开发者提供从理论到实践的完整指导。
509 22
|
3月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
1306 0
|
3月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
457 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,那么就进来看看吧!
424 2
|
4月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
|
4月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
4月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。

热门文章

最新文章