当前位置: 首页 > news >正文

兰州优化网站排名中国十大互联网公司排名

兰州优化网站排名,中国十大互联网公司排名,wordpress 视频文件夹,卡盟在线自助下单Spring提供的BeanUtils源码剖析目录 前言先导知识之JAVA内省山寨版 BeanUtils.copyProperties()效果展示正版 BeanUtils.copyProperties() 源码剖析上班一年的时候补充:Map转对象(补充)抽象接口 Trans 使用初版工具类的 Trans 接口存在的 bug…

Spring提供的BeanUtils源码剖析目录

    • 前言
    • 先导知识之JAVA内省
    • 山寨版 BeanUtils.copyProperties()
    • 效果展示
    • 正版 BeanUtils.copyProperties() 源码剖析
    • 上班一年的时候补充:Map转对象(补充)
    • 抽象接口 Trans 使用
    • 初版工具类的 Trans 接口存在的 bug优化!加入高亮字段映射
    • 抽象接口 Trans 优化
    • 抽象接口 Trans 最终效果
    • 总结
    • 小咸鱼的技术窝

前言

前段时间刚入职xxx公司,由于公司内部有一套自己的技术架构,并且很多东西都是自研、封装的。身为小菜鸡的在业余时间抽空看了一下里面的源码,感觉这些人基础挺扎实的哈哈哈哈,这些个基础架构工具包全是自研的,牛逼。一下子激发了我看 BeanUtils 源码的兴趣,想着靠自己的摸索,结合之前研究的JDK动态代理技术,自己也尝试着写一套功能类似的基架组件出来(结合代理技术的以后再写,这玩意有点繁琐)。

先导知识之JAVA内省

不清楚JAVA内省的小伙伴,先来了解一下这方面的知识,何为内省?内省是JAVA提供的一组可以操纵 JavaBean 属性的一组 Api,掌握了这些个 Api 我们也可以写一个自己的 BeanUtils 出来。下面先来介绍一波这些个 Api。

  1. Introspector.getBeanInfo(o.getClass()) 获取当类的一个BeanInfo对象,和Spring中的 BeanDefinition 对象有点类似,BeanDefinition 是封装了 Bean 信息的一个信息对象,BeanInfo 是封装了 Java 对象一系列 Api 方法的对象。
  2. BeanInfo.getPropertyDescriptors() 获取 PropertyDescriptor 对象,可以通过此对象获取类字段属性 name、value、get和set方法名字、对字段进行属性填充。等操作

山寨版 BeanUtils.copyProperties()

恭喜你已经通过了入职考核,有资格进入 zzh 盗版集团来,我们集团这里的人都是人中翘楚、人中龙凤、国之栋梁、梁之中流砥柱、柱中之无懈可击的存在了。下面列举一个 我司开发的山寨版BeanUtils.copyProperties()软件 给读者参观(),温馨提示:前方500米有宝箱,请大家仔细翻阅。大概流程为:遍历操作对源对象与目标对象进行属性名的匹配,匹配上了,随即进行对应属性名的value值填充

public class IntrospectionTest {public static List<Object> init() {List<Object> zzhSources = new ArrayList<>();ZzhSource zzhSource = new ZzhSource();zzhSource.setAge("1");zzhSource.setName("zzh1");ZzhSource zzhSource2 = new ZzhSource();zzhSource2.setAge("2");zzhSource2.setName("zzh2");zzhSources.add(zzhSource);zzhSources.add(zzhSource2);return zzhSources;}@SneakyThrowspublic static void main(String[] args) {List<Object> zzhTargets = new ArrayList<>();System.err.println("copy before: " + zzhTargets);copyProperties(init(), zzhTargets, ZzhTarget.class);System.err.println("copy after:: " + zzhTargets);}public static void copyProperties(List<Object> sources, List<Object> targets, Class targetClass) {sources.stream().forEach(source -> {try {Object o = targetClass.newInstance();Arrays.stream(Introspector.getBeanInfo(source.getClass()).getPropertyDescriptors()).forEach(sp -> {try {/*** 遍历操作:targetClass 对应的对象与 sources 集合中对应的对象进行属性匹配*/Arrays.stream(Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors()).forEach(op -> {/*** 名称匹配上了之后进行属性填充*/if (sp.getName().equals(op.getName()) && !sp.getName().equals("class")) {try {/*** 对我们新创建的 o 对象进行属性填充,填充数据的来源为 sources*/op.getWriteMethod().invoke(o, sp.getReadMethod().invoke(source));} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}});} catch (IntrospectionException e) {e.printStackTrace();}});/*** o 对象属性填充完毕,添加至 targets集合中*/targets.add(o);} catch (IntrospectionException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}});}@Datastatic class ZzhSource {String name;String age;String sex;}@Datastatic class ZzhTarget {String name;String age;String sex;}
}

