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的环绕增强