重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
本篇内容介绍了“如何用Java反射提高开发效率的框架”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
在源汇等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供网站制作、做网站 网站设计制作定制网站,公司网站建设,企业网站建设,品牌网站制作,营销型网站建设,外贸网站建设,源汇网站建设费用合理。
基于spring的aop,定义一个注解做为切点,注释在service层的分页查询方法上,声明方法的返回结果POJO对象的哪个字段需要应用默认值规则。
通过aop在方法执行完成之后,给返回结果应用配置的默认值规则,再返回给前端,如下图所示。
如果一次查询返回含有20个元素的数组List
对于默认值规则应用这个例子,我们可以有很好的做法,拿到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
要实现根据注解自动将TestResponse对象解析生成List
先不讲那么多,来看下最终实现的效果,使用@ProdCampaignMapRules注解声明映射规则。
正如上图所示,我在RowsetBean类添加@ProdCampaignMapRules注解,意味着会自动将类型为RowsetBean的对象,映射生成ProdCampaign对象。
认真看,你会发现,TestRsponse类上面还有个注解@MapRulesComponent,它的作用只是声明这个类支持使用自动映射。我在程序启动时,会扫描所有被该注解注释的Response,将这些Response解析成一棵棵类结构树,缓存在内存中。
实现自动解析API返回的广告Offer数组,映射生成平台统一的ProdCampaign集合的步骤,继续以上图中的例子为例。
第一步:从类结构树中,找到有@ProdCampaignMapRules的ClassNode,再得到这个ClassNode 所属的FieldNode。找到的FieldNode就是Response中的List
第二步:New一个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反射提高开发效率的框架”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注创新互联网站,小编将为大家输出更多高质量的实用文章!