效果展示

可以看到数据成功的拷贝到了我们指定的 List 中了
在这里插入图片描述

正版 BeanUtils.copyProperties() 源码剖析

步骤流程总是惊人的相似,获取对象的 PropertyDescriptor ,然后调用内省为我们提供的各种操作 字段 属性的Api,最终达到属性拷贝的目的。

private static void copyProperties(Object source, Object target, @Nullable Class<?> editable, @Nullable String... ignoreProperties) throws BeansException {Assert.notNull(source, "Source must not be null");Assert.notNull(target, "Target must not be null");//获取目标对象ClassClass<?> actualEditable = target.getClass();if (editable != null) {if (!editable.isInstance(target)) {throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]");}actualEditable = editable;}
//获取目标对象的所有 PropertyDescriptorPropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;PropertyDescriptor[] var7 = targetPds;int var8 = targetPds.length;
//遍历目标对象的 PropertyDescriptorfor(int var9 = 0; var9 < var8; ++var9) {PropertyDescriptor targetPd = var7[var9];//获取目标对象的写方法,通过此方法可以对指定字段赋值Method writeMethod = targetPd.getWriteMethod();if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {//获取源对象 PropertyDescriptorPropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());if (sourcePd != null) {//获取源对象的读方法,通过此方法可以获取对应字段的 value值Method readMethod = sourcePd.getReadMethod();if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {try {//设置一下方法操作权限,为可操作if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {readMethod.setAccessible(true);}
//获取源对象字段中的 value值Object value = readMethod.invoke(source);if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {writeMethod.setAccessible(true);}
//为目标对象进行属性填充writeMethod.invoke(target, value);} catch (Throwable var15) {throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var15);}}}}}}

上班一年的时候补充:Map转对象(补充)

最近在写 Es 相关的业务,但是懒得用框架,主要是 Es 6 和 Es 7 和 Es 8 之间的 api 语法相差过大,实在是垃圾,于是自己基于原始 Api 封装了一套基于组内同时使用,其中就包括 Map 转 对象,传统写法需要一个个 Set 实在是垃圾,于是用反射封转了如下一个抽象方法。

public interface Trans<T> {abstract Class getTargetClass();default Object trans(Map<String, Object> map) throws IntrospectionException, InstantiationException, IllegalAccessException {Object o = getTargetClass().newInstance();BeanInfo beanInfo = Introspector.getBeanInfo(o.getClass());Arrays.stream(beanInfo.getPropertyDescriptors()).forEach(propertyDescriptor -> {if (!"this".equals(propertyDescriptor.getName())&&!Objects.isNull(map.get(propertyDescriptor.getName()))) {try {propertyDescriptor.getWriteMethod().invoke(o, map.get(propertyDescriptor.getName()));} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}});return o;}
}

抽象接口 Trans 使用

使用很简单每个业务对象实现 Trans 中的抽象方法即可

在这里插入图片描述

后续 Es 查到数据直接 new ArticleResponse().trans(hit.getSourceAsMap()) 即可得到填充好的对象,简单方便!

在这里插入图片描述

初版工具类的 Trans 接口存在的 bug优化!加入高亮字段映射

之前没考虑到父类属性赋值的问题,以及 Es 查到的数据源全是字符串,需按照类型进行映射,比如 Es 查到的日期是 2023-12-12 字符串类型的,但是映射实体类是 Date 接受的,这种情况优化了一下代码 如下。
在这里插入图片描述
主要逻辑就是根据字段类型做一个匹配映射,匹配类型对不上的进行强转,以及加入高亮字段替换!!!

/*** map 转对象* author:zzh** @param <T>*/
public interface Trans<T> {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");abstract Class getTargetClass();default PropertyDescriptor[] mergeAndDeduplicate(PropertyDescriptor[]... arrays) {Set<PropertyDescriptor> set = new HashSet<>();for (PropertyDescriptor[] array : arrays) {set.addAll(Arrays.asList(array));}return set.toArray(new PropertyDescriptor[0]);}default Object trans(Map<String, Object> map, Map<String, HighlightField> highlightFields) throws IntrospectionException, InstantiationException, IllegalAccessException {Object o = getTargetClass().newInstance();Class tclass = getTargetClass();HashMap<String, Class> nameTypeMap = new HashMap<>();//找到父类的所有字段do {Arrays.stream(tclass.getDeclaredFields()).forEach(field -> {field.setAccessible(true);//key:字段名称,value:字段类型nameTypeMap.put(field.getName(), field.getType());});tclass = tclass.getSuperclass();} while (!tclass.equals(Object.class));PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors();Arrays.stream(propertyDescriptors).forEach(propertyDescriptor -> {if (!"targetClass".equals(propertyDescriptor.getName()) && !Objects.isNull(map.get(propertyDescriptor.getName()))) {try {Method writeMethod = propertyDescriptor.getWriteMethod();if (null != writeMethod) {if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {writeMethod.setAccessible(true);}Object sourceValue = map.get(propertyDescriptor.getName());Class aClass = nameTypeMap.get(propertyDescriptor.getName());//类型一致,直接赋值if (sourceValue.getClass().equals(aClass)) {writeMethod.invoke(o, highlightFields.get(propertyDescriptor.getName()) != null ?(highlightFields.get(propertyDescriptor.getName()).getFragments()[0]).toString() :map.get(propertyDescriptor.getName()));}/*** 类型不一致强转,这里可以搞个策略模式优化优化*/else {if (aClass.equals(Date.class)) {Date parse = simpleDateFormat.parse(String.valueOf(map.get(propertyDescriptor.getName())));writeMethod.invoke(o, parse);}if (aClass.equals(Integer.class)) {writeMethod.invoke(o, Integer.valueOf(String.valueOf(map.get(propertyDescriptor.getName()))));}if (aClass.equals(Long.class)) {writeMethod.invoke(o, Long.valueOf(String.valueOf(map.get(propertyDescriptor.getName()))));}if (aClass.equals(int.class)) {writeMethod.invoke(o, Integer.parseInt(String.valueOf(map.get(propertyDescriptor.getName()))));}}} else throw new RuntimeException(propertyDescriptor.getName() + "~ writeMethod is null!!!!!");} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (Exception e) {//类型不匹配
//                    System.err.println(propertyDescriptor.getWriteMethod());
//                    System.err.println(propertyDescriptor.getName());
//                    System.err.println(o);
//                    System.err.println(map.get(propertyDescriptor.getName()));e.printStackTrace();}}});return o;}
}

抽象接口 Trans 优化

又优化了一下复杂对象下高亮字段的映射!!!!!最终代码如下

/*** map 转对象* author:zzh** @param <T>*/
public interface Trans<T> {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");abstract Class getTargetClass();default PropertyDescriptor[] mergeAndDeduplicate(PropertyDescriptor[]... arrays) {Set<PropertyDescriptor> set = new HashSet<>();for (PropertyDescriptor[] array : arrays) {set.addAll(Arrays.asList(array));}return set.toArray(new PropertyDescriptor[0]);}default Object trans(Map<String, Object> map, Map<String, HighlightField> highlightFieldsSource, List<String> highLightFields) throws IntrospectionException, InstantiationException, IllegalAccessException {Object o = getTargetClass().newInstance();Class tclass = getTargetClass();HashMap<String, Class> nameTypeMap = new HashMap<>();//找到父类的所有字段do {Arrays.stream(tclass.getDeclaredFields()).forEach(field -> {field.setAccessible(true);//key:字段名称,value:字段类型nameTypeMap.put(field.getName(), field.getType());});tclass = tclass.getSuperclass();} while (!tclass.equals(Object.class));PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors();Arrays.stream(propertyDescriptors).forEach(propertyDescriptor -> {if (!"targetClass".equals(propertyDescriptor.getName()) && !Objects.isNull(map.get(propertyDescriptor.getName()))) {try {Method writeMethod = propertyDescriptor.getWriteMethod();if (null != writeMethod) {if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {writeMethod.setAccessible(true);}Object sourceValue = map.get(propertyDescriptor.getName());//父类以及自己所有字段类型Class aClass = nameTypeMap.get(propertyDescriptor.getName());//字符串类型以及高亮直接赋值if (sourceValue.getClass().equals(aClass)) {writeMethod.invoke(o, highlightFieldsSource.get(propertyDescriptor.getName()) != null ?(highlightFieldsSource.get(propertyDescriptor.getName()).getFragments()[0]).toString() :map.get(propertyDescriptor.getName()));}/*** 类型不一致强转,这里可以搞个策略模式优化优化*/else {if (aClass.equals(Date.class)) {Date parse = simpleDateFormat.parse(String.valueOf(map.get(propertyDescriptor.getName())));writeMethod.invoke(o, parse);}if (aClass.equals(Integer.class)) {writeMethod.invoke(o, Integer.valueOf(String.valueOf(map.get(propertyDescriptor.getName()))));}if (aClass.equals(Long.class)) {writeMethod.invoke(o, Long.valueOf(String.valueOf(map.get(propertyDescriptor.getName()))));}if (aClass.equals(List.class)) {ArrayList<Map<String, Object>> oraginSources = (ArrayList<Map<String, Object>>) map.get(propertyDescriptor.getName());if (null != oraginSources &&0 != highlightFieldsSource.size()) {for (int i = 0; i < oraginSources.size(); i++) {for (int j = 0; j < highLightFields.size(); j++) {try {if (highlightFieldsSource.containsKey(highLightFields.get(j))) {oraginSources.get(i).put(highLightFields.get(j).split("\\.")[1],highlightFieldsSource.get(highLightFields.get(j)).getFragments()[j].toString());}} catch (Exception e) {e.printStackTrace();}}}}writeMethod.invoke(o, oraginSources);}if (aClass.equals(int.class)) {writeMethod.invoke(o, Integer.parseInt(String.valueOf(map.get(propertyDescriptor.getName()))));}}} else throw new RuntimeException(propertyDescriptor.getName() + "~ writeMethod is null!!!!!");} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (Exception e) {//类型不匹配
//                    System.err.println(propertyDescriptor.getWriteMethod());
//                    System.err.println(propertyDescriptor.getName());
//                    System.err.println(o);
//                    System.err.println(map.get(propertyDescriptor.getName()));e.printStackTrace();}}});return o;}}

抽象接口 Trans 最终效果

使用方法如下
在这里插入图片描述
可以看到复杂对象也成功加上高亮标签
在这里插入图片描述

总结

Spring为我们提供的 BeanUtils 工具类其实也就是对 内省 Api中的一些方法的包转而已,思考:内省的实现原理是什么呢?我们是否可以从 Jdk 或者 CgLib动态代理入手,自己写一套 山寨版 内省 Api呢?答案肯定是可以的,以后有时间再去研究一下这个,读者感兴趣的话,也可以尝试着自己写一套内省 Api哦

小咸鱼的技术窝

关注不迷路,日后分享更多技术干货,B站、CSDN、微信公众号同名,名称都是(小咸鱼的技术窝)更多详情在主页
在这里插入图片描述


文章转载自:
http://dinncojamshedpur.bkqw.cn
http://dinncooocyst.bkqw.cn
http://dinncoisothermic.bkqw.cn
http://dinncorosemary.bkqw.cn
http://dinncogoddamnit.bkqw.cn
http://dinncoattitudinarian.bkqw.cn
http://dinncoathenai.bkqw.cn
http://dinncodisequilibrium.bkqw.cn
http://dinncoinurement.bkqw.cn
http://dinncobenthon.bkqw.cn
http://dinncosemidiameter.bkqw.cn
http://dinncoprotean.bkqw.cn
http://dinncopurify.bkqw.cn
http://dinncodictatorship.bkqw.cn
http://dinncodifferent.bkqw.cn
http://dinncosuperbike.bkqw.cn
http://dinncofrivolity.bkqw.cn
http://dinncoplanetarium.bkqw.cn
http://dinncoathetoid.bkqw.cn
http://dinncothymocyte.bkqw.cn
http://dinncouranus.bkqw.cn
http://dinncoconvulse.bkqw.cn
http://dinncominibus.bkqw.cn
http://dinncoprecambrian.bkqw.cn
http://dinncoforefront.bkqw.cn
http://dinncoclupeid.bkqw.cn
http://dinncocervantite.bkqw.cn
http://dinncoenfetter.bkqw.cn
http://dinncounrighteousness.bkqw.cn
http://dinncoimmunogenesis.bkqw.cn
http://dinncotainan.bkqw.cn
http://dinncoeccentricity.bkqw.cn
http://dinncodurbar.bkqw.cn
http://dinncofracas.bkqw.cn
http://dinncobartend.bkqw.cn
http://dinncondugu.bkqw.cn
http://dinncotoadflax.bkqw.cn
http://dinncoauc.bkqw.cn
http://dinncohydrofracturing.bkqw.cn
http://dinncoursiform.bkqw.cn
http://dinncoindictor.bkqw.cn
http://dinncocatalepsis.bkqw.cn
http://dinncorabid.bkqw.cn
http://dinncouppie.bkqw.cn
http://dinncoviewership.bkqw.cn
http://dinncofloorer.bkqw.cn
http://dinncoboxful.bkqw.cn
http://dinncofacile.bkqw.cn
http://dinncolondonization.bkqw.cn
http://dinncomedoc.bkqw.cn
http://dinncomonochrome.bkqw.cn
http://dinncomaulers.bkqw.cn
http://dinncoempurpled.bkqw.cn
http://dinncounweight.bkqw.cn
http://dinncokythe.bkqw.cn
http://dinncoimpeachment.bkqw.cn
http://dinncochorizon.bkqw.cn
http://dinncotheology.bkqw.cn
http://dinncocernet.bkqw.cn
http://dinncorouser.bkqw.cn
http://dinncoairt.bkqw.cn
http://dinncosubcontract.bkqw.cn
http://dinncopalmiped.bkqw.cn
http://dinncosiloam.bkqw.cn
http://dinnconazir.bkqw.cn
http://dinncojuju.bkqw.cn
http://dinncofoyer.bkqw.cn
http://dinncodelusive.bkqw.cn
http://dinncobangle.bkqw.cn
http://dinncobehavior.bkqw.cn
http://dinncoaustralia.bkqw.cn
http://dinncoerrata.bkqw.cn
http://dinncogreenkeeper.bkqw.cn
http://dinncoshaddock.bkqw.cn
http://dinncoplanaria.bkqw.cn
http://dinncolord.bkqw.cn
http://dinncounretarded.bkqw.cn
http://dinncomolybdenite.bkqw.cn
http://dinncoallonymous.bkqw.cn
http://dinncoreconcentrate.bkqw.cn
http://dinncoincomparably.bkqw.cn
http://dinncoperineum.bkqw.cn
http://dinncosizeable.bkqw.cn
http://dinncopulvillus.bkqw.cn
http://dinncohirundine.bkqw.cn
http://dinncocolumbarium.bkqw.cn
http://dinncosleave.bkqw.cn
http://dinncocontradict.bkqw.cn
http://dinncodoable.bkqw.cn
http://dinncotext.bkqw.cn
http://dinncospiritist.bkqw.cn
http://dinncophotog.bkqw.cn
http://dinncotattered.bkqw.cn
http://dinncosalutation.bkqw.cn
http://dinncosentimentality.bkqw.cn
http://dinncomassif.bkqw.cn
http://dinncoanharmonic.bkqw.cn
http://dinncoalternately.bkqw.cn
http://dinncoarblast.bkqw.cn
http://dinncosuperpower.bkqw.cn
http://www.dinnco.com/news/149580.html

相关文章:

  • 医药企业网站建设要哪些备案中央新闻频道直播今天
  • 软件开发 网页设计网站网站测速
  • wordpress 链接扁平化东莞市网络seo推广服务机构
  • 前端网站开发培训百度移动首页
  • 网站开发人员职位晋升空间百度口碑官网
  • 制作网页链接的方法全能优化大师
  • 那里有专业注册网站建设的网站关键词怎么优化排名
  • 做盗链网站网络公关公司联系方式
  • 建设银行网站转账必须u盾吗腾讯企点是干嘛的
  • 电子商务网站建设哪家好厦门百度竞价开户
  • 学做日本菜的网站好品牌形象推广
  • 商务网站开发的基本流程百度竞价推广开户费用
  • 怎么做网站关键词推广好的竞价推广托管
  • 用wordpress videopro广州seo诊断
  • wordpress 文章回收站长沙网站制作主要公司
  • 建设网站应注意什么360推广
  • 现在哪个网站做网站好企业网站推广策划
  • 外贸网站建设网站开发腾讯企点怎么注册
  • 电商网站建设 网站定制开发条友网
  • 设计logo网站免费奇米seo快速优化文章排名
  • 响水做网站的价格竞价推广托管服务
  • 贵阳网站开发培训一周热点新闻
  • 如果域名网站用来做违法近期的新闻热点
  • 网易云wordpress代码关键词是网站seo的核心工作
  • 网站配置优化seo排名优化推广
  • 江西网站建设费用网络推广计划方案
  • 深圳做网站的给说seo研究学院
  • 国外 电子 商务 网站 欣赏知乎软文推广
  • 网站链接太多怎么做网站地图googleplaystore
  • 电子商务网站建设与实例网络热词2022