千家信息网

如何用Java反射提高开发效率的框架

发表于:2024-09-22 作者:千家信息网编辑
千家信息网最后更新 2024年09月22日,本篇内容介绍了"如何用Java反射提高开发效率的框架"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!基
千家信息网最后更新 2024年09月22日如何用Java反射提高开发效率的框架

本篇内容介绍了"如何用Java反射提高开发效率的框架"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

基于spring的aop,定义一个注解做为切点,注释在service层的分页查询方法上,声明方法的返回结果POJO对象的哪个字段需要应用默认值规则。

通过aop在方法执行完成之后,给返回结果应用配置的默认值规则,再返回给前端,如下图所示。



如果一次查询返回含有20个元素的数组List,要对每个元素R都反射查找一次Field,判断该Field的值,如果为空则赋值为默认值,那就是重复做反射获取Field,乱用反射,延长接口的响应时间。


对于默认值规则应用这个例子,我们可以有很好的做法,拿到R类中的name字段,即Field,只需要反射一次。就是在应用启动时,执行包扫描获取到R的Class对象,执行反射获取R类型中所有的Field,然后使用Map>缓存在内存中,这样用到的时候就能很快拿到。虽然会消耗点内存,但这是可以忽略的,因为整个系统应用到默认值规则的类就没几个。


我认为我设计的这套默认值规则是最优的方案。

1、使用aop实现代码的解耦,默认值规则的应用逻辑不侵入业务代码,随时可对这个功能进行插拔。


2、同时,利用反射可以实现添加默认值规则不需要改动任何代码,随时添加随时用,随时修改随时生效。


3、再者,由于默认值规则存在的很少改动这个特性,使用内存缓存,有效减少数据库的查询次数,也是对性能的一个提升。


…………… 利用反射提高工作效率 …………


业务场景简介


今天,我继续分享另一种反射的使用场景,包括如何设计实现。以此,回答本篇文章开头的问题,怎样才算用到刀刃上。


先了解点简单的业务场景,这段内容主要介绍使用场景,看不懂没关系,大概过一遍就行。


本次优化的是一个定时任务服务,它要做的就是调用很多第三方的接口拉取数据,并转为平台统一结构的数据,如将A、B、C…转为P,存入到数据库中。


假如我有一个产品,需要做推广,那我就是上游广告主,而我想投放到百度搜索、微信朋友圈展示,那么百度和微信就是下游渠道。但中间可能经过几层渠道,而中间的每一个渠道对于下游来说都是一个广告主,也都可以称为网盟平台,大家可能会对百度网盟广告平台有所耳闻。




那么作为一个网盟平台,需要整合上游的Offer,批给下游去展示。整合上游的 Offer就是调用每个上游提供的api。但每个上游所返回的json数据都不一样,字段名称也不一样。那就需要为每个api实现一个解析映射的方法。这就是重复劳动。如何减少这种重复劳动,就是提高工作效率。


简单一句话,要做什么


与Mybatis实现的将查询结果映射成pojo对象的过程相似。如果还觉得这段内容抽象,那就直接跳过吧,我改了好几次,发现都好难表述清楚啊。


解析映射,就是将json数据解析后得到的java对象Response,之后,再获取到Response中存放广告信息数组(List)的字段的值,再遍历该List,将每个元素由类型A转为平台统一的类型对象B,这个过程就是A to B,比如。


class A{

String a_name;

}


Class B{

String name;

}


实现 A==>to ==> B 就是:

A a;

B b;

b.setName(a.getA_name());


很显然,直接使用反射copy字段的值是没有用的,一是字段名不同,二是可能字段的类型也不同,三是还可能是下面这样情况。


class A{

C c;

public static class C{

String c_name;

}

}


class B{

String name;

}


实现 A==> to ==> B 就是:

A a;

B b;

b.setName(a.getC().get C_name());


如何实现自动映射


如果可以添加一个注解,在注解中声明映射规则,比如其中一条:class A中的name字段对应class B中的pkgName字段。


如果能根据注解声明的一个个映射规则,完成自动映射,就可以不用每次都写这些重复代码了。是的,我要实现的就是这样一个功能。


P.S:最后我还加入了插件功能,满足一些需要做特殊处理的需求。


类结构树的定义


知道我为啥叫它结构树吗?二叉树不是二叉树,n差数不是n叉树,我不懂怎么叫,难道这是我自己发明的?哈哈。


以一个例子来讲,不那么抽象。如图,实现自动从TestResponse对象中,拿到List rowset的值。因为根据对接文档,我知道这个字段正是广告Offer集合,一个item代表一个广告Offer。




要实现根据注解自动将TestResponse对象解析生成List集合,那肯定要对TestResponse对象的结构了如指掌(下文将这一类由调用API返回的对象称为Response对象)。所以需要将TestResponse类中的字段信息映射成一颗树。


先不讲那么多,来看下最终实现的效果,使用@ProdCampaignMapRules注解声明映射规则。





正如上图所示,我在RowsetBean类添加@ProdCampaignMapRules注解,意味着会自动将类型为RowsetBean的对象,映射生成ProdCampaign对象。


认真看,你会发现,TestRsponse类上面还有个注解@MapRulesComponent,它的作用只是声明这个类支持使用自动映射。我在程序启动时,会扫描所有被该注解注释的Response,将这些Response解析成一棵棵类结构树,缓存在内存中。


