您的位置:首页 > 编程语言 > Java开发

JAVA问题记录-利用Spring AOP来拦截特定方法上的注解并根据业务修改注解字段值

2018-03-03 23:01 543 查看
问题起因:
    首先有块业务,需要添加埋点内容,但是此处埋点在入参值中有一个字段值,这个字段值的不同,会发送不同的打点信息(这个是在接口返回正确的情况下调用的),奔着解耦原业务和埋点的出发点,于是选择利用注解和SpringAOP来实现,其实这个实现还有其他的方式。但是此次就我实现的方式解释下,并把遇到的问题记录下。
   二话不说,先上代码@AfterReturning(value = "interceptorMethod(reqModel,request)", returning = "responseModel")
    public void afterReturningAdvice(JoinPoint joinPoint, ReqPublishDynamicModelXX reqModel, HttpServletRequest request, ResponseModel responseModel) {
        if (responseModel.getError() == ErrorCodes.OK){
Signature signature = joinPoint.getSignature();
        if (signature instanceof MethodSignature) {
            MethodSignature methodSignature = (MethodSignature) signature;
            PointResource pointResource = methodSignature.getMethod().getAnnotation(PointResource.class);
            if (null != pointResource) {
                InvocationHandler handler = Proxy.getInvocationHandler(pointResource);
                Field sourceField;
                try {
                    sourceField = handler.getClass().getDeclaredField("memberValues");
                    sourceField.setAccessible(true);
                    Map<String, Object> memberValues = (Map<String, Object>) sourceField.get(handler);
                    if (reqModel.getTopicId() <= 0) {                       
                        memberValues.put("source", 7);
                    } else {    
                        memberValues.put("source", 5);
                    }
                } catch (Exception e) {
                    //省略.....
                }
                userPointService.handleUserPointResource(userModel.getUid(), pointResource.source(), pointResource.type(), pointResource.plus(), UUID.randomUUID().toString());
            }
        }
}
    }接下来针对代码中的部分内容进行解
1、释@AfterReturning这个是在方法执行返回后织入的,因为要根据业务的调用结果来判断是否需要执行,这点很简单。
2、PointResource pointResource = methodSignature.getMethod().getAnnotation(PointResource.class);这句是获取方法上的注释类,InvocationHandler handler = Proxy.getInvocationHandler(pointResource);这一句是利用代理来获取注解类的InvocationHandler,其实对应注解类的具体InvocationHandler接口实现类是AnnotationInvocationHandler,但是这个类不是public的,所以无法直接使用,知道具体的实现类之后,我们会从AnnotationInvocationHandler的源码类中发现所有的注解类的字段都维护在一个叫做Map<String, Object> memberValues这么个字段中,所有才有sourceField = handler.getClass().getDeclaredField("memberValues");这么一句,在执行完这一句之后,我们会获取到Map<String, Object> memberValues字段,并且通过   memberValues.put("source", 7);这样类似的语句来实现控制注解的字段值内容。
到这里所有的业务实现都已经完成了,接下来说说遇到的坑点.....
===================================华丽的分界线================================
坑点描述:加在方法上的注释类,由于当前类是由Spring托管的,所以对于该类的默认对象实例是单例类,那么对于加在该类方法上的注解类也是单例的(可能对于注解类描述不恰当,但是是为了表达对于该方法每次调用都是同一个注解类),那么在通过代理模式修改了注解类的字段值之后,那么对于该字段值影响是永久的。但是我错误的认为该注解类是原型的(即每次访问都算是一个全新的注解类)这就导致我业务代码书写错误了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