本期知识小报的主要内容包括:

  • • Lombok 之 @Builder 注解与 JSON 反序列化的冲突

  • • 如何动态设置日志输出级别

  • • JWT的生成原理和误区

  • • Java 8 parallelStream 避坑指南

Lombok 之 @Builder 注解与 JSON 反序列化的冲突

Lombok 是 Java 开发中常见的工具,可以极大提高开发效率,对冗余代码进行简化。@Builder 是 Lombok 提供的一个快速实现建造者模式的注解。通过该注解,便可以直接进行参数的链式调用构造, 如下所示:

@Builder
@Data
public class ItemData {/*** 商品id*/public Long itemId;/*** 商品标题*/public String itemTitle;}
ItemData itemData = ItemData.builder().itemId(123456L).itemTitle("闲小鱼").build();

一切都看起来非常优雅,直到我们使用 fastjson 进行序列化和反序列化,看似再正常不过的代码,居然抛了如下异常

ItemData itemData = ItemData.builder().itemId(123456L).itemTitle("闲小鱼").build();
//fastjson序列化
String itemString = JSONObject.toJSONString(itemData);
//fastjson反序列化
ItemData deserializeItem = JSON.parseObject(itemString, ItemData.class);

通过源码分析得知,fastjson 实例化对象优先使用无参构造函数,其次再使用 public 修饰的带参构造函数。因此反编译看下 @Builder 注解帮我们生成的代码,可以看到只有一个带全部参数的构造函数供 Builder 类内部类使用,并且该构造函数没有被 public 修饰,因此反序列化时 fastjon 无法进行实例化对象。

针对上述问题,我们在使用 @Builder 注解时,建议配合 @NoArgsConstructor @AllArgsConstructor 这两个注解使用,可以避免一些情况下的的反序列化问题(jackson , Gson 等序列化框架也会有此问题)。

@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ItemData {/*** 商品id*/public Long itemId;/*** 商品标题*/public String itemTitle;}

如何动态设置日志输出级别

日志输出级别定义取决于日志框架,如常见的日志框架Log4j中支持8种日志级别,从低到高依次为OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL;而Logback中支持7种日志级别,从低到高依次为OFF、ERROR、WARN、INFO、DEBUG、TRACE、ALL。日志打印级别由日志配置文件声明,在应用启动时便根据配置文件指定了相关Logger的日志打印级别。那么在应用运行过程中,如何动态变更日志输出级别呢?

对于单台机器,可以使用arthas(阿里巴巴开源的超实用JAVA监控诊断工具)来快速的查看和重置指定Logger的日志打印级别。输入命令logger,查看当前机器上所有Logger的相关信息。

输入命令logger --name root --level debug -c 2dde1bff (--name指定Logger名称,--level指定修改到的日志级别) 这里,笔者将主日志日志打印级别调整到了DEBUG。

那么对于线上机器集群,如何实现日志级别动态调整呢?答:通过配置中心 + LoggingSystem(org.springframework.boot.logging.LoggingSystem)来实现。LoggingSystem会帮我们屏蔽掉底层具体的日志框架,实现统一的日志操作。这里,笔者为大家提供一个工具类。

@Service
public class LoggerLevelAdjustService {@Autowiredprivate LoggingSystem loggingSystem;/*** 设置主日志(ROOT Logger)的日志输出级别* @param newLevel 要设置到的日志输出级别* @return void*/public void setRootLoggerLevel(String newLevel){setLoggerLevel(ROOT_LOGGER_NAME, newLevel);}/**** @param loggerName logger name* @param newLevel 要设置到的日志输出级别* @return void*/public void setLoggerLevel(String loggerName, String newLevel){if (StringUtils.isEmpty(newLevel)) {return;}for (LogLevel level : LogLevel.values()) {if (level.name().equals(newLevel)) {loggingSystem.setLogLevel(loggerName, level);}}}
}

之后,只需要在配置中心接收配置推送的代码中,调用工具类中修改日志输出级别的方法,即可实现日志输出级别的动态调整。

JWT的生成原理和误区

JWT的全名是JSON Web Token,是一套去中心化的信息传输工业标准,在认证和信息交换领域中被较为广泛地使用。在短时效身份认证场景下,相比于传统的“cookie + session”方案,JWT使用计算替代存储,无需服务端额外存储session,可以减少数据库访问,并具有更好的扩展性。

在结构上JWT由三部分组成:Header,Payload和Signature,并使用“.”将三部分连接形成“Header.Payload.Signature”。在Header中,指明Signature生成过程使用的加密算法,明文如下:

