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

计算机科学与技术网站余姚响应式网站建设

计算机科学与技术网站,余姚响应式网站建设,枣庄住房和城市建设局网站,重庆网站建设公司夹夹虫专业这是我的第 210 期分享作者 | 王磊来源 | Java中文社群#xff08;ID#xff1a;javacn666#xff09;转载请联系授权#xff08;微信ID#xff1a;GG_Stone#xff09;本来打算写一篇《阿里巴巴为什么不允许日志输出时#xff0c;使用字符串拼接#xff1f;》的文章IDjavacn666转载请联系授权微信IDGG_Stone本来打算写一篇《阿里巴巴为什么不允许日志输出时使用字符串拼接》的文章主要是想从性能方面来说此问题可在文章写到一半进行性能测试时却发现了一个异常问题实际测试的结果和手册上描述的结果是截然相反的天撸了怎么会发生这种事情此时我的内心是拒绝的因为文章已经写了一半了啊这让我瞬间陷入了尴尬的境地。阿里巴巴的《Java开发手册》泰山版最新版是这样描述的它在第二章第三小节的第 4 条规范中指出【强制】在日志输出时字符串变量之间的拼接使用占位符的方式。说明因为 String 字符串的拼接会使用 StringBuilder 的 append() 方式有一定的性能损耗。使用占位符仅 是替换动作可以有效提升性能。正例logger.debug(Processing trade with id: {} and symbol: {}, id, symbol);从上述描述中可以看出阿里强制要求在日志输出时必须使用占位符的方式进行字符串拼接因为这样可以有效的提高程序的性能。然而当我们使用 Oracle 官方提供的 JMHJava Microbenchmark HarnessJAVA 微基准测试套件框架来测试时却发现结果和手册上描述的完全不一样。PS对 JMH 不熟悉的朋友可以看我发布的另一篇文章《Oracle官方推荐的性能测试工具简单、精准又直观》性能测试本文我们借助 Spring Boot 2.2.6 来完成测试首先我们先在 Spring Boot 的 pom.xml 中添加 JMH 框架的依赖!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-core -- dependencygroupIdorg.openjdk.jmh/groupIdartifactIdjmh-core/artifactIdversion1.23/version /dependency !-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-generator-annprocess -- dependencygroupIdorg.openjdk.jmh/groupIdartifactIdjmh-generator-annprocess/artifactIdversion1.23/versionscopeprovided/scope /dependency 这里需要注意一下一般的项目我们只需要添加 jmh-core 的依赖包就可以了但如果是 Spring Boot 项目的话我们还必须添加 jmh-generator-annprocess 包依赖并且要把 scope 设置为 provided 类型如果使用它的默认值 test 就会导致程序报错 Unable to find the resource: /META-INF/BenchmarkList。scope 值说明compile默认值它表示被依赖项目需要参与当前项目的编译、测试和运行等阶段在打包时通常也需要添加进去test表示依赖项目仅仅参与测试相关的工作在编译和运行环境下都不会被使用更别说打包了provided适用于编译和测试的阶段他不会被打包到 lib 目录下runntime仅仅适用于运行环境在编译和测试环境下都不会被使用。紧接着我们编写了完整的测试代码import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.TimeUnit;BenchmarkMode(Mode.AverageTime) // 测试完成时间 OutputTimeUnit(TimeUnit.NANOSECONDS) Warmup(iterations  2, time  1, timeUnit  TimeUnit.SECONDS) // 预热 2 轮每次 1s Measurement(iterations  5, time  3, timeUnit  TimeUnit.SECONDS) // 测试 5 轮每次 3s Fork(1) // fork 1 个线程 State(Scope.Thread) // 每个测试线程一个实例 RestController RequestMapping(/log) public class LogPrint {private final Logger log  LoggerFactory.getLogger(LogPrint.class);private final static int MAX_FOR_COUNT  100; // for 循环次数public static void main(String[] args) throws RunnerException {// 启动基准测试Options opt  new OptionsBuilder().include(LogPrint.class.getName()  .*) // 要导入的测试类.build();new Runner(opt).run(); // 执行测试}Benchmarkpublic void appendLogPrint() {for (int i  0; i  MAX_FOR_COUNT; i) { // 循环的意图是为了放大性能测试效果StringBuilder sb  new StringBuilder();sb.append(Hello, );sb.append(Java);sb.append(.);sb.append(Hello, );sb.append(Redis);sb.append(.);sb.append(Hello, );sb.append(MySQL);sb.append(.);log.info(sb.toString());}}Benchmarkpublic void logPrint() {for (int i  0; i  MAX_FOR_COUNT; i) { // 循环的意图是为了放大性能测试效果log.info(Hello, {}.Hello, {}.Hello, {}., Java, Redis, MySQL);}} } 测试结果如下从上述结果可以看出直接使用 StringBuilder 拼接的方式显然要比使用占位符的方式性能要高难道是我搞错了备注测试环境为 Spring Boot 2.2.6 RELEASE、JDK 8JDK 1.8.0_10、MacOSMacMini 2018源码分析抱着怀疑的态度我们打开了 slf4j 的源码看看占位符的底层方法到底是如何实现的于是我就顺着 log.info 方法找到了占位符最终的实现源码final public static FormattingTuple arrayFormat(final String messagePattern, final Object[] argArray, Throwable throwable) {if (messagePattern  null) {return new FormattingTuple(null, argArray, throwable);}if (argArray  null) {return new FormattingTuple(messagePattern);}int i  0;int j;// use string builder for better multicore performanceStringBuilder sbuf  new StringBuilder(messagePattern.length()  50);int L;// for 循环替换占位符for (L  0; L  argArray.length; L) {j  messagePattern.indexOf(DELIM_STR, i);if (j  -1) {// no more variablesif (i  0) { // this is a simple stringreturn new FormattingTuple(messagePattern, argArray, throwable);} else { // add the tail string which contains no variables and return// the result.sbuf.append(messagePattern, i, messagePattern.length());return new FormattingTuple(sbuf.toString(), argArray, throwable);}} else {if (isEscapedDelimeter(messagePattern, j)) {if (!isDoubleEscaped(messagePattern, j)) {L--; // DELIM_START was escaped, thus should not be incrementedsbuf.append(messagePattern, i, j - 1);sbuf.append(DELIM_START);i  j  1;} else {// The escape character preceding the delimiter start is// itself escaped: abc x:\\{}// we have to consume one backward slashsbuf.append(messagePattern, i, j - 1);deeplyAppendParameter(sbuf, argArray[L], new HashMapObject[], Object());i  j  2;}} else {// normal casesbuf.append(messagePattern, i, j);deeplyAppendParameter(sbuf, argArray[L], new HashMapObject[], Object());i  j  2;}}}// append the characters following the last {} pair.sbuf.append(messagePattern, i, messagePattern.length());return new FormattingTuple(sbuf.toString(), argArray, throwable); } 从上述源码可以看出所谓的占位符其实底层也是使用 StringBuilder 来实现的怪不得性能不如直接使用 StringBuilder。因为在进行占位符替换的时候还经过了一些列的验证才进行替换的而直接使用 StringBuilder 则可以省去这部分效验的工作。为了保证我没有搞错于是我使用 Idea 开启了调试模式调试的结果如下图所示从上图可以看出此方法就是占位符的实际执行方法那也就是说手册上写的性能问题确实是错的。于是我就随手发了一个朋友圈却发现在审纸质书的编辑也恰好是我的好友这样就可以避免这个问题会直接出现在未来的纸质书中也算是功劳一件了。扩展篇我们在 Spring Boot 中使用日志通常会这样写private final Logger log  LoggerFactory.getLogger(LogPrint.class); 并且每个类中都要写这样一行代码未免有些麻烦。此时我们可以使用 Slf4j 注解来替代上面的那行 Logger 对象创建的代码完整使用示例如下import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test;Slf4j class LogTest {Testvoid show() {log.debug(Hello, {}., Debug);log.info(Hello, {}., Info);log.error(Hello, {}., Error);} } 程序的执行结果14:33:18.377 [main] DEBUG com.example.demo.LogTestTest - Hello, Debug.14:33:18.382 [main] INFO com.example.demo.LogTestTest - Hello, Info.14:33:18.382 [main] ERROR com.example.demo.LogTestTest - Hello, Error.从上述结果可以看出日志已经正常输出到控制台了。注意Slf4j 注解属于 lombok因此要想在项目中使用 Slf4j 注解需要保证项目中已经添加了 lombok 的依赖。总结在进行日志输出时字符串变量之间的拼接要使用占位符的方式因为这样写会比较优雅。我们查了 slf4j 的源码发现占位符的底层也是通过 StringBuilder 拼接来实现的。最后的话原创不易点击「在看」下次带你一块摆地摊????。旧文为了响应国家“低碳生活绿色出行”的号召老王决定以后要骑自行车上下班不但省钱而且还不堵车最主要的是能为国家出一份力。为了达成这个目标老王 happy 的掏出了他的诺基亚老年机一顿操作在某宝买了一辆 8 成新的二八自行车幻想着从此能过上了幸福生活。但车子买回来之后却发现村东头已经放满了 2 元钱就能骑一个月的共享自行车你说气人不不但如此老王还发现自己买回来的车子不仅不好骑还不支持七天无理由退货这给老王气的回手就是一个五星差评。在看卖家这边反而一点都不着急只是冷冷的给回了一句小子我还怕你这月干完我就全职摆地摊了网店反正也不开了差评就差评呗。这个故事深刻告诉我们一个道理如果别人已经给我们提供好了“自行车”那我们就不用自己花钱再卖一个了。看到这里有人可能会问了小伙子你这是正经的技术文章不你说的这些和技术有毛关系啊这个故事和今天的主题还真有关系下面我们正式开始...往期推荐 阿里新版《Java 开发手册(泰山版)》内容解读附下载地址阿里巴巴为什么让初始化集合时必须指定大小关注下方二维码订阅更多精彩内容觉得有用请点击“在看”
http://wiki.neutronadmin.com/news/19577/

