AOP原理
初始化AOP容器
读取配置文件或注解
解析配置文件,将配置文件转换成为AOP容器能够识别的数据结构Advisor,Advisor中包含了两个重要的数据结构。Advice:描述一个切面行为,即干什么;Pointcut:描述切面的位置,即在哪里
Spring将这个Advisor转换成自己能够识别的数据结构-AdvisorSupport,Spring动态的将这些方法植入到对应的方法中
生成动态代理类,使用jdk动态代理和cglib动态代理
提供调用,在使用的时候调用方调用的就是代理方法,也就是已经植入了增强方法的方法。
AOP使用
添加maven依赖
1 2 3 4 5 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-aop</artifactId > </dependency >
执行顺序
创建注解
1 2 3 4 5 6 7 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Log { String value () default "" ; }
AOP切面处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 @Aspect @Component public class LogAspect { @Pointcut("@annotation(com.example.demojava.aop.Log)") public void logPointCut () { } @Before(value = "logPointCut()") public void logBefore (JoinPoint point) { System.out.println("Before" ); } @AfterReturning(value = "logPointCut()") public void afterReturning (JoinPoint point) { System.out.println("AfterReturning" ); } @AfterThrowing(value = "logPointCut()") public void afterThrowing (JoinPoint point) { System.out.println("AfterThrowing" ); } @After(value = "logPointCut()") public void after (JoinPoint point) { System.out.println("After" ); } @Around(value = "logPointCut()") public void around (ProceedingJoinPoint point) throws Throwable { System.out.println("Around Before" ); Object result = point.proceed(); System.out.println("Around After" ); } }
测试
1 2 3 4 5 6 7 8 9 10 11 @RestController public class LogController { @Log(value = "测试aop") @GetMapping("/log") public void log () { throw new RuntimeException("" ); } }
系统日志
接案例一,这里做个完善
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 @Slf4j @Aspect @Component public class SysLogAspect { @Autowired private SysLogService sysLogService; @Autowired private TokenUtils tokenUtils; @Pointcut("@annotation(com.idcmind.idcboot.common.annotation.SysLog)") public void logPointCut () { } @Around("logPointCut()") public Object around (ProceedingJoinPoint point) throws Throwable { long beginTime = System.currentTimeMillis(); Object result = point.proceed(); long time = System.currentTimeMillis() - beginTime; saveSysLog(point, time); return result; } private void saveSysLog (ProceedingJoinPoint joinPoint, long time) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); SysLogEntity sysLog = new SysLogEntity(); SysLog syslog = method.getAnnotation(SysLog.class); if (syslog != null ){ sysLog.setOperation(syslog.value()); } String className = joinPoint.getTarget().getClass().getName(); String methodName = signature.getName(); sysLog.setMethod(className + "." + methodName + "()" ); Object[] args = joinPoint.getArgs(); try { String params = new Gson().toJson(args); sysLog.setParams(params); }catch (Exception e){ } ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); sysLog.setIp(IPUtils.getIpAddr(request)); String username = tokenUtils.getUsernameFromToken(); sysLog.setUsername(username); sysLog.setTime(time); sysLog.setCreateDate(new Date()); sysLogService.save(sysLog); log.info("请求接口: [{}]" , request.getRequestURL().toString()); log.info("请求方法: [{}]" , request.getMethod()); log.info("访问ip: [{}]" , request.getRemoteAddr()); log.info("类名: [{}]" , className); log.info("方法名: [{}]" , methodName); log.info("表单参数: [{}]" , new Gson().toJson(request.getParameterMap())); log.info("请求体参数: [{}]" , params); log.info("耗时: [{}ms]" , endTime - startTime); log.info("响应: [{}]" , new Gson().toJson(proceed)); log.info("\r\n" ); } }
简单认证
设置注解
1 2 3 4 5 6 7 8 9 10 11 12 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RequiresPermissions { String value () default "" ; }
权限过滤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 @Aspect @Component @Slf4j public class AuthorizeAspect { @Autowired private TokenUtils tokenUtils; @Autowired private SysUserService sysUserService; @Pointcut( "execution(public * com.idcmind.idcboot.modules.sys.controller.*.*(..))" + "&& !execution(public * com.idcmind.idcboot.modules.sys.controller.SysLoginController.login(..))" ) public void verify () {} @Before("verify()") public void doBefore (JoinPoint joinPoint) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); log.info("URL : " + request.getRequestURL().toString()); log.info("HTTP_METHOD : " + request.getMethod()); log.info("CLASS_NAME : " + joinPoint.getSignature().getDeclaringTypeName()); log.info("METHOD_NAME : " + joinPoint.getSignature().getName()); log.info("ARGS : " + Arrays.toString(joinPoint.getArgs())); String token = tokenUtils.getToken(request); boolean validateToken = tokenUtils.validateToken(token); if (!validateToken){ throw new ApiException(ApiErrorCode.AUTH_ERR); } MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); RequiresPermissions permissions = method.getAnnotation(RequiresPermissions.class); if (permissions == null ) { return ; } String value = permissions.value(); if (StringUtils.isNotEmpty(value)) { Set<String> perms = sysUserService.getUserPermissions(tokenUtils.getUserFromToken(token).getUserId()); if (!perms.contains(value)) { throw new ApiException(ApiErrorCode.AUTH_ERR); } } } }
SpringMVC配置
application.xml配置
1 2 3 4 5 6 7 8 xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd <mvc:annotation-driven /> <aop:aspectj-autoproxy proxy-target-class ="true" />
Non-Web配置
application.xml配置
1 2 3 4 xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
最后
本文到此结束,感谢阅读。如果您觉得不错,请关注公众号【当我遇上你】,您的支持是我写作的最大动力。