AOP:面向切面编程【底层使用动态代理实现】,就是在运行期间动态的将某段代码切入到方法的指定位置进行运行的编程方式

基本使用

  1. 使用AOP功能需要引入spring的aop以及aspects相关包

    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.6.RELEASE</version>
    </dependency> <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.0.6.RELEASE</version>
    </dependency> 
  2. 定义逻辑类
    public class TestService {
    public int service(int i, int j){
    System.out.println(".........service........");
    return i/j;
    }
    }
  3. 定义切面类
    @Aspect//声明该类是切面类
    public class MyAspectJ { /**
    * @Before
    * 前置通知:在目标方法(service)运行之前运行
    */
    @Before("execution(public int com.enjoy.study.cap13.TestService.service(int,int))")
    public void logStart(){
    System.out.println("@Before目标方法执行前");
    } /**
    * @After
    * 后置通知:在目标方法(service)运行结束之后运行,无论正常或异常结束
    */
    @After("execution(public int com.enjoy.study.cap13.TestService.service(int,int))")
    public void logEnd(){
    System.out.println("@After目标方法执行后");
    } /**
    * @AfterReturning
    * 返回通知:在目标方法(service)正常返回之后运行
    */
    @AfterReturning("execution(public int com.enjoy.study.cap13.TestService.service(int,int))")
    public void logReturn() {
    System.out.println("@AfterReturning目标方法执行后返回"); } /**
    * @AfterThrowing
    * 异常通知:在目标方法(service)出现异常后运行
    */
    @AfterThrowing("execution(public int com.enjoy.study.cap13.TestService.service(int,int))")
    public void logThrowing(){
    System.out.println("@AfterThrowing目标方法执行出现异常");
    } /**
    * @Around
    * 环绕通知:动态代理,手动执行目标方法运行joinPoint.procced(),最底层通知,手动指定执行目标方法,
    * 执行之前相当于前置通知, 执行之后相当于返回通知,其实就是通过反射执行目标对象的连接点处的方法
    * @param joinPoint : 用于环绕通知,通过procced()来执行目标方法
    * @return
    * @throws Throwable
    */
    @Around("execution(public int com.enjoy.study.cap13.TestService.service(int,int))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("@Around目标方法执行前...........");
    Object object = joinPoint.proceed();
    System.out.println("@Around目标方法执行后...........");
    return object;
    }
    }
  4. 配置类
    @Configuration
    @EnableAspectJAutoProxy//用于开启spring注解的AOP模式,使得ioc容器可以辨别Aspect类
    public class AopMainConfig {
    @Bean
    public MyAspectJ myAspectJ(){
    return new MyAspectJ();
    } @Bean
    public TestService testService(){
    return new TestService();
    }
    }
  5. 测试

    public class TestAspectJ {
    @Test
    public void testM(){
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopMainConfig.class);
    TestService service = context.getBean(TestService.class);
    int result = service.service(4, 2);
    System.out.println("result = " + result);
    }
    } 
  6. 结果
    @Around目标方法执行前...........
    @Before目标方法执行前
    .........service........
    @Around目标方法执行后...........
    @After目标方法执行后
    @AfterReturning目标方法执行后返回
    result = 2
      

知识点

  • execution:用于匹配方法执行的连接点
  • ProceedingJoinPoint:应用于环绕通知,使用proceed()执行目标方法
  • @Aspect:声明当前类是切面类
  • @EnableAspectJAutoProxy:在配置类上使用该注解开启Spring基于注解的AOP模式,使得Spring的IOC容器可以识别哪个bean是Aspect切面bean  

优化

对于上面的切面类,每个通知的execution都一样,是冗余的,导致重复写了多次,可以抽取公共切入方法

@Pointcut("execution(public int com.enjoy.study.cap13.TestService.service(int,int))")
public void pointCut(){}

本类可以直接引用,其他类可以通过路径+方法引用

