博客
关于我
Spring AOP 实战篇
阅读量:343 次
发布时间:2019-03-04

本文共 4692 字,大约阅读时间需要 15 分钟。

Spring AOP 实战指南

HTTP 接口鉴权

在实际开发中,HTTP RESTful服务的接口通常需要对调用方进行权限校验。直接在每个接口方法中进行权限验证虽然可行,但会导致代码冗余和潜在错误风险。为了更优雅地解决这个问题,我们可以使用Spring AOP来实现权限校验。

实现思路

  • 定制一个AuthChecker注解,用于标注需要权限校验的方法。
  • 使用Spring AOP的@Around注解,匹配标注了AuthChecker的方法。
  • 在advice中检查调用方的Cookie中是否存在合法的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注解。
  • 在before advice中记录方法调用参数。
  • 在afterReturning advice中记录方法返回结果。
  • 在afterThrowing advice中记录方法抛出的异常信息。
  • 代码示例

    @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注解。
  • 在advice中使用StopWatch记录方法执行时间。
  • 将方法执行时间上报到监控系统。
  • 代码示例

    @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/

    你可能感兴趣的文章
    Protobuf 属性解释
    查看>>
    Protobuf 编译工具转换 Java 类
    查看>>
    protobuf使用详解
    查看>>
    ProtoBuf在使用protoc进行编译时提示: Required fields are not allowed in proto3
    查看>>
    Protobuf学习 - 入门
    查看>>
    protobuf对象与JSON相互转换
    查看>>
    ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化
    查看>>
    protocol学习笔记001---RPC和HTTP协议之间的区别_与各自优势
    查看>>
    protostuff简单应用
    查看>>
    PRover 开源项目教程
    查看>>
    PyTorch-Tutorials【pytorch官方教程中英文详解】- 4 Transforms
    查看>>
    Proxy server 緩存 jsp html
    查看>>
    Proxy 和 Reflect 结合实现代理和拦截( 代码示例 )
    查看>>
    PyTorch-Tutorials【pytorch官方教程中英文详解】- 3 Datasets&DataLoaders
    查看>>
    ProxySQL+MHA搭建MySQL读写分离高可用集群
    查看>>
    Proxy源代码分析--谈谈如何学习linux网络编程
    查看>>
    pr录制自己声音杂音很重
    查看>>
    PyTorch-Tutorials【pytorch官方教程中英文详解】- 2 Tensors
    查看>>
    ps ww
    查看>>
    PS —— 制作喷漆人像
    查看>>