aop中的@within,@Pointcut,@annotation

AOP

面向切面编程,日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术,在不改变原有代码的情况下 , 去增加新的功能

名词

  • 切面(Aspect):横切关注点 被模块化 的特殊对象。是一个,提供API
  • 通知(Advice):它是类中的方法
  • 目标(Target):被一个或多个方面通知对象
  • 代理(Proxy):向目标对象应用通知之后创建的对象
  • 连接点(JointPoint):被拦截到的方法
  • 切入点(PointCut):代理对象执行方法时,通知执行的地点
  • 织入(weaving) 把切面应用到目标对象 ,创建新的代理对象 的过程

依赖

<!-- AOP-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

execution()

是最常用的切点函数

("execution(* com.aop..*.*(..))")
1、execution(): 表达式主体
2、第一个*号:表示返回类型,*号表示所有的类型
3、.包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包
4、第二个*号:表示类名,号表示所有的类
5、.*(..):最后这个星号表示方法名,号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数

@within

@Component
@Aspect
public class HttpAccessAspect {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Around("@within(org.springframework.stereotype.Controller)" +
            "|| @within(org.springframework.web.bind.annotation.RestController)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        // <1.1> 获取类名
        String className = point.getTarget().getClass().getName();
        // <1.2> 获取方法
        String methodName = point.getSignature().getName();
        // <1.3> 记录开始时间
        long beginTime = System.currentTimeMillis();
        // 记录返回结果
        Object result = null;
        Exception ex = null;
        try {
            // <2.1> 执行方法
            result = point.proceed();
            return result;
        } catch (Exception e) {
            // <2.2> 记录异常
            ex = e;
            throw e;
        } finally {
            // <3.1> 计算消耗时间
            long costTime = System.currentTimeMillis() - beginTime;
            // <3.2> 发生异常,则打印 ERROR 日志
            if (ex != null) {
                this.logger.error("[className: {}][methodName: {}][cost: {} ms][errorMessage: {}]",
                        className, methodName, point.getArgs(), ex.getMessage(), ex);
                // <3.3> 正常执行,则打印 INFO 日志
            } else {
                this.logger.info("[className: {}][methodName: {}][cost: {} ms][args: {}][return: {}]",
                        className, methodName, costTime, point.getArgs(), result);
            }
        }
    }

}


@within(org.springframework.stereotype.Controller // 所有Controller
@within(org.springframework.web.bind.annotation.RestController// 所有RestController
        
@within(org.springframework.stereotype.Service) // 所有@Service
@within(@org.springframework.stereotype.Service com.abc.*) // com.abc下所有@Service

@Pointcut

@Aspect
public class Logging {

   @Pointcut("execution(* com.tutorialspoint.*.*(..))")
   private void selectAll(){}
  
   @Before("selectAll()")
   public void beforeAdvice(){
      System.out.println("Going to setup student profile.");
   }
  
   @After("selectAll()")
   public void afterAdvice(){
      System.out.println("Student profile has been setup.");
   }
  
   @AfterReturning(pointcut = "selectAll()", returning="retVal")
   public void afterReturningAdvice(Object retVal){
      System.out.println("Returning:" + retVal.toString() );
   }
  
   @AfterThrowing(pointcut = "selectAll()", throwing = "ex")
   public void AfterThrowingAdvice(IllegalArgumentException ex){
      System.out.println("There has been an exception: " + ex.toString());   
   }  
}

@annotation

@Retention(RetentionPolicy.RUNTIME)//运行时有效
@Target(ElementType.METHOD)//作用于方法
public @interface MyAnnotation {
    String methodName () default "";
}
@Aspect@Componentpublic class AspectTest {    // 切面类中定义增强,pointcut连接点使用@annotation(xxx)进行定义    
    @Around(value = "@annotation(around)") //around 与 下面参数名around对应 
    public void processAuthority(ProceedingJoinPoint point, MyAnnotation around) throws Throwable{       
    System.out.println("ANNOTATION welcome");        System.out.println("ANNOTATION 调用方法:"+ around.methodName());        System.out.println("ANNOTATION 调用类:" + point.getSignature().getDeclaringTypeName());        System.out.println("ANNOTATION 调用类名" + point.getSignature().getDeclaringType().getSimpleName());        point.proceed(); //调用目标方法        
    System.out.println("ANNOTATION login success");    }}
@Controller
@RequestMapping("/hello")
public class AspectController {

    @RequestMapping("/login/{name}")
    @MyAnnotation(methodName = "login")
    @ResponseBody
    public String login(@PathVariable String name){
        System.out.println("hello!"+name);
        return "aspect ok";
    }
}
ANNOTATION welcome
ANNOTATION 调用方法:login
ANNOTATION 调用类:com.example.demo.controller.AspectController
ANNOTATION 调用类名AspectController
hello!aaa
ANNOTATION login success

@Around的argNames



版权声明:本文为huang6chen6原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。