【java】这样使用 注解 规范吗?

发布于 2022-09-12 01:53:51 字数 1629 浏览 48 评论 0

项目环境

  1. 使用 SpringCloud
  2. 各服务模块依赖 common-remote 模块,通过里面的 Feign Client 进行跨服务调用
  3. 工具类均放在 common-service 模块里面,各模块依赖 common-service
  4. common-servicecommon-remote 没有依赖关系

背景

  1. 由于要对接第三方系统,需要将本系统A的字段 与 第三方系统B的字段 建立映射关系,比如 A系统 字段名为 a1的值 要赋值给 B系统 字段名为 b2
  2. 笔者开发了一个注解MyAnnotation 以及工具类utils,通过在a1字段上添加注解 @MyAnnotation(name = "b2",dataType = DataType.Employee) ,然后将 所在类 传入工具类,工具类会根据 dataType进行值的转换以适配B系统,再进行字段重命名(a1 => b2),即可输出对应的 数据结构(假设为 AimClass)

    类似于 @JSONField(name="b2")
  3. 开发的远程Feign接口 ThePort 的参数类为 AimClass,只能通过 AimClass 参数类才能向第三方发起请求,位于 common-remote

权衡

好处

  1. 调用者只需进行注解的书写,无需关注值的转换 以及 数据结构的构造过程,有利于 项目快速开发 以及隐藏细节

坏处

  1. 通过注解 与表单有着某种耦合,当 A系统的表单结果调整了,修改者或许不敢乱改代码
  2. 接口 依赖于 工具类,因为如果缺少工具类,构造 AimClass 很困难或者 易出错,因此使用这个远程接口及必须要有这个工具类

    举个例子,如果公司其他项目想通过 远程接口ThePort 访问 第三方系统,就会出现这个问题。

我的想法

  1. 我问过一位同事,十分认同他一个说法, 使用工具类没有问题,以内这个是需要对接的、位于两个系统的单据结构属于强关联的关系,因此当A系统修改需要修改 表单结构,那么B系统的表单结构也会改变,而调用者改的只是注解。

我的问题

  1. 坏处中的第二个问题可以通过 将此工具类 放在 common-remote 中解决,但是这样 科学吗?规范吗?
  2. 笔者这种通过注解 + 工具类 的解决方案是否 可取呢?为什么?
  3. 有没有其他参考的方案呢?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情绪 2022-09-19 01:53:51

不知道你的 @MyAnnotation 用以修饰哪个类,我这里假设是 OriginClass 吧.

以我个人来说,我会使用 AimClass.from(originClassInstance);

其实就是把你的工具类融合到目标类里.

理由:

  1. 转换逻辑只有 AimClass 需要,转换逻辑的输出即 AimClass,那么只需要把转换逻辑封装到该类中即可.
  2. 转换逻辑中,可以硬编码或者也通过 @MyAnnotation 注解来处理.但是注意,这里的 @MyAnnotation 应该修饰的是 AimClass 上的字段.
  3. 由于 1、2,如果映射关系发生变化,调用者完全无感,因为他依旧可以传入一个干净的 OriginClassInstance.
  4. 如果想做到 AimClass 不依赖 OriginClass 也是可以的(不然就需要 remote 反过来依赖 OriginClass 所在的包了,虽然可以通过 provide 解决但是终究看着闹心):
public class AimClass {

    @MyAnnotation(name = "origin_id", type = String.class)
    private String id;
    
    public static AimClass from(Object object) {
        AimClass aim = new AimClass();
        Class tClass = object.getClass();
        // 如果有反射工具类的话则更方便,不想依赖的话则用原始写法就好.
        // 这一段应该跟你原先的转换代码差不多. 我就不多解释了.
        // 异常捕捉我也没写,需要的就自己加一下.
        Arrays.stream(
            // 如果不支持 stream 那就换成 for 循环.
            AimClass.class.getDeclaredFields()
        )
            .filter(f -> f.isAnnotationPresent(MyAnnotation.class))
            .forEach(f -> {
                f.setAccessible(true);
                MyAnnotation myAnnotation = f.getAnnotation(MyAnnotation.class);
                Field tField = tClass.getDeclaredField(myAnnotation.name());
                tFiled.setAccessible(true);
                f.set(aim, myAnnotation.type().cast(tField.get(object)));
            })
         return aim;
    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文