zoukankan      html  css  js  c++  java
  • Spring5(七)——AOP注解

    一、AOP注解

    1、介绍

      上一节介绍了 AspectJ 框架如何实现 AOP,具体的实现方式是通过 xml 来进行配置的。xml 方式思路清晰,便于理解,但是书写过于麻烦。这一节介绍注解的方式来进行 AOP 配置。

    2、案例(注解)

      定义目标对象(被代理的对象)

     1 // 定义一个接口
     2 public interface ITeacher {
     3     void teach();
     4     int add(int i, int j);
     5 }
     6 
     7 // 定义目标对象
     8 @Service
     9 public class Teacher implements ITeacher {
    10     @Override
    11     public void teach() {
    12         System.out.println("老师正在上课");
    13     }
    14 
    15     @Override
    16     public int add(int i, int j) {
    17         int add = i + j;
    18         System.out.println("执行目标方法:老师正在做加法,结果为:" + add);
    19         // int throwable = 10 / 0; 测试异常通知
    20         return add;
    21     }
    22 
    23     // 目标对象自己的方法,此方法不是接口所以无法代理
    24     public void sayHello() {
    25         System.out.println("老师会说hello");
    26     }
    27 
    28 }

      编写一个切面类(通知)

     1 // 创建切面类(包含各种通知)
     2 @Component
     3 @Aspect
     4 public class MyAspect {
     5 
     6     // 1.先定义切入点表达式
     7     @Pointcut("execution(* com.lx.spring.day4.ITeacher.*(..))")
     8     private void myPointcut() {
     9 
    10     }
    11 
    12     // 2.标识此方法为一个前置通知,用来切满足后面切点表达式的方法
    13     @Before("myPointcut()")
    14     public void myBefore(JoinPoint joinPoint) {
    15         System.out.println("前置通知:方法增强myBefore()" + " , -->" + joinPoint.getSignature().getName());
    16     }
    17 
    18     @AfterReturning(value = "myPointcut()", returning = "object")
    19     public void myAfterReturning(JoinPoint joinPoint, Object object) {
    20         System.out.println("后置通知:方法增强myAfterReturning()" + " , -->" + joinPoint.getSignature().getName() + " , -->" + object);
    21     }
    22 
    23     public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
    24         System.out.println("============环绕前==============");
    25         Object obj = joinPoint.proceed(); // 手动执行目标方法
    26         System.out.println("============环绕后==============");
    27         return obj;
    28     }
    29 
    30     public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
    31         System.out.println("抛出异常通知:" + e.getMessage());
    32     }
    33 
    34     public void myAfter() {
    35         System.out.println("最终通知:方法增强myAfter()");
    36     }
    37 
    38 }

      编写配置文件 application.xml

    1 <!-- 1.自动扫描(自动注入bean) -->
    2 <context:component-scan base-package="com.lx.spring.day4"/>
    3 
    4 <!-- 2.扫描 @Aspect 告诉 spring 这是一个切面类 -->
    5 <aop:aspectj-autoproxy/>
     1 // 测试类
     2 public class Main {
     3     public static void main(String[] args) {
     4         ApplicationContext app = new ClassPathXmlApplicationContext("app4.xml");
     5         ITeacher iTeacher = app.getBean(ITeacher.class);
     6 
     7         iTeacher.add(11, 24);
     8     }
     9 }
    10 
    11 // 结果
    12 前置通知:方法增强myBefore() , -->add
    13 执行目标方法:老师正在做加法,结果为:35
    14 后置通知:方法增强myAfterReturning() , -->add , -->35

      说明:对比 xml 的配置,不难理解注解的方式。

      @Service @Component
      <context:component-scan base-package="com.lx.spring.day4"/>

      用于 Spring 扫描并注册bean。

      @Aspect:指明这是一个切面类
      <aop:aspectj-autoproxy/>:开启切面注解扫描

    3、优先级

      有多个增强类对同一个方法进行增强,设置增强类优先级,在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高。

    1 @Component
    2 @Aspect
    3 @Order(1)
    4 public class MyAspect2 {}

      优先级:这里的优先级,只会影响两个增强类对应的方法,执行的先后顺序。并不会只执行优先级高的。

    二、AOP+自定义注解

      通过AOP+自定义注解的方式,可以实现前面说的抽取公共非业务模块,对业务逻辑的增强。比如:

      需求:①想要对业务逻辑层的所有方法,打印出入参和出参,做日志管理。②对业务逻辑层的方法入口,开启事务,逻辑执行后,提交事务,等。

      自定义注解

    1 // 用于日志打印
    2 @Target({ElementType.METHOD})
    3 @Retention(RetentionPolicy.RUNTIME)
    4 @Documented
    5 public @interface Log {
    6 
    7     String value() default "";
    8 }
      编写切面类(通知)
     1 @Component
     2 @Aspect
     3 public class MyAspect {
     4 
     5     // 定义切入点为 有注解Log的方法
     6     @Pointcut("@annotation(com.lx.spring.day5.Log) ")
     7     private void myLogPointcut() {
     8 
     9     }
    10     
    11     // 为切入点增强一个环绕通知,可以在这里写打印入参出参的逻辑
    12     @Around("myLogPointcut()")
    13     public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
    14         System.out.println("============环绕前==============");
    15         Object obj = joinPoint.proceed(); // 手动执行目标方法
    16         System.out.println("============环绕后==============");
    17         return obj;
    18     }
    19 
    20 }
      在相应的方法上加注解
     1 @Service
     2 public class Teacher implements ITeacher {
     3 
     4     // 为需要打印入参出参的方法 加上@Log注解即可
     5     @Log
     6     @Override
     7     public int add(int i, int j) {
     8         int add = i + j;
     9         System.out.println("执行目标方法:老师正在做加法,结果为:" + add);
    10         // int throwable = 10 / 0; 测试异常通知
    11         return add;
    12     }
    13 
    14 }
      测试类
     1 public class Main {
     2     public static void main(String[] args) {
     3         ApplicationContext app = new ClassPathXmlApplicationContext("app4.xml");
     4         ITeacher iTeacher = app.getBean(ITeacher.class);
     5 
     6         iTeacher.add(11, 24);
     7     }
     8 }
     9 
    10 // 结果
    11 ============环绕前==============
    12 执行目标方法:老师正在做加法,结果为:35
    13 ============环绕后==============

    作者:Craftsman-L

    本博客所有文章仅用于学习、研究和交流目的,版权归作者所有,欢迎非商业性质转载。

    如果本篇博客给您带来帮助,请作者喝杯咖啡吧!点击下面打赏,您的支持是我最大的动力!

  • 相关阅读:
    从U盘安装Windows 7 / Vista / 2008
    Windows 7 Enterprise 微软官方90天评估序列号
    Windows 2008 Vista 安装sp2后释放C盘空间
    Windows 7 一年试用批处理
    Windows 2008 R2 试用版序列号
    又出来一个OEM的序列号
    查看 windows 7 激活信息的相关命令
    最新一组OEM Key
    Windows 7 / Vista 分区问题
    MSN 9 多开设置
  • 原文地址:https://www.cnblogs.com/originator/p/15271248.html
Copyright © 2011-2022 走看看