相关文章:

  • 电子商务网站的建设与流程洛阳seo
  • 培训网站平台如何推广广州番禺房价最新楼盘价格
  • 给网站做企业所得税优惠政策
  • 做个网站需要什么设备wordpress 免费采集插件
  • 四川省住房和城乡建设局网站首页网页开发流程
  • 建设部网站核对编号你的网站尚未备案 根据
  • 怎么重新网站做301网站开发具体步骤
  • 物流案例 网站深圳市测绘建设局网站
  • 如何申请网站优化工作广州网站备案
  • 做网站的费用如何写分录非经营备案网站能贴放广告么
  • 学仿网站360建筑网怎么找回密码
  • jsp网站开发与数据库连接网站名称怎么变更
  • 上海做网站的月薪网站seo诊断湖南岚鸿
  • 学做家常菜的网站ps网页模板
  • vue框架做的网站软件商店打不开怎么办
  • 成都成仁路网站建设仁怀那里可以做网站
  • 外国黄冈网站推广平台专业沈阳网站制作
  • 关键词带淘宝的网站不收录万和城官方网站
  • 兼职 做网站中国空间站机械臂
  • wordpress 站点描述微信服务号绑定网站
  • discuz怎么做网站地图全屏网站模板
  • 做外文翻译的网站高端网站建设系统
  • 制作外贸网站模板下载专做国际时事评论网站
  • 网站域名注册机制个人建购物网站 备案
  • 免费的行情网站ifind是宠物网站开发背景
  • 企业网站建设费怎么记账dw网页制作考试题目
  • 企业网站建设专业精准丨 鸣远科技东莞网站建设哪里找
  • 无锡 网站 seo 优化网站开发人员晋升体系
  • 做十个网站制作网页原型的目的
  • 合肥做网站设计网站收录大全