Spring AOP 注解及使用示例
什么是 AOP
AOP是Spring框架面向切面的编程思想,AOP采用一种称为“横切”的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。
切面:相当于应用对象间的横切点,我们可以将其单独抽象为单独的模块

AOP 术语
AOP 领域中的特性术语:
- 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
- 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
- 切点(PointCut): 可以插入增强处理的连接点。
- 切面(Aspect): 切面是通知和切点的结合。
- 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
- 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入
通过注解声明切点指示器
| AspectJ指示器 | 描述 |
|---|---|
| arg() | 限制连接点匹配参数为指定类型的执行方法 |
| @args() | 限制连接点匹配参数由指定注解标注的执行方法 |
| execution() | 用于匹配是连接点的执行方法 |
| this() | 限制连接点匹配AOP 代理的Bean 引用为指定类型的类 |
| target() | 限制连接点匹配目标对象为指定类型的类 |
| @target() | 限制连接点匹配特定的执行对象.这些对象对应的类要具备指定类型的注解 |
| within() | 限制连接点匹配指定的类型 |
| @within() | 限制连接点匹配指定注解所标注的类型(当使用Spring AOP时,方法定义在由指定的注解所标注的类里) |
| @annotation() | 限制匹配带有指定注解连接点 |
通过注解声明 5 种通知类型
| 注解 | 描述 |
|---|---|
| @Before | 通知方法会在目标方法调用之前执行 |
| @After | 通知方法会在目标方法返回或异常后调用 |
| @AfterReturning | 通知方法会在目标方法返回后调用 |
| @AfterThrowing | 通知方法会在目标方法抛出异常后调用 |
| @Around | 通知方法会将目标方法封装起来 |
@Pointcut //定义切点位置
使用:
@Pointcut("execution(* com.springinaction.springidol.Instrument.play(..))")

AOP 示例
下列代码基于SpringBoot 工程,部分代码已省略,请自行创建
1.创建AopController.java
package com.soft.controller; import com.google.gson.Gson; import com.soft.service.IAopService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; /** * Aop测试 * @description: AopController * @author: suphowe * @create: 2019-12-25 14:46 **/ @RestController @RequestMapping("/aop") @Api(value = "Aop切面编程测试") public class AopController { @Autowired private IAopService aopService; @ResponseBody @RequestMapping(value = "/method_one", method = RequestMethod.POST) @ApiOperation(value = "方法1", notes = "") @ApiImplicitParams({ @ApiImplicitParam(paramType = "query", name = "msg", value = "msg", required = false, dataType = "String") }) public String method_one(String msg){ String result = aopService.method_one(msg); return result; } }
2.创建 IAopService.java 和 AopServiceImpl.java
package com.soft.service; public interface IAopService { String method_one(String msg); }
package com.soft.service.impl;
import com.soft.service.IAopService;
import org.springframework.stereotype.Service;
@Service
public class AopServiceImpl implements IAopService {
@Override
public String method_one(String msg){
System.out.println("==>接收信息:" + msg);
return "return method_one";
}
}
3.创建 SysAspect.java
package com.soft.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class SysAspect {
/**
* 声明切点
*/
@Pointcut("execution(* com.soft.service.*.*(..))")
public void point(){}
/**
* 通知方法会在目标方法调用之前执行
*/
@Before("point())")
public void before() {
System.out.println("before ==> 通知方法会在目标方法调用之前执行");
}
/**
* 通知方法会在目标方法返回或异常后调用
*/
@After("point()")
public void after() {
System.out.println("After ==> 通知方法会在目标方法返回或异常后调用");
}
/**
* 通知方法会在目标方法返回后调用
*/
@AfterReturning("point()")
public void afterReturing() {
System.out.println("AfterReturning ==> 通知方法会在目标方法返回后调用");
}
/**
* 通知方法会在目标方法抛出异常后调用
*/
@AfterThrowing("point()")
public void afterThrowing() {
System.out.println("AfterThrowing ==> 通知方法会在目标方法抛出异常后调用");
}
/**
* 通知方法会将目标方法封装起来
* @param proceeding
*/
@Around("point()")
public Object around(ProceedingJoinPoint proceeding) throws Exception{
//和JoinPoint一样,ProceedingJoinPoint也可以获取
//连接点方法的实参
Object[] args=proceeding.getArgs();
//连接点方法的方法名
String methodName=proceeding.getSignature().getName();
//连接点方法所在的对象
Object targetObj=proceeding.getTarget();
String targetClassName=targetObj.getClass().getName();
Object result=null;
try {
System.out.println("前置通知==>参数:" + args[0]);
System.out.println("前置通知==>执行方法:" + methodName);
//执行连接点的方法 获取返回值
result=proceeding.proceed(args);
System.out.println("返回通知==>返回结果:" + result);
}catch (Throwable e) {
System.out.println("异常通知==>" + e);
}finally {
System.out.println("最终通知==>执行结束");
}
return result;
}
}
4.启动工程,通过Swagger-ui.html访问
swagger访问结果

控制台日志输出结果


浙公网安备 33010602011771号