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. bzoj 3569 DZY Loves Chinese II 随机算法 树上倍增

    题意:给你一个n个点m条边的图,有若干组询问,每次询问会选择图中的一些边删除,删除之后问此图是否联通?询问之间相互独立.此题强制在线. 思路:首先对于这张图随便求一颗生成树,对于每一条非树边,随机一个 ...

  2. maven 常用插件 拷贝依赖 拷贝jar包 查看属性 环境变量

    1 maven编译后希望将生产的jar包拷贝到指定目录 在pom中配置maven插件 maven-antrun-plugin <build > <plugins> <pl ...

  3. 【LGR-062】洛谷10月月赛 III div.2 (A-C)

    前言 100+100+46+0=246pts 300多名 以后每次比赛都要有进步哦!qwq 小D与笔试 水题 Code #include<algorithm> #include<io ...

  4. django之重定向redirect

    一:redirect的场景 加入登录成功后,需要跳转到主页:登录退出后,跳转到主页面.

  5. MYSQL数据库类型与JAVA类型对应表

    MYSQL数据库类型与JAVA类型对应表   MYSQL数据库类型与JAVA类型对应表 类型名称 显示长度 数据库类型 JAVA类型 JDBC类型 索引(int) VARCHAR L+N VARCHA ...

  6. 前端VUE环境构建

    https://nodejs.org/en/ 安装node 安装淘宝npm镜像 D:\>cd cnpm D:\cnpm>npm install -g cnpm --registry=htt ...

  7. html中的点击事件

    使用点击事件写一个计数器. onmouseup : 当鼠标按下,松开的时候触发事件. onmousedown: 当鼠标按下的时候触发事件.onMouseOver: 鼠标经过时触发 onMouseOut ...

  8. java生成128A条形码

    添加maven依赖 <dependency> <groupId>net.sf.barcode4j</groupId> <artifactId>barco ...

  9. Graph Neural Networks for Computer Vision

    Graph Neural Networks for Computer Vision I was attracted by this image: This is an inspiring image ...

  10. Harbor在安装前的几个注意点

    由于Harbor有1.8后和前的配置不一样,决定先安装1.8,结果报错如下 [root@localhost harbor]# ./install.sh [Step 0]: checking insta ...