@Aspect
public class MyAspectJ { @Pointcut("execution(public int com.enjoy.study.cap13.TestService.service(int,int))")
public void pointCut(){}

/**
* @Before
* 前置通知:在目标方法(service)运行之前运行
*/
@Before("pointCut()")
public void logStart(){
System.out.println("@Before目标方法执行前");
} /**
* @After
* 后置通知:在目标方法(service)运行结束之后运行,无论正常或异常结束
*/
@After("com.enjoy.study.cap13.MyAspectJ.pointCut()")
public void logEnd(){
System.out.println("@After目标方法执行后");
} /**
* @AfterReturning
* 返回通知:在目标方法(service)正常返回之后运行
*/
@AfterReturning("pointCut()")
public void logReturn() {
System.out.println("@AfterReturning目标方法执行后返回"); } /**
* @AfterThrowing
* 异常通知:在目标方法(service)出现异常后运行
*/
@AfterThrowing("pointCut()")
public void logThrowing(){
System.out.println("@AfterThrowing目标方法执行出现异常");
} /**
* @Around
* 环绕通知:动态代理,手动执行目标方法运行joinPoint.procced(),最底层通知,手动指定执行目标方法,
* 执行之前相当于前置通知, 执行之后相当于返回通知,其实就是通过反射执行目标对象的连接点处的方法
* @param joinPoint : 用于环绕通知,通过procced()来执行目标方法
* @return
* @throws Throwable
*/
@Around("pointCut()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("@Around目标方法执行前...........");
Object object = joinPoint.proceed();
System.out.println("@Around目标方法执行后...........");
return object;
}
}

我们还可以在切面类中得到方法名、方法的参数、结果、异常等信息

@Aspect
public class MyAspectJ { @Pointcut("execution(public int com.enjoy.study.cap13.TestService.service(int,int))")
public void pointCut(){} /**
* @Before
* 前置通知:在目标方法(service)运行之前运行
* @param joinPoint:应用于每个通知
*/
@Before(value = "pointCut()")
public void logStart(JoinPoint joinPoint){
System.out.println("@Before目标方法执行前,方法名:"+joinPoint.getSignature().getName()+
"方法参数:"+ Arrays.asList(joinPoint.getArgs()));
} /**
* @After
* 后置通知:在目标方法(service)运行结束之后运行,无论正常或异常结束
*/
@After("com.enjoy.study.cap13.MyAspectJ.pointCut()")
public void logEnd(){
System.out.println("@After目标方法执行后");
} /**
* @AfterReturning
* 返回通知:在目标方法(service)正常返回之后运行
*/
@AfterReturning(value = "pointCut()",returning = "result")
public void logReturn(Object result) {
System.out.println("@AfterReturning目标方法执行后返回结果:"+result); } /**
* @AfterThrowing
* 异常通知:在目标方法(service)出现异常后运行
*/
@AfterThrowing(value = "pointCut()",throwing = "ex")
public void logThrowing(Exception ex){
System.out.println("@AfterThrowing目标方法执行出现异常信息:"+ex);
} /**
* @Around
* 环绕通知:动态代理,手动执行目标方法运行joinPoint.procced(),最底层通知,手动指定执行目标方法,
* 执行之前相当于前置通知, 执行之后相当于返回通知,其实就是通过反射执行目标对象的连接点处的方法
* @param joinPoint : 用于环绕通知,通过procced()来执行目标方法
* @return
* @throws Throwable
*/
@Around("pointCut()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("@Around目标方法执行前...........");
Object object = joinPoint.proceed();
System.out.println("@Around目标方法执行后...........");
return object;
}
}

结果

@Around目标方法执行前...........
@Before目标方法执行前,方法名:service方法参数:[4, 2]
.........service........
@Around目标方法执行后...........
@After目标方法执行后
@AfterReturning目标方法执行后返回结果:2
result = 2

如果有异常会打印异常信息,例如将i/j中的j设置为0

@AfterThrowing目标方法执行出现异常信息:java.lang.ArithmeticException: / by zero

  

