zoukankan      html  css  js  c++  java
  • cglib动态代理导致注解丢失问题及如何修改注解允许被继承

    现象

      SOAService这个bean先后经过两个BeanPostProcessor,会发现代理之后注解就丢失了。

      

        

    开启了cglib代理

    @SpringBootApplication
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class Application {
        public static void main(String[] args) {
            SpringApplication app = new SpringApplication(Application.class);
            app.run(args);
        }
    }

    为什么开启这个代理模式呢

      http://www.cnblogs.com/hujunzheng/p/8428422.html 

    如何解决这个问题

      在自定义注解上添加@Inherited。如果是第三方的注解,调整项目接口层或者拿到这个注解通过代码方式加上@Inherited注解, 或者如下图所示。

      

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Service anon = bean.getClass().getAnnotation(Service.class);
        if (anon != null) {
            try {
                InvocationHandler h = Proxy.getInvocationHandler(anon);
    
                //设置@Service注解支持继承,应对动态代理导致类上的@Service注解丢失
                Field typeField = h.getClass().getDeclaredField("type");
                typeField.setAccessible(true);
                Field annotationTypeField = Class.class.getDeclaredField("annotationType");
                annotationTypeField.setAccessible(true);
                AnnotationType annotationType = (AnnotationType) annotationTypeField.get(typeField.get(h));
                Field inheritedField = AnnotationType.class.getDeclaredField("inherited");
                this.updateFinalModifiers(inheritedField);
                inheritedField.set(annotationType, true);
    
                // 获取 AnnotationInvocationHandler 的 memberValues 字段
                Field memberValuesField = h.getClass().getDeclaredField("memberValues");
                // 因为这个字段事 private final 修饰,所以要打开权限
                memberValuesField.setAccessible(true);
                // 获取 memberValues
                Map memberValues = (Map) memberValuesField.get(h);
    
                Service service = Stream.of(bean.getClass().getInterfaces())
                        .filter(iface -> iface.getAnnotation(Service.class) != null)
                        .collect(Collectors.toList())
                        .get(0)
                        .getAnnotation(Service.class);
    
                memberValues.put("version", service.version());
                memberValues.put("group", service.group());
            } catch (Exception e) {
                throw new BeanCreationException(String.format("%s %s %s %s %s"
                            , "修改"
                            , ClassUtils.getQualifiedName(bean.getClass())
                            , "的注解"
                            , ClassUtils.getQualifiedName(Service.class)
                            , "的 group值和version值出错")
                        , e);
            }
        }
        return bean;
    }

      参考链接:Annotation和动态代理

  • 相关阅读:
    zabbix3.4.6之源码安装
    集群概念Cluster
    awk文本分析工具
    shell getopts用法
    expect交互式安装软件
    常用通配符
    iptable四表五链
    质量保障&&质量体系建设
    MySQL数据库同步工具的设计与实现
    Redis ==> 集群的三种模式
  • 原文地址:https://www.cnblogs.com/hujunzheng/p/8433980.html
Copyright © 2011-2022 走看看