Spring AOP 和 AspectJ 详解
2018-01-14 20:16
211 查看
最近在看《Spring 实战》,说真的第四章《面向切面编程的Spring》讲的真心很烂,看了几遍都不清楚到底要表达什么,也没有讲清楚Spring AOP 和 AspectJ的区别关系,终于让我找到了一篇文章关于 Spring AOP (AspectJ) 你该知晓的一切,写的是真好,这里记录一下。
接下来举个我自己项目代码的例子。
我们知道,很多时候,要判断当前用户是否已经登录,也就是进行鉴权,登录后获取到用户的userId,方便进行后续操作,鉴权这里的逻辑,我们可以写一个Bean去处理,在每一个Controller的方法里用以下代码实现:
这段代码看着没有什么问题,但是如果这类的逻辑多了,就要出现很多重复性的代码,满篇的重复逻辑,这个时候面向切面编程就要登场了。
这里我们通过环绕注解
首先实现两个注解。
这个是一个标注方法的注解,标注的方法会调用鉴权逻辑进行鉴权,注解的参数require代码是否要求强制登录。
这个是标注方法参数的注解,作用是如果鉴权成功,在切面编程的通知中会把标注的参数赋值为鉴权后的userId,比如:
是不是变得很简单,需要鉴权的部分只需要用@CheckLogin注解标注即可。
接下来举个我自己项目代码的例子。
我们知道,很多时候,要判断当前用户是否已经登录,也就是进行鉴权,登录后获取到用户的userId,方便进行后续操作,鉴权这里的逻辑,我们可以写一个Bean去处理,在每一个Controller的方法里用以下代码实现:
@Autowired private UserService userService; public Object buy(HttpServletRequest request){ Integer userId = userService.getUserId(request); if(userId == null){ return "鉴权失败"; } // 处理逻辑 return "处理成功"; }
这段代码看着没有什么问题,但是如果这类的逻辑多了,就要出现很多重复性的代码,满篇的重复逻辑,这个时候面向切面编程就要登场了。
这里我们通过环绕注解
@Around("@annotation(xxxxx)的方式实现这个切面。
首先实现两个注解。
@CheckLogin
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CheckLogin { /** * 设置为true会强制返回 ApiResponse 401 * * @return 是否强制要求登录 */ boolean require() default true; }
这个是一个标注方法的注解,标注的方法会调用鉴权逻辑进行鉴权,注解的参数require代码是否要求强制登录。
@UserId
@Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface UserId { }
这个是标注方法参数的注解,作用是如果鉴权成功,在切面编程的通知中会把标注的参数赋值为鉴权后的userId,比如:
@CheckLogin public ApiResponse ling(@UserId Integer userId){ //处理逻辑 }
实现切面的通知
@Aspect @Component public class LoginAspect { // 鉴权客户端对象 private final AuthClient authClient; // 鉴权失败时返回值 private static final ApiResponse NOT_LOGIN_RESPONSE = ApiResponse.error(401,"您还未登录,请登录后再试"); // 构造方法 @Autowired public LoginAspect(AuthClient authClient) { this.authClient = authClient; } // 声明当前切面为环绕型切面,切入点为注解切入,注解CheckLogin标注的方法都进行环绕切入 @Around("@annotation(com.cyf.annotation.CheckLogin)") public Object requireLogin(ProceedingJoinPoint pjp) throws Throwable { //获取切入的方法签名 MethodSignature signature = (MethodSignature) pjp.getSignature(); //获取方法 Method method = signature.getMethod(); //获取注解实例 CheckLogin checkLogin = method.getAnnotation(CheckLogin.class); Integer userId = null; try { //进行鉴权操作 userId = authClient.getUserId(); } catch (ThriftCallException e) { if (!(e instanceof AuthNoPassException)) { throw e; } //如果必须登录 if (checkLogin.require()) { //如果返回值是ResponseEntity if (method.getReturnType().isAssignableFrom(ResponseEntity.class)) { return ResponseEntity.ok(NOT_LOGIN_RESPONSE); } else { return NOT_LOGIN_RESPONSE; } } } // 获取切点方法的参数 Object[] args = pjp.getArgs(); // 给切点的userId赋值 assignUserId(method, args, userId); return pjp.proceed(args); } //给切点的@userId注解标注的方法赋值 private void assignUserId(Method method, Object[] args, Integer userId){ // 获取方法参数的所有注解 Annotation[][] annotations = method.getParameterAnnotations(); //获取方法参数的类型 Class<?>[] types = method.getParameterTypes(); for (int i = 0; i < annotations.length; i++) { Annotation[] arr = annotations[i]; for (Annotation a : arr) { Class<? extends Annotation> c = a.annotationType(); //判断是@UserId注解 if (c.isAssignableFrom(UserId.class)) { Class clazz = types[i]; if (clazz == Integer.class) { args[i] = userId;//给参数赋值 return; } else if (clazz == Optional.class) { args[i] = Optional.ofNullable(userId);//给Optional参数赋值 return; } break; } } } } }
使用切面
@RestController @RequestMapping("test") public class TestApi { @CheckLogin public ApiResponse buy(@UserId Integer userId){ // 处理逻辑 return "处理结果"; } }
是不是变得很简单,需要鉴权的部分只需要用@CheckLogin注解标注即可。
相关文章推荐
- 【第六章】 AOP 之 6.5 AspectJ切入点语法详解 ——跟我学spring3
- Spring AOP支持的AspectJ语法详解
- Spring AOP AspectJ切入点语法详解
- 【第六章】 AOP 之 6.5 AspectJ切入点语法详解 ——跟我学spring3
- Spring AOP AspectJ切入点语法详解,execution,within,this.......
- 详解Spring Aop实例之AspectJ注解配置
- Spring 之AOP AspectJ切入点语法详解(最全了,不需要再去其他地找了)
- Spring详解(五)------AspectJ 实现AOP
- »Spring 之AOP AspectJ切入点语法详解(最全了,不需要再去其他地找了)
- Spring 之AOP AspectJ切入点语法详解(最全面、最详细。)
- Spring 之AOP AspectJ切入点语法详解(最全面、最详细。)
- Spring 之AOP AspectJ切入点语法详解
- Spring 之AOP AspectJ切入点语法详解
- Spring 之AOP AspectJ切入点语法详解(最全了,不需要再去其他地找了)
- 【第六章】 AOP 之 6.5 AspectJ切入点语法详解 ——跟我学spring3
- JAVAWEB开发之Spring详解之——AOP底层剖析(基于JDK和cglib)、Spring中的AOP以及基于AspectJ的AOP实现、Spring的JDBCTemplate详解
- Spring 之AOP AspectJ切入点语法详解(最全了,不需要再去其他地找了)
- 【第六章】 AOP 之 6.5 AspectJ切入点语法详解 ——跟我学spring3
- Spring Aop AspectJ切入点语法详解