在Payload中,放入需要被传输的信息,如:

在最终的JWT令牌中,Header和Payload会使用Base64Url算法编码为最终传输信息的前二部分。为了防止信息交换的过程中被篡改,JWT设计了第三部分Signature。Signature通过将Header和Payload的信息进行加密的方式生成,常见支持的加密算法有HS256(一种引入密钥的摘要算法),非对称加密RS256等。若我们采用HS256,则Signature的生成公式为:Signature = HS256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) 在设定HS256特定密钥后,我们可以得到Signature为zYAABCrTH4trLliHsSbmCA3Rrn0Fym5aZ5MgrlnkW9Y。最终将编码后的Header、Payload和生成的Signature使用“.”连接起来,便得到了JWT令牌(红色部分为Header,紫色为Payload,蓝色为Signature)。

显然,若在传输过程中Payload被进行了篡改,接收方使用预先定义的密钥便会生成截然不同的Signature。因此,JWT可以实现信息传输过程中的防篡改。此外,因为Payload部分仅仅是进行了编码(而非加密),所以在接收方或者第三方可以被解码为明文userId。因此,切记不能使用Payload传输密码等敏感信息。

Java 8 parallelStream 避坑指南

StreamAPI 是 Java 8 中引入的新特性,借助这个能力,开发者们可以更容易地对集合数据进行处理。除了默认的串行 Stream 之外,StreamAPI 还引入了 parallelStream ,只需一行 parallelStream() ,就可以开启多线程并行处理,进而充分发挥多核 CPU 的性能。不过在你使用它之前,最好注意以下几个问题:

  1. 1. 并行流与串行流的执行结果可能会不一致

IntStream.of(1, 2, 3).reduce(4, Integer::sum); 这是一段简单的数组元素相加,得到执行结果为 10,符合预期。 IntStream.of(1, 2, 3).parallel().reduce(4, Integer::sum);
接下来我们将这段代码改写为使用并行流来处理,在其他条件都不变的基础上,得到结果为 18,与预期结果不一致。造成这种差异的原因主要是 Stream 的并行流底层采用的是 ForkJoinPool 来执行,其线程数为运行机器的 cpu 核数-1(因此cpu核数会影响执行结果),其主要原理是把任务分成多个部分,每个部分进行独立计算最后合并。复原一下上面的例子,如下图所示:

  1. 2. 串行流并不是在所有场景下都可以带来性能提升

由上面的例子可以看出,并行流更适合处理无状态的数据,即各子任务之间关联性较弱的操作,如 map,filter 等,而 sorted、 distinct 以及 limit 等操作可能并不会带来性能上的提升,反而会因为线程的额外开销导致效率不如并行流。因此,需要视具体使用场景来评估是否使用。

  1. 3. 长耗时任务需要单独指定处理任务的线程池

parallel stream 默认使用的执行线程池为 ForkJoinPool 内部的静态 commonPool,主要用于处理没有为其单独分配线程池的任务。该线程池的大小默认为 cpu 核数-1,因此如果在其中运行长耗时的任务,极有可能造成线程池阻塞,影响当前业务甚至其他用了 parallel stream 的业务。此时更建议手动开启一个新的线程池进行任务处理,或者为 parallel stream 单独指定一个专用线程池,如下所示:

ForkJoinPool businessPool = new ForkJoinPool(4);
int sum = businessPool.submit(() -> IntStream.of(1, 2, 3).parallel().reduce(0, Integer::sum)).get();
businessPool.shutdown();

引用

Github fastjson: https://github.com/alibaba/fastjson/wiki/ASMDeserializerFactory%E8%AE%BE%E8%AE%A1

Arthas: https://arthas.aliyun.com/doc/logger.html

JWT: https://jwt.io/introduction

Java8Stream: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/Stream.html

