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和动态代理

posted @   hjzqyx  阅读(4912)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示