什么是 AOP
根据维基百科对aop的定义为:AOP(Aspect Oriented Programming,面向切面的程序设计)是计算机科学中的一种程序设计思想,旨在将横切关注点与业务主体进行进一步分离,以提高程序代码的模块化程度。该思想使得开发人员能够将与代码核心业务逻辑关系不那么密切的功能添加至程序中,同时又不降低业务代码的可读性。面向切面的程序设计思想也是面向切面软件开发的基础。
目前主流的程序设计思想
- OOP(Object Oriented Programming)面向对象编程
- AOP(Aspect Oriented Programming)面向切面编程
- POP(Process Oriented Programming)面向过程编程
- FP(Functional Programming)函数式编程
AOP的作用 AOP 的诞生就是为了弥补 OOP(面向对象编程)的不足,面向对象用来解决纵向的业务逻辑非常擅长,但是对于横向的公共操作却显得有些力不从心。所以通过AOP来弥补OOP。常见的运用场景性能统计、记录日志、权限检查、事务控制、缓存处理等公用性很强的横向功能。
AOP 中的核心概念
- Advice(通知):为aop要处理的业务。如日志记录等。
- JoinPoint(连接点):允许 AOP 进行 Advice 的地方,比如在方法触发日记记录,这个方法被调用前就是一个 JoinPoint;
- Pointcut(切入点):用于筛选 JoinPoint 的条件,只有符合 Poincut 的条件的 JoinPoint 才会执行 Advice。
- Aspect(切面):是一个包含 Advice 和 Pointcut 的集合,完整的定义了符合什么条件时做什么事
- Before:在目标方法调用前调用 Advice
- After[finally]:在目标方法执行完成后调用 Advice
- After-returning:在目标方法成功执行后调用 Advice
- After-throwing:在目标方法抛出异常后调用 Advice
- Around:一般解释为环绕 / 包裹目标方法调用 Advice
Aspect运用
1、引入aspect的依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2、然后创建 AspectController(为横切的类哦):
@RestController
@RequestMapping("/aspect")
@Slf4j
public class AspectCotroller {
@GetMapping("/hello")
public String hello() {
log.info("apsect 到达了");
return "hello world";
}
}
创建一个切面类 WebAspect:
// @Aspect 注解,用来标识该类为一个 AOP 的切面。
// @Component 注解,标明这个类需要加入到ioc管理的
@Aspect
@Component
@Slf4j
public class WebAspect {
@Pointcut("execution(* cn.lcw.controller..*.*(..)) ")
public void pointCut() {
}
@Before(value = "pointCut()")
public void before(JoinPoint joinPoint) {
// 获取切点的方法
String methodName = joinPoint.getSignature().getName();
// 获取切点的类名
String className = joinPoint.getTarget().getClass().getName();
// 切点参数
Object[] args = joinPoint.getArgs();
String[] parameterNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
Map<String, Object> paramMap = new HashMap<>();
for (int i = 0; i < parameterNames.length; i++) {
paramMap.put(parameterNames[i], args[i]);
}
log.info("path:{}", request.getServletPath());
log.info("class name:{}", className);
log.info("method name:{}", methodName);
log.info("args:{}", paramMap.toString());
}
@After(value = "pointCut()")
public void after(JoinPoint joinPoint) {
log.info("{} after", joinPoint.getSignature().getName());
}
@AfterReturning(value = "pointCut()", returning = "returnVal")
public void afterReturning(JoinPoint joinPoint, Object returnVal) {
log.info("{} after return, returnVal: {}", joinPoint.getSignature().getName(), returnVal);
}
}
具体的执行效果如下:
Spring AOP 中@Pointcut的用法:
使用的基本格式:execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
其中括号中各个pattern分别表示:
- 修饰符匹配(modifier-pattern?)
- 返回值匹配(ret-type-pattern)可以为*表示任何返回值,全路径的类名等
- 类路径匹配(declaring-type-pattern?)
- 方法名匹配(name-pattern)可以指定方法名 或者 代表所有, set 代表以set开头的所有方法
- 参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用“”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(…)表示零个或多个任意参数
- 异常类型匹配(throws-pattern?)
- 其中后面跟着“?”的是可选项
具体使用的示例:
1)execution(* *(..))
//表示匹配所有方法
2)execution(public * com. savage.service.UserService.*(..))
//表示匹配com.savage.server.UserService中所有的公有方法
3)execution(* com.savage.server..*.*(..))
//表示匹配com.savage.server包及其子包下的所有方法
在Spring 2.0中,Pointcut的定义包括两个部分:Pointcut表示式(expression)和Pointcut签名(signature)
//Pointcut表示式
@Pointcut(“execution(* com.savage.aop.MessageSender.*(…))”)
//Point签名
private void log(){}