11月小报|读小报,涨知识相关推荐

  1. 上顿号符号_标点符号常见错误,读后涨知识了

    一.文字材料中序号.标点的正确使用 1."第一.""第二."或"首先.""其次."等用顿号不规范,应该用逗号,即&quo ...

  2. 11月22日云栖精选夜读 | 送你一份Spring Boot 知识清单

    在过去两三年的Spring生态圈,最让人兴奋的莫过于Spring Boot框架.或许从命名上就能看出这个框架的设计初衷:快速的启动Spring应用.因而Spring Boot应用本质上就是一个基于Sp ...

  3. 11月30日云栖精选夜读 | 用Python告诉你,现在的房租有多高?

    杭州房租:钱塘两岸最高,奥体单间达4830元/月.不少人感叹:躲过了高房价,躲不过高房租,面对房租上涨,感觉身体被掏空.2018年的这个夏天,房租正在成为摧垮年轻人的"第一根稻草" ...

  4. 11月14日云栖精选夜读 | 动画+原理+代码,解读十大经典排序算法

    排序算法是<数据结构与算法>中最基本的算法之一. 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过 ...

  5. 11月29日云栖精选夜读:阿里传奇工程师多隆的程序世界

    摘要: 写代码写到入定,是一种什么样的体验?11月29日(本周三),<阿里技术人纪录片系列>将带大家走进大神多隆的代码世界.在此之前,我们先来重温一篇关于多隆的旧文,来自<淘宝技术这 ...

  6. 11月12日云栖精选夜读 | 2135亿!新技术的力量刚刚开始

    双11对计算能力的"脉冲"挑战,将很快通过阿里云变成全社会共享的普惠科技! 热点热议 2135亿!新技术的力量刚刚开始 作者:阿里云头条 2135亿背后,你所不知道的那些阿里瞬间 ...

  7. 11月10日云栖精选夜读:零点之战!2017双11关键技术全公开

    2019独角兽企业重金招聘Python工程师标准>>> 在距离双11已经不到10天的这个时刻,一场看不见硝烟的战争似乎已经打响.面对双11期间极为严苛的技术压力,阿里巴巴究竟是用怎样 ...

  8. 11月3日云栖精选夜读:《maven实战》读书笔记2——maven安装(windows和eclipse插件)...

    前言 由于我的工作中开发环境就是windows,IDE是eclipse,因此安装也只涉及和记录这两部分,在看书和动手的过程也就直接跳过其他部分. 笔记 windows中maven的安装 安装条件 ma ...

  9. 11月13日云栖精选夜读:阿里云中间件产品科技普惠企业,满足多场景需求

    摘要: 阿里云上的互联网中间件产品家族不久前又添了一名新成员,应用配置管理(ACM)的工具类产品.基于该产品,用户可以在微服务应用架构.分布式架构下的服务治理.应用业务场景动态推送.大数据实时计算算法 ...

  10. 11月20日云栖精选夜读:围观阿里总部:边喝茶边搞技术是一种怎样的体验?

    点击有惊喜 最近,一边喝着茶一边创造双11奇迹的阿里技术哥哥们火了.当大家感慨双11再次刷新历史的同时,也为阿里创新智能的能力而惊叹. 实际上在阿里巴巴内部,一些先进的智能技术已经运用到员工日常办公场 ...

最新文章

  1. C语言两种查找方式(分块查找,二分法)
  2. python是全栈_Python全栈之路-3-字符串
  3. MySQL_常见函数
  4. ibm liberty_使用Open Liberty的开发模式最大程度地缩短周转时间
  5. Java 8 map(),flatMap()示例
  6. 数据可视化系列(三):布局格式定方圆
  7. svn提交提示服务器文件被锁,svn被锁定怎么解决-svn被锁定的解决方法 - 河东软件园...
  8. 深度学习之RNN、LSTM及正向反向传播原理
  9. oracle job 与存储过程,讲解Oracle中JOB与存储过程的接合用法
  10. delphi自带控件操作excel
  11. 【118期分享】简约商务PPT模板免费下载
  12. 【VS开发】ClientToScreen 和ScreenToClient 用法
  13. 怎样组建家庭计算机网络,不要再求人了,教你最详细的家庭网络组建方法。
  14. 845 数组中的最长山脉
  15. 股票学习-量柱和k线-第六天
  16. requests使用案例 爬取信用中国
  17. 基于安卓的高清语音技术亮相中国国际通信展览会
  18. 图像拼接和图像融合技术(基于Opencv)
  19. appium连接ios手机
  20. 计算机工程与科学是sci,系统科学与系统工程有哪些sci期刊

热门文章

  1. 正则表达式:特殊字符之“-”(减号)
  2. Revit中绘图填充与模型填充的区别
  3. UE战棋游戏的制作流程(使用GAS来制作技能系统)
  4. vue 3 + mo.js 实现点赞粒子特效【实战】
  5. 【漫画】分享16张程序员高端漫画~
  6. java基于Springboot+vue的球鞋销售商城网站 elementui
  7. echarts 图例 两行展示
  8. 2个大厂 100亿级 超大流量 红包 架构方案
  9. windows自定义屏幕大小,分辨率大小,自定义电脑屏幕分辨率
  10. 中国甜味剂粉市场趋势报告、技术动态创新及市场预测