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. 小程序封装一个有输入框的modal层组件

    其实很简单,就是在modal中添加新的 input <view> <modal class="modal" wx:if="{{!hiddenModal} ...

  2. HTTP post get request 时遇到特殊字符 ! @ # $ % ^ & * ( )

    HTTP post get request 时遇到特殊字符 ! @ # $ % ^ & * ( ) 使用对应的编码替代 例如: curl ftp://username:pass@word@ex ...

  3. django之项目部署知识点

    一:项目部署的框架 nginx和uWSGI在生产服务器上进行的部署 二:什么是nginx? nginx是一个web服务器. 什么是web服务器? web服务器则主要是让客户可以通过浏览器进行访问,处理 ...

  4. flask之数据库的交互

    一:关系型数据库 mysql Flask-SQLAlchemy管理关系型数据库. mysql数据库引擎:url : mysql://username:passowrd@hostname/databas ...

  5. VUE的系统指令

    1. -text原样渲染,渲染文本 2.-html   HTML渲染页面 举例: <!doctype html> <html lang="en"> < ...

  6. ES集群health为yellow解决办法

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11766147.html Logstash导入数据后,Cerebro显示集群health的状态为yell ...

  7. SQLite和MySQL数据库的差别与应用

    简单来说,SQLITE功能简约.小型化,追求最大磁盘效率:MYSQL功能全面,综合化.追求最大并发效率.假设仅仅是单机上用的,数据量不是非常大.须要方便移植或者须要频繁读/写磁盘文件的话.就用SQLi ...

  8. 算法-python

    选择排序:一个列表被分为无序列表和有序列表,选择排序就是拿无序列表的第一个和后面的每一个相比较,每一趟选择出最小的一个,添加进有序列表. def select_sort(list): for i in ...

  9. WinForm、WPF、ASP.NET窗口生命周期

    https://blog.csdn.net/s_521_h/article/details/73826928

  10. 带有lazy标记的线段树

    #include<bits/stdc++.h> using namespace std; ]; struct st{ int l,r,val,add; }tr[]; void build( ...