实现自动解析API返回的广告Offer数组,映射生成平台统一的ProdCampaign集合的步骤,继续以上图中的例子为例。


第一步:从类结构树中,找到有@ProdCampaignMapRules的ClassNode,再得到这个ClassNode 所属的FieldNode。找到的FieldNode就是Response中的List rowset字段。获取rowset的值,这就得到了广告Offer集合。


第二步:New一个List,遍历广告Offer集合rowset,将每个RowsetBean类型的元素转为平台统一的ProdCampaign对象,并添加到List集合中。


第三步:将每个RowsetBean转为ProdCampaign的过程当中,需要new一个ProdCampaign对象,然后给这个对象里面的字段赋值。值从哪来?从RowsetBean对象中找到与之对应的字段,并获取值,为ProdCampaign对象赋值。很好理解,不就是属性拷贝。


第四步:如果是多层映射,如例子中的"offer.name"映射规则,就是要先获取到RowsetBean对象中的offer字段,类型为OfferBean。再继续下一层name的映射,name的映射就是获取OfferBean的name字段。这就是一个两层映射的例子。


我定义的结构体看起来很复杂。RuleMetaData,就是完成包扫描后每个Class生成的类结构树。类中的字段信息用FieldNode存放,如果该字段的类型是非基本数据类型,则FieldNode的child是该字段所对应类型的ClassNode数据。


整棵结构树就是一个RuleMetaData,根节点root肯定是一个ClassNode。非基本数据类型的FieldNode也有一个child指向一个ClassNode。很抽象?没关系,继续看,下面会有一张图,形象的画出了这棵结构数。


实现包扫描将Class解析成一颗结构树


在应用启动时,实现包扫描,找出所有被@MapRulesComponent注释的类,解析生成结构树RuleMetaData,举个例子。



如图,已经画得很形象了,这棵树的结构应该已经在你的脑子里。

结构树的root节点,是该Response的第一个字段,存储了这个字段的字段名和反射获取到的Field,所属类TestResponse。下个字段就是节点的nextField字段,由于该字段的类型是基本数据类型int,所以child的值为null。

到data字段的时候,由于其类型是非基本数据类型,而是一个内部类DtaBean,需要解析成一个ClassNode,同时要继续反射取得DataBean的所有字段的FieldNode节点链。最后将data节点的child指向这个ClassNode。

在反射DataBean生成FieldNode链的时候,处理到rowset字段,发现其是一个List类型,那就获取这个List的元素的类型,这个反射是支持的,能获取到。

然后再继续对RowsetBean继续以上步骤。还有一点,就是RowsetBean被@ProdCampaignMapRules注解注释,所以要获取到@ProdCampaignMapRules注解,赋值给rowset的ClassNode节点的rule。

反射解析Response生成结构数,我是使用队列加广度优先遍历方法。代码如下图所示。

包扫描如何实现我就不说了。


根据OfferBean的Class结构树映射生成ProdCampaign


这一步我只介绍实现思路,每一步的具体实现,整体的实现就不贴代码了。


1.首先使用jackson解析调用第三方API返回的json字符串,得到Response对象。


2.根据Response的Class从缓存中获取其类结构树。使用深度优先搜索,取得被@ProdCampaignMapRules注释的ClassNode。这个很好判断,因为在前面将类生成结构树的步骤,已经取得@ProdCampaignMapRules注解并存放到了ClassNode的rule。



3.获取到被@ProdCampaignMapRules注释的ClassNode后,取得该ClassNode所属的FieldNode。


4.取得该FieldNode后,获取Field,反射取得值,这个值就是要找的目标,即存放广告Offer的集合。



5.拿到存放广告Offer的集合后,遍历这个集合,将里面的每个元素,映射成平台统一的存放广告信息的ProdCampaign。最后就能获取到ProdCampaign集合。


6.每个元素映射成ProdCampaign对象的过程,才是重点,还是很复杂的。因为需要支持多层映射,就是支持像使用mybatis拼写sql一样支持"."操作,如"offer.geo.country",就是要取得offer对象的geo字段的值,再获取geo的country字段的值。有了类结构树,多级映射并不难,只需要一个while循环即可。




7.对于tracklinkMap,是一个注解数组,类型是@TracklinkMap,用于声明url需要哪些参数,怎么拼接。


"如何用Java反射提高开发效率的框架"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

字段 就是 对象 类型 反射 构树 注解 广告 规则 数据 生成 平台 元素 应用 代码 例子 注释 结构 节点 方法 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 买一个服务器家用能带几台电脑 茂名工行网络技术公司 如何把数据写入数据库sql 软件开发支出么做会计分录 wdcp让数据库远程连接 葡萄市场消费者意愿数据库 软件开发行业风险类别 魔兽世界不打架的服务器 手机总显示服务器失败 我的世界服务器活跃值指令 access数据库打印 丽江网络安全技术提升十大品牌 在电脑数据库上如何导入数据 网络安全与风险的例子 安徽在线网络技术服务以客为尊 能有效阻止网络安全攻防 服务器安全狗要钱吗 武清软件开发项目管理 做发卡网站需要什么服务器 中华人民共和国网络安全网站 北京hp服务器虚拟化系统 天龙八部卡级服务器玩法 易缘云网络技术有限公司 关于网络安全的会议纪要 达梦数据库介绍材料 武汉戴尔服务器高质量的选择 美国摄像头网络安全事件 云易袋互联网科技有限公司 360在网络安全方面实力如何 服务器 塔式 机架式
0