一、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 ============环绕后==============

Spring5(七)——AOP注解的更多相关文章

  1. Spring详解(七)------AOP 注解

    上一篇博客我们讲解了 AspectJ 框架如何实现 AOP,然后具体的实现方式我们是通过 xml 来进行配置的.xml 方式思路清晰,便于理解,但是书写过于麻烦.这篇博客我们将用 注解 的方式来进行 ...

  2. 来一手 AOP 注解方式进行日志记录

    系统日志对于定位/排查问题的重要性不言而喻,相信许多开发和运维都深有体会. 通过日志追踪代码运行状况,模拟系统执行情况,并迅速定位代码/部署环境问题. 系统日志同样也是数据统计/建模的重要依据,通过分 ...

  3. Spring详解(六)------AOP 注解

    上一篇博客我们讲解了 AspectJ 框架如何实现 AOP,然后具体的实现方式我们是通过 xml 来进行配置的.xml 方式思路清晰,便于理解,但是书写过于麻烦.这篇博客我们将用 注解 的方式来进行 ...

  4. SpringBoot —— AOP注解式拦截与方法规则拦截

    AspectJ是一个面向切面的框架,它扩展了Java语言.AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件. SpringBoot中AOP的使用 ...

  5. Spring AOP注解为什么失效?90%Java程序员不知道

    使用Spring Aop注解的时候,如@Transactional, @Cacheable等注解一般需要在类方法第一个入口的地方加,不然不会生效. 如下面几种场景 1.Controller直接调用Se ...

  6. Spring入门(三)— AOP注解、jdbc模板、事务

    一.AOP注解开发 导入jar包 aop联盟包. aspectJ实现包 . spring-aop-xxx.jar . spring-aspect-xxx.jar 导入约束 aop约束 托管扩展类和被扩 ...

  7. SpringBoot整合Mybatis多数据源 (AOP+注解)

    SpringBoot整合Mybatis多数据源 (AOP+注解) 1.pom.xml文件(开发用的JDK 10) <?xml version="1.0" encoding=& ...

  8. Spring AOP注解形式简单实现

    实现步骤: 1:导入类扫描的注解解析器 命名空间:xmlns:context="http://www.springframework.org/schema/context" xsi ...

  9. AOP注解不起作用的debug结果

    经过2天的调试,我发现AOP注解配置不起作用居然是表达式的错误导致的 在xml文件中配置的base-package有关,初步认为@PointCut只能使用base-package..*(..)这样的方 ...

  10. Spring aop注解失效

    问题 在spring 中使用 @Transactional . @Cacheable 或 自定义 AOP 注解时,对象内部方法中调用该对象的其他使用aop机制的方法会失效. @Transactiona ...

随机推荐

  1. H2

    0.近期写了一个模拟数据接口,不想采用大型数据库,于是在同事的推荐下用了H2,简要记录. 1.  H2简介(摘自H2官网:http://www.h2database.com/html/main.htm ...

  2. iOS开发网络篇—GET请求和POST请求(转)

    一.GET请求和POST请求简单说明 创建GET请求 1 // 1.设置请求路径 2 NSString *urlStr=[NSString stringWithFormat:@"http:/ ...

  3. C#堆栈和托管堆

    首先堆栈和堆(托管堆)都在进程的虚拟内存中.(在32位处理器上每个进程的虚拟内存为4GB) 堆栈stack 堆栈中存储值类型. 堆栈实际上是向下填充,即由高内存地址指向低内存地址填充. 堆栈的工作方式 ...

  4. hihocoder 1037 数字三角形

    #1037 : 数字三角形 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 问题描述 小Hi和小Ho在经历了螃蟹先生的任务之后被奖励了一次出国旅游的机会,于是他们来到了大洋彼岸 ...

  5. Spark RDD概念学习系列之Spark的数据存储(十二)

    Spark数据存储的核心是弹性分布式数据集(RDD). RDD可以被抽象地理解为一个大的数组(Array),但是这个数组是分布在集群上的. 逻辑上RDD的每个分区叫一个Partition. 在Spar ...

  6. ODI性能问题

        在这里分析下最近分析和解决ODI性能问题的点滴,用作参考.在介入该问题前,已经具备的基础知识包括了ODI基础,SOA理论和实施,特别是04年封闭四天的informatic ETL培训和实操.几 ...

  7. 高通MSM8998 ABL的调试

    高通在MSM8998上引入了UEFI,用来代替LK(Little Kernel).高通UEFI由XBL和ABL两部分组成.XBL负责芯片驱动及充电等核心应用功能.ABL包括芯片无关的应用如fastbo ...

  8. ionic3 Loading组件的用法

    import { LoadingController } from 'ionic-angular'; @Component({ selector: 'page-contact', templateUr ...

  9. 最短路算法模板--SPFA

    初见SPFA时,直接认成了优先队列优化的Dijkstra,经过几位大佬的指点,我终于明白了他们的差异. Dijkstra是保证已经出队过的点不再入队,SPFA是已经在队列中不再入队.比较起来,SPFA ...

  10. 使用SUI框架下的&lt;a&gt;标签点击跳转页面不刷新的问题

    最近写好了几个页面,今天试着将各个页面的链接打通,然后问题就来了...(╯︵╰) 这里看一下原来想要实现的两个页面跳转的效果--点击图一标注的栏目可以跳转到一个新的页面图二... 按照之前写a标签的跳 ...