spring(六):spring中AOP的基本使用的更多相关文章

  1. Spring中AOP实现

    1.什么是SpringAOP 什么是aop:Aspect Oriented Programming的缩写,面向切面编程,通过预编译和动态代理实现程序功能的 统一维护的一种技术 主要功能:日志记录,性能 ...

  2. Spring中AOP原理,源码学习笔记

    一.AOP(面向切面编程):通过预编译和运行期动态代理的方式在不改变代码的情况下给程序动态的添加一些功能.利用AOP可以对应用程序的各个部分进行隔离,在Spring中AOP主要用来分离业务逻辑和系统级 ...

  3. spring Aop中aop:advisor 与 aop:aspect的区别

    转载:http://blog.csdn.net/u011710466/article/details/52888277 在spring的配置中,会用到这两个标签.那么他们的区别是什么呢?       ...

  4. 关于Spring中AOP的理解

    AOP简介[理解][重点] 1.AOP(Aspect Oriented Programing)面向切面/方面编程 2.AOP隶属软件工程的范畴,指导开发人员如何制作开发软件,进行结构设计 3.AOP联 ...

  5. Spring中AOP简介与切面编程的使用

    Spring中AOP简介与使用 什么是AOP? Aspect Oriented Programming(AOP),多译作 "面向切面编程",也就是说,对一段程序,从侧面插入,进行操 ...

  6. 框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)

    一.AOP的核心概念回顾 https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#a ...

  7. Spring 中aop切面注解实现

    spring中aop的注解实现方式简单实例   上篇中我们讲到spring的xml实现,这里我们讲讲使用注解如何实现aop呢.前面已经讲过aop的简单理解了,这里就不在赘述了. 注解方式实现aop我们 ...

  8. Spring中AOP相关源码解析

    前言 在Spring中AOP是我们使用的非常频繁的一个特性.通过AOP我们可以补足一些面向对象编程中不足或难以实现的部分. AOP 前置理论 首先在学习源码之前我们需要了解关于AOP的相关概念如切点切 ...

  9. 六、Spring之初步认识AOP

    Spring之初步认识AOP [1]AOP概览 什么是AOP?(来自百度) ​ 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行 ...

随机推荐

  1. JuniorCTF - Web - blind

    题目链接 https://ctftime.org/task/7450 参考链接 https://github.com/Dvd848/CTFs/blob/master/2018_35C3_Junior/ ...

  2. Rust(一)介绍 安装

    目录 Rust安装 Rust介绍: Windows 安装步骤: Helle world 创建项目文件夹: 写并执行程序: Rust安装 安装过程简单快捷,直接参照官网即可,Rust安装 Rust介绍: ...

  3. windowserver 常用命令

    1.查看端口占用: netstat -ano | findstr "服务端口号"2.查看程序运行id: tasklist | findstr  nginx 3.杀死进程  tskk ...

  4. 带你一文搞定 IO 流相关核心问题

    问:简单谈谈 Java IO 流各实现类的特性? 答:java.io 包下面的流基本都是装饰器模式的实现,提供了各种类型流操作的便携性,常见的流分类如下. 以二进制字节方式读写的流: InputStr ...

  5. rm 或者ls 报Argument list too long

    一个文件夹下面碎文件太多,rm 或者 ls的时候报 Argument list too long 解决办法: find /tmp -type d -name "*-*-" -del ...

  6. Docker Swarm学习教程【转载】

    Swarm介绍 Swarm是Docker公司在2014年12月初发布的一套较为简单的工具,用来管理Docker集群,它将一群Docker宿主机变成一个单一的,虚拟的主机.Swarm使用标准的Docke ...

  7. tensorflow2.0 squeeze出错

    用tf.keras写了自定义层,但在调用自定义层的时候总是报错,找了好久才发现问题所在,所以记下此问题. 问题代码 u=tf.squeeze(tf.expand_dims(tf.expand_dims ...

  8. 动态规划 List

    例题 #A 传纸条(Accepted)    #B 乘积最大 (Unaccepted)    #C 石子合并 (Accepted)    #D 加分二叉树 (Unaccepted)    #E 没有上 ...

  9. 【运维】使用FileZilla搭建FTP服务器

    一.下载Filezilla  Server 官网网址:https://filezilla-project.org 二.安装Filezilla  Server   Filezilla  Server的安 ...

  10. css3的各种属性的讲解

    1.渐变(gradients) 水平渐变:linear gradient 语法:background:linear-gradient(direction,color1,color2); directi ...