AOP称为面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。
常见的AOP使用场景:
- 记录操作日志:记录操作日志属于公共行为,而每一个service可能都需要记录日志,我们不能在每一个service里面都编写记录日志代码,因此 AOP 就很方便
- 缓存处理:可能也会存在很多 service 需要进行缓存,也有使用到 AOP 的必要
- Spring中内置的事务处理
接下来演示如何使用AOP
首先,提供一个切面类
@Component
@Aspect //切面类
public class SysAspect {
@Pointcut("@annotation(com.itheima.annotation.Log)")
private void pointcut() {
}
@Around("pointcut2()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
//获取用户名
//需要通过解析seesion或token获取
//获取被增强类和方法的信息
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
//获取被增强的方法对象
Method method = methodSignature.getMethod();
//从方法中解析注解
if(method != null){
Log logAnnotation = method.getAnnotation(Log.class);
System.out.println(logAnnotation.name());
}
//方法名字
String name = method.getName();
System.out.println(name);
//通过工具类获取Request对象
RequestAttributes reqa = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes)reqa;
HttpServletRequest request = sra.getRequest();
//访问的url
String url = request.getRequestURI().toString();
System.out.println(url);
//请求方式
String methodName = request.getMethod();
System.out.println(methodName);
//登录IP
String ipAddr = getIpAddr(request);
System.out.println(ipAddr);
//操作时间
System.out.println(new Date());*/
//保存到数据库(操作日志)
//....
return joinPoint.proceed();
}
}
从上往下看
@Component 不用解释
@Aspect 表明该类是切面类
pointcut 方法是切点表达式,@Pointcut 中表示,如果某个方法添加了 Log 注解(Log 是我们自定义的注解,如下),则调用当前方法时就会进入到环绕通知进行增强
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
/**
* 模块名称
*/
public String name() default "";
}
around 方法中有一个形参 joinPoint ,从这里面可以获取当前被增强的类和方法的信息
接着我们在需要增强的方法上添加 @Log 注解,如下
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/getById/{id}")
@Log(name = "根据用户id获取用户")
public User getById(@PathVariable("id") Integer id) {
return userService.getById(id);
}
}
这样就完成AOP的环绕增强