Java反射机制实战(搭配泛型使用)

Java反射是java高级特性里极其重要的一种。但是很多同学在刚接触的时候一定会想:这玩意这么麻烦,我用它干嘛?直接new 一个对象出来不好吗?
包括笔者在学习的时候也只知道有这么个东西,听老师说很多框架的底层用到的都是反射。仅此而已。
直到最近,笔者在项目重构中第一次使用到了反射+泛型。为此对反射也有了一点点浅薄的理解。也是感受到了其功能的强大。
项目背景如下:某电商项目,用户获取商品信息时,可以从多个维度上作为起点,比如常规的搜索功能,还有根据获取商品榜单,获取某个分类下的所有商品等等。
那么就以获取商品榜单为例:
通常在数据库中会存在以下几张表

  1. 榜单表,记录了榜单id,榜单名称,榜单的生效时间与过期时间等等。
  2. 商品表,记录了商品id,商品名称,商品预览图,商品链接等等,
  3. 榜单-商品关系表,记录了榜单与商品的关系。通常是一个榜单下有多个商品。也就是1-n。
怎么将榜单呈现给用户呢。在学校时,一个通用但简单的逻辑是:后端接收前端传过来了榜单id,然后在榜单表里找到对应的榜单名称等等,在关系表里找到该id下的所有商品id,再根据商品id在商品表里找到对应的信息返回给前端。
但是工作以后遇到的业务可不止这么几张表,通常还要查店铺表获取店铺名字,查价格表获取商品的价格,查促销表获取促销/打折信息,评论表获取商品的所有评论等等等等,最后再拼接全部数据。
【Java反射机制实战(搭配泛型使用)】以上加粗的业务,在根据榜单查询商品时要走一遍,根据分类查询商品也要走一遍,根据搜索查询商品也要走一遍,查询单个商品时也要走一遍。
我原来的逻辑是:以查询单个商品作为底层方法,实现好该逻辑后。再在其他维度查询商品时,获得商品id的集合后,再遍历调用查询单个商品的方法。
该逻辑好处只有一个:复用了代码且写起来方便。但是坏处有很多很多:耦合度太高,缓存不好设置,扩展性太差等等。
所以在一个新需求来之后,我发现我的逻辑不足以支撑新需求的开发。于是重构了项目。
在重构项目时,用到了反射+泛型的方法抽取了加粗部分的代码作为公共代码。
在拿到有着商品id的List后,由于每种维度的list里的类型都不一样(榜单id+其他,分类id+其他),但是它们肯定有一个共同的字段productId,怎么抽取成公共类呢?答案是使用泛型,然后用反射得到productId
GetProductResponse getProductResponse(List ob, GetProductRequest getProductRequest, StringBuilder redisKey) throws NoSuchFieldException, IllegalAccessException { //根据商品id查询商品的基本信息 List toDoList = new ArrayList<>(); for (T e : ob) { Field t = e.getClass().getDeclaredField("productId"); t.setAccessible(true); String productId = (String) t.get(e); toDoList.addAll(getProductList(productId, getProductRequest)); } //其他需要做的事,如找其他的字段,筛选,排序等 xxxxxxxx return new GetProductResponse; }

这里的重点是
  1. 使用泛型时,要在方法的最前面加上,告诉jvm这是个泛型标识,不然不会识别List
  2. 使用getClass()方法获取到对应的类对象,再通过getDeclardFiled拿到对应的字段。
  3. 注意字段filed调用setAccessible(true)方法。如果没有这行代码,private的字段在调用filed.get(T)时会报错。
笔者通过公共代码的抽取,让该公共方法成为了所有维度的底层。解放了根据单个商品id查询。
使代码可读性,可维护性变强,最重要的是架构清晰,解耦合,且行数加起来一下子少了几百行。
所以什么时候适合用反射呢?该怎么用呢?笔者在这里记录一种场景,也欢迎大家补充其他场景。
  1. 有多个维度或者说入口,他们的目的是一样的(根据榜单,分类等查询,目的都是为了获取商品信息)
  2. 在经过处理后,它们具有共同的字段,且这个字段是后续步骤的关键(榜单,分类里都存了productId的list,但是于此同时,除了productId,它们的其余字段是不一样的,比如榜单id,分类id)
  1. 搭配泛型一起使用,泛型的作用是使这个方法能成为多个维度的共同底层,而反射是为了获取泛型里的重要的字段(productId)
如果读者们在项目中也遇到了符合上述条件的场景,笔者在这里也非常推荐大家考虑反射+泛型的方式解耦合。如果是和笔者一样刚刚入门的初学者,一定也能对反射有个新的认识

    推荐阅读