本文共 4692 字,大约阅读时间需要 15 分钟。
在实际开发中,HTTP RESTful服务的接口通常需要对调用方进行权限校验。直接在每个接口方法中进行权限验证虽然可行,但会导致代码冗余和潜在错误风险。为了更优雅地解决这个问题,我们可以使用Spring AOP来实现权限校验。
AuthChecker注解,用于标注需要权限校验的方法。@Around注解,匹配标注了AuthChecker的方法。user_token,如果存在则允许访问,否则返回权限错误。@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface AuthChecker {}@Component@Aspectpublic class HttpAopAdviseDefine { @Pointcut("@annotation(com.xys.demo1.AuthChecker)") public void pointcut() {} @Around("pointcut()") public Object checkAuth(ProceedingJoinPoint joinPoint) throws Throwable { HttpServletRequest request = RequestContextHolder.getRequestAttributes().getRequest(); String token = getUserToken(request); if (!token.equalsIgnoreCase("123456")) { return "权限不合法!"; } return joinPoint.proceed(); } private String getUserToken(HttpServletRequest request) { Cookie[] cookies = request.getCookies(); if (cookies == null) { return ""; } for (Cookie cookie : cookies) { if (cookie.getName().equalsIgnoreCase("user_token")) { return cookie.getValue(); } } return ""; }} @RestControllerpublic class DemoController { @RequestMapping("/aop/http/alive") public String alive() { return "服务一切正常"; } @AuthChecker @RequestMapping("/aop/http/user_info") public String callSomeInterface() { return "调用了 user_info 接口。"; }} 记录方法调用的日志是开发和维护服务的重要需求。我们可以使用Spring AOP的before、afterReturning和afterThrowing方法来实现日志记录。
LogAopAdviseDefine类,使用@Before、@AfterReturning和@AfterThrowing注解。@Component@Aspectpublic class LogAopAdviseDefine { private Logger logger = LoggerFactory.getLogger(getClass()); @Pointcut("within(NeedLogService)") public void pointcut() {} @Before("pointcut()") public void logMethodInvokeParam(JoinPoint joinPoint) { logger.info("---Before method {} invoke, param: {}---", joinPoint.getSignature().toShortString(), joinPoint.getArgs()); } @AfterReturning(pointcut = "pointcut()", returning = "retVal") public void logMethodInvokeResult(JoinPoint joinPoint, Object retVal) { logger.info("---After method {} invoke, result: {}---", joinPoint.getSignature().toShortString(), joinPoint.getArgs()); } @AfterThrowing(pointcut = "pointcut()", throwing = "exception") public void logMethodInvokeException(JoinPoint joinPoint, Exception exception) { logger.info("---method {} invoke exception: {}---", joinPoint.getSignature().toShortString(), exception.getMessage()); }} @Servicepublic class NeedLogService { private Logger logger = LoggerFactory.getLogger(getClass()); private Random random = new Random(System.currentTimeMillis()); public int logMethod(String someParam) { logger.info("---NeedLogService: logMethod invoked, param: {}---", someParam); return random.nextInt(); } public void exceptionMethod() throws Exception { logger.info("---NeedLogService: exceptionMethod invoked---"); throw new Exception("Something bad happened!"); }} 在服务监控中,记录方法调用耗时是非常重要的。我们可以使用Spring AOP的@Around注解来实现耗时统计。
ExpiredAopAdviseDefine类,使用@Around注解。@Component@Aspectpublic class ExpiredAopAdviseDefine { private Logger logger = LoggerFactory.getLogger(getClass()); @Pointcut("within(SomeService)") public void pointcut() {} @Around("pointcut()") public Object methodInvokeExpiredTime(ProceedingJoinPoint pjp) throws Throwable { StopWatch stopWatch = new StopWatch(); stopWatch.start(); Object retVal = pjp.proceed(); stopWatch.stop(); reportToMonitorSystem(pjp.getSignature().toShortString(), stopWatch.getTotalTimeMillis()); return retVal; } private void reportToMonitorSystem(String methodName, long expiredTime) { logger.info("---method {} invoked, expired time: {} ms---", methodName, expiredTime); }} @Servicepublic class SomeService { private Logger logger = LoggerFactory.getLogger(getClass()); private Random random = new Random(System.currentTimeMillis()); public void someMethod() { logger.info("---SomeService: someMethod invoked---"); try { Thread.sleep(random.nextInt(500)); } catch (InterruptedException e) { e.printStackTrace(); } }} 通过以上几个实际场景的实现,我们可以看到Spring AOP的强大功能。无论是权限校验、日志记录还是耗时统计,Spring AOP都能以优雅的方式解决问题。如果你有更多的业务需求,可以根据实际需求灵活配置Spring AOP来实现更复杂的功能。
转载地址:http://guie.baihongyu.com/