项目中spring proxy遇到的bug

1、类被代理导致无法正确获取到注解

简介:mq消息消费接口,有多个实现类,每个实现类都有Tag注解,Tag注解上有关键字段名称,消息过来根据Tag标签寻找实现类进行解析处理,所以在程序初始化的时候需要又一个map,存储着tag标签名以及其对应的实现类,问题出在初始化的时候,实现类上的Tag注解没有正确获取到。

以下为自己测试所用代码:

public interface MessageComsumer {

    public void consume(Record record);

}
@Component
@Tag(name = "taoge2222")
public class MagComsumer implements MessageComsumer {
    @Override
    public void consume(Record record) {
        start();
    }

    public void start() {

    }
}
@Component
@Tag(name = "taoge")
public class FagComsumer implements MessageComsumer {
    @Override
    public void consume(Record record) {
        start();
    }

    @Async
    public void start() {

    }
}
@RequestMapping("/test1")
    @ResponseBody
    public String test1(){
        Map<String, MessageComsumer> beansOfType = applicationContext.getBeansOfType(MessageComsumer.class);
        for (MessageComsumer messageProcessor : beansOfType.values()) {
            Tag annotation = messageProcessor.getClass().getAnnotation(Tag.class);
            if (annotation != null) {
                String tag = annotation.name();
                System.out.println(tag);
            }
        }
        return "test1";
    }

结果打印实现类Tag注解名称时,只成功打印了一个,FagComsumer未成功打印,原因就出在@Async,因为@Async的原理也是通过代理,所以获取到的是代理类,所以没有办法成功获取到实现类上的注解

所以在遇到这种情况的时候需要判断是否是代理类

        @RequestMapping("/test2")
    @ResponseBody
    public String test2(){
        Map<String, MessageComsumer> beansOfType = applicationContext.getBeansOfType(MessageComsumer.class);
        for (MessageComsumer messageProcessor : beansOfType.values()) {
            Tag annotation = messageProcessor.getClass().getAnnotation(Tag.class);
            if (annotation != null) {
                String tag = annotation.name();
                System.out.println(tag);
            }else{
                if(AopUtils.isAopProxy(messageProcessor)){
                    try {
                        Object obj;
                        //判断是jdk还是cglib代理
                        if (AopUtils.isJdkDynamicProxy(messageProcessor)) {
                            obj = getJdkDynamicProxyTargetObject(messageProcessor);
                        } else {
                            obj = getCglibDynamicProxyTargetObject(messageProcessor);
                        }
                        Tag annotation2 = obj.getClass().getAnnotation(Tag.class);
                        if(annotation2!=null){
                            System.out.println(annotation2.name());
                        }
                    }catch (Exception e){

                    }
                }
            }
        }
        return "test2";
    }

    private static Object getCglibDynamicProxyTargetObject(Object obj) throws Exception {
        Field h = obj.getClass().getDeclaredField("CGLIB$CALLBACK_0");
        h.setAccessible(true);

        Object dynamicAdvisedInterceptor = h.get(obj);
        Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
        advised.setAccessible(true);
        Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
        return target;
    }

    private static Object getJdkDynamicProxyTargetObject(Object obj) throws Exception {

        Field h = obj.getClass().getSuperclass().getDeclaredField("h");
        h.setAccessible(true);

        AopProxy aopProxy = (AopProxy)h.get(obj);
        Field advised = aopProxy.getClass().getDeclaredField("advised");
        advised.setAccessible(true);
        Object target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
        return target;

    }

这样就可以成功获取,当然这种方案可能还是有问题,因为如果遇到多重代理的问题,需要递归获取。

2、对同一个方法多个aop实现的问题

简介:repo层更新时,原本已经对该方法进行有过切面主要用于信息同步到第三方系统(AfterReturing),现在需要对该方法再次进行切面,主要是使用AfterReturing对更新之后的模型进行处理,结果出现了bug,对他的数据同步造成了影响,我把自己的切面关掉之后就正常了。

解决方法就是保证对方的aop实现先执行,所以就需要搞清楚多个aop谁先执行的问题,其实Order注解可控制。

spring aop就是一个同心圆,要执行的方法为圆心,最外层的order最小。从最外层按照AOP1、AOP2的顺序依次执行doAround方法,doBefore方法。然后执行method方法,最后按照AOP2、AOP1的顺序依次执行doAfter、doAfterReturn方法。也就是说对多个AOP来说,先before的,一定后after。

results matching ""

    No results matching ""