Spring(十五)Spring AOP 初窥

AOP: 面向切面编程(Aspect Oriented Programming),和Java结构中的OOP是截然不同两种的逻辑,可以理解为是对OOP的一种补充,对程序结构的另一种思考。
在OOP的一等公民是类(Class),而在AOP中则是切面(Aspect),AOP典型应用就是事务管理器。
其实在Spring IoC 容器并不依赖于AOP,所以你可以在IoC中不使用AOP,但是在 Spring 使用AOP 提供了非常方面的支持。
本文将简单介绍AOP用法,包括各个名词定义与举例。

本文大部分知识点,来源于Spring 官方文档:https://docs.spring.io/spring/docs/2.5.x/reference/aop.html

例子

下面是在Spring 中,定义一个切面:

@Aspect
public class WorldAop implements Ordered {
    @Pointcut("execution(* com.anla.springaop.service.*.*(..))")
    private void returnPointcut() {
    }

    @Before("returnPointcut()")
    public void doBefore(JoinPoint joinPoint) {
        String apiName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        System.out.println("========== 调用方法WorldAop:{} start ==========, " + apiName);
        for (Object arg : joinPoint.getArgs()) {
            System.out.println("arg:," + arg);
        }
        System.out.println("========== 调用方法WorldAop:{} end ==========, " + apiName);
    }

    @Around("returnPointcut()")
    public Object interceptor(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("pjp is :" + pjp);
        return pjp.proceed();
    }

    @Override
    public int getOrder() {
        return 10;
    }
}

@Aspect

@Aspect 注解,表明这个类是个切面。
例如:

@Aspect
public class NotVeryUsefulAspect {

}

@Pointcut

@Pointcut 定义一个切入点,可以理解为正则表达式,即类方法方法执行点的表达式。

实际上,AOP切点支持在任意位置切入,但是Spring AOP 只支持部分 PointCut表达式:

  • execution 用于匹配方法的切入点
  • within 限制切点为某一些特定的类型。即对Spring 切入点的所有方法
  • this 限定当前执行的方法的 bean实例 是某一种类型
  • target 限制执行放的类型是某一种类型,和上一种来说是对比方法不同,使用this和使用target。
  • args 限制执行的方法,参数是怎样的
  • @target: 限制切入点,这个类具有某一种类型的注解
  • @args: 限制方法的参数,是使用什么样的注解
  • @within:
  • @annotation: 限制切入点,方法有 这个注解时候会被拦截

执行阶段切面

这里包括这几种注解:@Before, @AfterReturning, @AfterThrowing , @Around等几种。
分别是代表 方法执行前后的逻辑(@Before, @AfterReturning),以及 报错后的逻辑@AfterThrowing
方法执行前后的逻辑,包括前和后 @Around
例如 下面 @Around 例子:

@Aspect
public class ConcurrentOperationExecutor implements Ordered {
   private static final int DEFAULT_MAX_RETRIES = 2;
   private int maxRetries = DEFAULT_MAX_RETRIES;
   private int order = 1;
   public void setMaxRetries(int maxRetries) {
      this.maxRetries = maxRetries;
   }
   public int getOrder() {
      return this.order;
   }
   
   public void setOrder(int order) {
      this.order = order;
   }
   // Around 类型切面
   @Around("com.xyz.myapp.SystemArchitecture.businessService()")
   public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable { 
      int numAttempts = 0;
      PessimisticLockingFailureException lockFailureException;
      do {
         numAttempts++;
         try { 
            return pjp.proceed();
         }
         catch(PessimisticLockingFailureException ex) {
            lockFailureException = ex;
         }
      }
      while(numAttempts <= this.maxRetries);
      throw lockFailureException;
   }

}

如果切面需要状态?

如果切面不是单例的,需要状态怎么做?
例如熔断降级,需要监控每一个方法,他们有不同状态,Spring AOP提供了一种基于类似于原型模式方法:

@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
public class MyAspect {

  private int someState;
	
  @Before(com.xyz.myapp.SystemArchitecture.businessService())
  public void recordServiceUsage() {
    // ...
  }
  	
}

即使用 @Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())") 这种方式去声明一个切面,那么每一个切入点都会有一个切面了。

参考:

  1. https://docs.spring.io/spring/docs/2.5.x/reference/aop.html
  2. 一些自定义 的 AOP

觉得博主写的有用,不妨关注博主公众号: 六点A君。
哈哈哈,一起研究Spring:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章