关于java:Redis开发注意项

一、键值设计1. key名设计(1)【倡议】: 可读性和可管理性以业务名(或数据库名)为前缀(避免key抵触),用冒号分隔,比方业务名:表名:idugc:video:1 (2)【倡议】:简洁性保障语义的前提下,管制key的长度,当key较多时,内存占用也不容忽视,例如:user:{uid}:friends:messages:{mid}简化为u:{uid}:fr:m:{mid} (3)【强制】:不要蕴含特殊字符反例: 蕴含空格、换行、单双引号以及其余转义字符 2. value设计(1)【强制】:回绝bigkey(避免网卡流量、慢查问)string类型管制在10KB以内,hash、list、set、zset元素个数不要超过5000。 反例: 一个蕴含200万个元素的list。 非字符串的bigkey,不要应用del删除,应用hscan、sscan、zscan形式渐进式删除,同时要留神避免bigkey过期工夫主动删除问题(例如一个200万的zset设置1小时过期,会触发del操作,造成阻塞,而且该操作不会呈现在慢查问中(latency可查))。 (2)【举荐】:抉择适宜的数据类型。例如:实体类型(要正当管制和应用数据结构内存编码优化配置,例如ziplist,但也要留神节俭内存和性能之间的均衡) 反例:set user:1:name tomset user:1:age 19set user:1:favor football 正例:hmset user:1 name tom age 19 favor football 二、命令应用1.【举荐】 O(N)命令关注N的数量例如hgetall、lrange、smembers、zrange、sinter等并非不能应用,然而须要明确N的值。有遍历的需要能够应用hscan、sscan、zscan代替。 2.【举荐】:禁用命令禁止线上应用keys、flushall、flushdb等,通过redis的rename机制禁掉命令,或者应用scan的形式渐进式解决。 3.【举荐】正当应用selectredis的多数据库较弱,应用数字进行辨别,很多客户端反对较差,同时多业务用多数据库理论还是单线程解决,会有烦扰。 4.【举荐】应用批量操作提高效率原生命令:例如mget、mset。非原生命令:能够应用pipeline提高效率。但要留神管制一次批量操作的元素个数 (例如500以内,理论也和元素字节数无关)。 留神两者不同: 原生是原子操作,pipeline是非原子操作。pipeline能够打包不同的命令,原生做不到。pipeline须要客户端和服务端同时反对。【倡议】Redis事务性能较弱,不倡议过多应用。5.【倡议】Redis事务性能较弱,不倡议过多应用Redis的事务性能较弱(不反对回滚),而且集群版本(自研和官网)要求一次事务操作的key必须在一个slot上(能够应用hashtag性能解决) 6.【倡议】Redis集群版本在应用Lua上有特殊要求:所有key都应该由 KEYS 数组来传递,redis.call/pcall 外面调用的redis命令,key的地位,必须是KEYS array, 否则间接返回error,"-ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array"所有key,必须在1个slot上,否则间接返回error, "-ERR eval/evalsha command keys must in same slot"7.【倡议】必要状况下应用monitor命令时,要留神不要长时间应用。 ...

February 17, 2023 · 2 min · jiezi

关于java:一口气说出-6-种实现延时消息的方案还有谁不会

原文:juejin.cn/post/6844904150703013901 延时音讯(定时音讯)指的在分布式异步音讯场景下,生产端发送一条音讯,心愿在指定延时或者指定工夫点被生产端生产到,而不是立即被生产。 延时音讯实用的业务场景十分的宽泛,在分布式系统环境下,延时音讯的性能个别会在下沉到中间件层,通常是 MQ 中内置这个性能或者内聚成一个公共根底服务。 本文旨在探讨常见延时音讯的实现计划以及方案设计的优缺点。 实现计划基于内部存储实现的计划这里探讨的内部存储指的是在 MQ 自身自带的存储以外又引入的其余的存储系统。基于内部存储的计划实质上都是一个套路,将 MQ 和 延时模块 辨别开来,延时音讯模块是一个独立的服务/过程。延时音讯先保留到其余存储介质中,而后在音讯到期时再投递到 MQ。当然还有一些细节性的设计,比方音讯进入的延时音讯模块时曾经到期则间接投递这类的逻辑,这里不展开讨论。 下述计划不同的是,采纳了不同的存储系统。 基于 数据库(如MySQL)基于关系型数据库(如MySQL)延时音讯表的形式来实现。 CREATE TABLE `delay_msg` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT, `delivery_time` DATETIME NOT NULL COMMENT '投递工夫', `payloads` blob COMMENT '音讯内容', PRIMARY KEY (`id`), KEY `time_index` (`delivery_time`))通过定时线程定时扫描到期的音讯,而后进行投递。定时线程的扫描距离实践上就是你延时音讯的最小工夫精度。 举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practice长处: 实现简略;毛病: B+Tree索引不适宜音讯场景的大量写入;基于 RocksDBRocksDB 的计划其实就是在上述计划上抉择了比拟适合的存储介质。 RocksDB 应用的是LSM Tree,LSM 树更适宜大量写入的场景。滴滴开源的DDMQ中的延时音讯模块 Chronos 就是采纳了这个计划。 DDMQ 这个我的项目简略来说就是在 RocketMQ 里面加了一层对立的代理层,在这个代理层就能够做一些性能维度的扩大。延时音讯的逻辑就是代理层实现了对延时音讯的转发,如果是延时音讯,会先投递到 RocketMQ 中 Chronos 专用的 topic 中。延时音讯模块 Chronos 生产失去延时音讯转储到 RocksDB,前面就是相似的逻辑了,定时扫描到期的音讯,而后往 RocketMQ 中投递。 ...

February 17, 2023 · 2 min · jiezi

关于java:面试官熔断和降级有什么区别

熔断和降级都是零碎自我爱护的一种机制,但二者又有所不同,它们的区别次要体现在以下几点: 概念不同触发条件不同归属关系不同1.概念不同1.1 熔断概念“熔断”一词晚期来自股票市场。熔断(Circuit Breaker)也叫主动停盘机制,是指当股指波幅达到规定的熔断点时,交易所为管制危险采取的暂停交易措施。比方 2020 年 3 月 9 日,纽约股市收盘呈现暴涨,随后跌幅达到 7% 下限,触发熔断机制,进行交易 15 分钟,复原交易后跌幅有所减缓。 而熔断在程序中,示意“断开”的意思。如产生了某事件,程序为了整体的稳定性,所以临时(断开)进行服务一段时间,以保障程序可用时再被应用。 如果没有熔断机制的话,会导致联机故障和服务雪崩等问题,如下图所示: 1.2 降级概念降级(Degradation)升高级别的意思,它是指程序在呈现问题时,仍能保障无限性能可用的一种机制。 比方电商交易系统在双 11 时,应用的人比拟多,此时如果凋谢所有性能,可能会导致系统不可用,所以此时能够开启降级性能,优先保障领取性能可用,而其余非核心性能,如评论、物流、商品介绍等性能能够临时敞开。 所以,从上述信息能够看出:降级是一种退而求其次的抉择,而熔断却是整体不可用。 2.触发条件不同不同框架的熔断和降级的触发条件是不同的,本文咱们以经典的 Spring Cloud 组件 Hystrix 为例,来阐明触发条件的问题。 2.1 Hystrix 熔断触发条件默认状况 hystrix 如果检测到 10 秒内申请的失败率超过 50%,就触发熔断机制。之后每隔 5 秒从新尝试申请微服务,如果微服务不能响应,持续走熔断机制。如果微服务可达,则敞开熔断机制,恢复正常申请。 2.2 Hystrix 降级触发条件默认状况下,hystrix 在以下 4 种条件下都会触发降级机制: 办法抛出 HystrixBadRequestException办法调用超时熔断器开启拦挡调用线程池或队列或信号量已满尽管 hystrix 组件的触发机制,不能代表所有的熔断和降级机制,但足矣阐明此问题。 3.归属关系不同熔断时可能会调用降级机制,而降级时通常不会调用熔断机制。因为熔断是从全局登程,为了保证系统稳定性而停用服务,而降级是退而求其次,提供一种保底的解决方案,所以它们的归属关系是不同(熔断 > 降级)。 题外话当然,某些框架如 Sentinel,它晚期在 Dashboard 控制台中可能叫“降级”,但在新版中新版本又叫“熔断”,如下图所示: 但在两个版本中都是通过同一个异样类型 DegradeException 来监听的,如下代码所示: 所以,在 Sentinel 中,熔断和降级性能指的都是同一件事,也侧面证实了“熔断”和“降级”概念的相似性。但咱们要晓得它们实质上是不同的,就像两个双胞胎,不能因为他们长得像,就说他们是同一个人。 总结熔断和降级都是程序在我爱护的一种机制,但二者在概念、触发条件、归属关系上都是不同的。熔断更偏差于全局视角的自我爱护(机制),而降级则偏差于具体模块“退而请其次”的解决方案。

February 17, 2023 · 1 min · jiezi

关于java:Java代码工具快速生成词云图强烈建议收藏

“词云”一词最早是由美国西北大学新闻学副教授、新媒体业余主任里奇戈登(Rich Gordon)提出的。词云(Word Cloud),又称文字云、标签云(Tag Cloud)、关键词云(Keyword Cloud),是对文本信息中肯定数量的关键词呈现的频率高下状况的一种可视化展示形式,它个别是由文本数据中提取的词汇组成某些黑白图形。在网络上查了很多材料,如果用java原生的形式进行代码开发还是非常复杂的,须要肯定的工夫能力开发进去,费时费力,成果还不肯定好。为此百度了大量材料,发现一个平台“昂焱数据”(www.ayshuju.com),该平台上的“代码工具”一栏有Java版的词云生成代码工具,简略调用一下办法就能够生成词云图,这里将该代码工具的应用步骤做一下记录。 第一步:下载并装置jar到本地maven库登录该网站,在“代码工具”一栏找到“关键词词频与词云图生成”代码工具,代码工具如下图所示:下载该代码工具并解压,双击“”执行,将提醒的maven坐标粘贴到我的项目的pom文件中即可。第二步:将该jar包的maven坐标粘贴到我的项目的pom文件中第三步:残缺的测试代码如下 package com.example.demo.test;import com.angyan.tool.wordcloud.dto.WordCloudConfig;import com.angyan.tool.wordcloud.util.WordCloudUtil;import com.angyan.tool.wordcloud.wordcolud.WordCloudEngine;import com.kennycason.kumo.CollisionMode;import com.kennycason.kumo.bg.CircleBackground;import com.kennycason.kumo.font.KumoFont;import com.kennycason.kumo.font.scale.LinearFontScalar;import com.kennycason.kumo.image.AngleGenerator;import java.awt.*;public class Test { public static void main(String[] args) { String content="全面推动农村振兴是新时代建设农业强国的重要工作。要把人力投入、物力配置、财力保障都转移到农村振兴上来,全面推动产业、人才、文化、生态、组织“五个振兴”。要认真贯彻落实地方一号文件部署要求,保持农业农村优先发展,保持城乡交融倒退,强化科技翻新和制度翻新,坚定守牢确保粮食安全、避免规模性返贫等底线,扎实推动农村倒退、农村建设、农村治理等重点工作。要抓紧抓好食粮和重要农产品稳产保供,增强农业基础设施建设,强化农业科技和配备撑持,坚固拓展脱贫攻坚成绩,推动农村产业高质量倒退,拓宽农民增收致富渠道,扎实推动宜居宜业和美农村建设,健全党组织领导的农村治理体系,强化政策保障和体制机制翻新。"; int size = 60; String outPath="D:\\workplace\\test\\wordCloud.png"; // --词云图配置-- WordCloudConfig wordCloudConfig = new WordCloudConfig(); // 宽度(px像素) wordCloudConfig.setWidth(300); // 高度(px像素) wordCloudConfig.setHeight(300); // 碰撞模式 wordCloudConfig.setCollisionMode(CollisionMode.PIXEL_PERFECT); // 调节词云的稠密水平,越高越稠密 wordCloudConfig.setPadding(2); // 背景色彩 wordCloudConfig.setBackgroundColor(new Color(0, 0, 0)); // 词云形态,如圆形,半径为宽度的一半 wordCloudConfig.setBackground(new CircleBackground(150)); // 设置字体 wordCloudConfig.setKumoFont(new KumoFont(new Font("楷体", Font.BOLD, 9))); // 字号的大小范畴,最小是多少,最大是多少 wordCloudConfig.setFontScalar(new LinearFontScalar(9, 60)); // 色彩模板,不同频率的色彩会不同 wordCloudConfig.setColorPalette(WordCloudEngine.buildRandomColorPalette(9)); // 设置偏转角,角度为0时,字体都是程度的 wordCloudConfig.setAngleGenerator(new AngleGenerator(0, 0, 2)); WordCloudUtil.getWordCloudPath(content,size,wordCloudConfig,outPath); }}运行后,会在“D:/workplace/test”下生成一张“wordCloud.png”图片,具体成果如下: ...

February 16, 2023 · 1 min · jiezi

关于java:Java泛型和迭代器

泛型1.为什么要用泛型?在泛型没有诞生之前,咱们常常会遇到这样的问题,如以下代码所示: ArrayList arrayList = new ArrayList();arrayList.add("Java");arrayList.add(24);for (int i = 0; i < arrayList.size(); i++) { String str = (String) arrayList.get(i); System.out.println(str);}看起来如同没有什么大问题,也能失常编译,但真正运行起来就会报错: Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Stringat xxx(xxx.java:12)类型转换出错,当咱们给 ArrayList 放入不同类型的数据,却应用一种类型进行接管的时候,就会呈现很多相似的谬误,可能更多的时候,是因为开发人员的不小心导致的。那有没有好的方法能够杜绝此类问题的产生呢?这个时候 Java 语言提供了一个很好的解决方案——“泛型”。 2.泛型介绍泛型:泛型实质上是类型参数化,解决了不确定对象的类型问题。泛型的应用,请参考以下代码: ArrayList<String> arrayList = new ArrayList();arrayList.add("Java");这个时候如果给 arrayList 增加非 String 类型的元素,编译器就会报错,揭示开发人员插入雷同类型的元素。 报错信息如下图所示: 这样就能够防止结尾示例中,类型不统一导致程序运行过程中报错的问题了。 3.泛型的长处泛型的长处次要体现在以下三个方面。 平安:不必放心程序运行过程中呈现类型转换的谬误。防止了类型转换:如果是非泛型,获取到的元素是 Object 类型的,须要强制类型转换。可读性高:编码阶段就明确的晓得汇合中元素的类型。迭代器(Iterator)1.为什么要用迭代器?咱们回忆一下,在迭代器(Iterator)没有呈现之前,如果要遍历数组和汇合,须要应用办法。 数组遍历,代码如下: String[] arr = new String[]{"Java", "Java虚拟机", "Java中文社群"};for (int i = 0; i < arr.length; i++) { String item = arr[i];}汇合遍历,代码如下: ...

February 16, 2023 · 2 min · jiezi

关于java:Spring-学习笔记Import-注解

@Import 是一个能让类生成为 Spring Bean 的注解。 @Import 注解它次要是配合 ImportSelector 和 @ImportBeanDefinitionRegistrar 的子类,或者一般的 Java Bean 类应用。 @Import 注解源码@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Import { /** * 须要引入的类,通常是 @ImportSelector , @ImportBeanDefinitionRegistrar 的子类;或者是当成其余一般的 Bean 来应用。 */ Class<?>[] value();}一般 Bean 用法在 @Import 注解导入一般 Bean 时,这个一般 Bean 必须要有无参构造方法,不然的话会报错。 例子 @SpringBootTest@Import(ImportNormalBeanTest.NormalBeanClass.class)public class ImportNormalBeanTest { @Autowired ApplicationContext ctx; @Test void testNormalBean(){ NormalBeanClass bean = ctx.getBean(NormalBeanClass.class); System.out.println(bean); } public static class NormalBeanClass{ @Override public String toString() { return "normal bean"; } }}测试后果 ...

February 16, 2023 · 9 min · jiezi

关于java:快速搭建一个网关服务动态路由鉴权一网打尽含流程图

作者:热黄油啤酒 \链接:https://juejin.cn/post/700475... 前言本文记录一下我是如何应用Gateway搭建网关服务及实现动静路由的,帮忙大家学习如何疾速搭建一个网关服务,理解路由相干配置,鉴权的流程及业务解决,有趣味的肯定看到最初,非常适合没接触过网关服务的同学当作入门教程。搭建服务框架SpringBoot 2.1 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.0.RELEASE</version></parent>Spring-cloud-gateway-core <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-gateway-core</artifactId></dependency>common-lang3 <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId></dependency>举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practice路由配置网关作为申请对立入口,路由就相当于是每个业务零碎的入口,通过路由规定则能够匹配到对应微服务的入口,将申请命中到对应的业务零碎中server: port: 8080spring: cloud: gateway: enabled: true routes: - id: demo-server uri: http://localhost:8081 predicates: - Path=/demo-server/** filters: - StripPrefix= 1routes 配置项形容id路由惟一id,应用服务名称即可uri路由服务的拜访地址predicates路由断言filters过滤规定解读配置当初有一个服务demo-server部署在本机,地址和端口为127.0.0.1:8081,所以路由配置uri为:http://localhost:8081应用网关服务路由到此服务,predicates -Path=/demo-server/**,网关服务的端口为8080,启动网关服务,拜访localhost:8080/demo-server,路由断言就会将申请路由到demo-server间接拜访demo-server的接口localhost:8081/api/test,通过网关的拜访地址则为localhost:8080/demo-server/api/test,predicates配置将申请断言到此路由,filters-StripPrefix=1代表将地址中/后的第一个截取,所以demo-server就截取掉了应用gateway通过配置文件即可实现路由的配置,十分不便,咱们只有充沛的理解配置项的含意及规定就能够了;然而这些配置如果要批改则须要重启服务,重启网关服务会导致整个零碎不可用,这一点是无奈承受的,上面介绍如何通过Nacos实现动静路由动静路由应用nacos联合gateway-server实现动静路由,咱们须要先部署一个nacos服务,能够应用docker部署或下载源码在本地启动,具体操作能够参考官网文档即可Nacos配置 groupId: 应用网关服务名称即可 dataId: routes 配置格局: json [{ "id": "xxx-server", "order": 1, #优先级 "predicates": [{ #路由断言 "args": { "pattern": "/xxx-server/**" }, "name": "Path" }], "filters":[{ #过滤规定 "args": { "parts": 0 #k8s服务外部拜访容器为http://xxx-server/xxx-server的话,配置0即可 }, "name": "StripPrefix" #截取的开始索引 }], "uri": "http://localhost:8080/xxx-server" #指标地址 }]json格局配置项与yaml中对应,须要理解配置在json中的写法比对一下json配置与yaml配置{ "id":"demo-server", "predicates":[ { "args":{ "pattern":"/demo-server/**" }, "name":"Path" } ], "filters":[ { "args":{ "parts":1 }, "name":"StripPrefix" } ], "uri":"http://localhost:8081"}spring: cloud: gateway: enabled: true routes: - id: demo-server uri: http://localhost:8081 predicates: - Path=/demo-server/** filters: - StripPrefix= 1代码实现Nacos实现动静路由的形式外围就是通过Nacos配置监听,配置产生扭转后执行网关相干api创立路由 ...

February 16, 2023 · 3 min · jiezi

关于java:Quartz-相关线程

咱们在后面文章中说到过Quartz波及到的线程,然而散落在几篇文章中,不好找。而Quartz波及到的线程对于了解Quartz也比拟重要,所以明天专门提取进去独自说一下。 Quartz中的次要线程: 任务调度线程QuartzSchedulerThread工作执行线程Misfire解决线程ClusterManager线程任务调度线程 QuartzSchedulerThreadQuartzSchedulerThread是任务调度线程,他的职责是对满足触发条件(nextFireTimer到了)的注册到JobStore的Trigger调配给可用的工作执行线程去执行。 QuartzSchedulerThread启动任务调度线程QuartzSchedulerThread是在调度器Scheduler创立的时候启动的。 应用层通过以下调用创立Scheduler: Scheduler sche = new StdSchedulerFactory().getScheduler();个别状况下通过StdSchedulerFactory构建Scheduler,getScheduler首先尝试从SchedulerRepository获取Schedule,首次运行获取不到,则通过instantiate()办法获取。 public Scheduler getScheduler() throws SchedulerException { if (cfg == null) { initialize(); } SchedulerRepository schedRep = SchedulerRepository.getInstance(); Scheduler sched = schedRep.lookup(getSchedulerName()); if (sched != null) { if (sched.isShutdown()) { schedRep.remove(getSchedulerName()); } else { return sched; } } sched = instantiate(); return sched; }instantiate()办法特地特地特地长,简直就是在这里实现Quartz所有相干组件的初始化的。 其中会创立QuartzScheduler,之后会将QuartzScheduler包装到stdScheduler中存入SchedulerRepository。 instantiate()创立QuartzScheduler是调用的构造方法: public QuartzScheduler(QuartzSchedulerResources resources, long idleWaitTime, @Deprecated long dbRetryInterval) throws SchedulerException { this.resources = resources; if (resources.getJobStore() instanceof JobListener) { addInternalJobListener((JobListener)resources.getJobStore()); } this.schedThread = new QuartzSchedulerThread(this, resources); ThreadExecutor schedThreadExecutor = resources.getThreadExecutor(); schedThreadExecutor.execute(this.schedThread); if (idleWaitTime > 0) { this.schedThread.setIdleWaitTime(idleWaitTime); } jobMgr = new ExecutingJobsManager(); addInternalJobListener(jobMgr); errLogger = new ErrorLogger(); addInternalSchedulerListener(errLogger); signaler = new SchedulerSignalerImpl(this, this.schedThread); getLog().info("Quartz Scheduler v." + getVersion() + " created."); }能够看到构造方法中创立了QuartzSchedulerThread对象,之后获取ThreadExecutor(个别状况下为DefaultThreadExecutor)并通过调用其execute办法启动QuartzSchedulerThread线程: ...

February 15, 2023 · 1 min · jiezi

关于java:Linux安装elasticsearchhead

elasticsearch-head 是一款专门针对于 elasticsearch 的客户端工具,用来展现数据。 elasticsearch-head 是基于 JavaScript 语言编写的,能够应用 Nodejs 下的包管理器 npm 部署。 1 装置Nodejsnodejs下载地址: https://nodejs.org/en/download/ 下载后上传到服务器,并解压。 进入解压的文件夹,能够查看版本: ./bin/node -v 建设 node 软连贯,变为全局变量: ln -s /home/myroot/Desktop/Vue/node-v16.16.0-linux-x64/bin/node /usr/local/bin/ 如呈现报错: ln: failed to create symbolic link '/usr/local/bin/node': Permission denied则须要批改 /usr/local/bin/node 的权限: sudo chmod 777 /usr/local/bin/nodeLinux权限相干的常识参见:https://mp.weixin.qq.com/s/r4... 批改权限后,再一次运行建设软连贯的命令。 而后查看 node 是否胜利设为全局变量: node -v 若输入为版本号,示意胜利。 同样的,建设 npm 软连贯,设为全局变量: ln -s /home/myroot/Desktop/Vue/node-v16.16.0-linux-x64/bin/npm /usr/local/bin/ 查看是否胜利: npm -v 2 装置elasticsearch-head2.1 装置下载地址:https://github.com/mobz/elast... 下载后上传到服务器并解压。 进入装置目录: cd elasticsearch-head-5.0.0执行命令装置: npm install启动服务: npm run start或者后盾启动: ...

February 15, 2023 · 1 min · jiezi

关于java:时隔多年这次我终于把动态代理的源码翻了个地儿朝天

本文内容整顿自 博学谷狂野架构师 动静代理简介 Proxy模式是罕用的设计模式,其特色是代理类与委托类有同样的接口,代理类次要负责为委托类预处理音讯、过滤音讯、把音讯转发给委托类,以及预先解决音讯等。 用户能够更加结构图,本人编码实现Proxy模式。这种实现称为动态代理。 Java提供了java.lang.reflect.Proxy类与InvocationHandler接口,配合反射,能够实现动静代理。动态代理的代理类与代理操作,都是当时编码,运行过程种无奈批改代理构造。动静代理的代理与代理操作,都是在运行过程中,动静生成,能够在运行过程中,批改代理构造,合乎面向对象的开闭准则。 最最最次要的起因就是,在不扭转指标对象办法的状况下对办法进行加强,比方,咱们心愿对办法的调用减少日志记录,或者对办法的调用进行拦挡,等等... 动静代理用于将在不须要批改原代码的状况下进行代码的减少,spring中的AOP,事务,都是应用动静代理来实现的,咱们天天都在应用动静代理只是本人不晓得而已。 动静代理三大因素须要定义一个接口,java动静代理类只能代理接口(不反对抽象类),如果没有接口就要应用cjlib须要一个实现类继承这个接口编写一个加强类实现 InvocationHandler接口,代理类都须要实现InvocationHandler接口的invoke办法一个例子先定义一个接口定义一个海内代购的接口/** * 海内代购 */public interface Buying { public String buy();}编写一个实现类实现类实现接口public class BuyingImpl implements Buying { @Override public String buy() { System.out.println("开始逻辑解决"); return "买了个锤子"; }}编写一个增将类编写一个加强类,次要要包裹一个须要须要加强的对象也就是咱们的BuyingImpl,并实现InvocationHandler接口,在invoke办法中写加强实现/** * 海内代购加强类 * 留神实现 InvocationHandler * 动静代理类只能代理接口(不反对抽象类),代理类都须要实现InvocationHandler类,实现invoke办法。 * 该invoke办法就是调用被代理接口的所有办法时须要调用的 。 */public class BuingHandler implements InvocationHandler { /** * 包裹一个须要加强的指标对象 */ private Object targetObject; public BuingHandler(Object targetObject){ this.targetObject = targetObject; } /** * 获取代理类 * * @return */ public Object getProxy() { /** * 该办法用于为指定类装载器、一组接口及调用处理器生成动静代理类实例 * 第一个参数指定产生代理对象的类加载器,须要将其指定为和指标对象同一个类加载器 * 第二个参数要实现和指标对象一样的接口,所以只须要拿到指标对象的实现接口 * 第三个参数表明这些被拦挡的办法在被拦挡时须要执行哪个InvocationHandler的invoke办法 * 依据传入的指标返回一个代理对象 */ return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this); } /** * 关联的这个实现类的办法被调用时将被执行 * InvocationHandler接口的办法 * * @param proxy 示意代理对象 * @param method 示原对象被调用的办法 * @param args 示意办法的参数 * @return 返回的是对象的一个接口 * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("前置加强"); //反射调用原始的须要加强的办法 Object value = method.invoke(targetObject, args); System.out.println("后置加强"); return value; }}这外面要留神 method 是咱们须要加强的办法,args 是咱们须要加强的参数数组 ...

February 15, 2023 · 9 min · jiezi

关于java:Transactional-与-synchronized-联合使用问题

应用 synchronized 为操作数据库办法加锁,防止并发操作,然而为办法外加上事务注解 @Transactional 则无奈完全避免并发操作,起因如下:synchronized 是针对 办法的锁 而 事务注解是 针对办法的盘绕解决 即在办法运行前开启事务 办法完结后提交事务 getTransaction(); process(); commitTransaction(); process的锁并不能束缚事务的办法 于是 呈现了 其余线程获取锁的时候 事务还没提交的状况 产生并发问题 解决办法是 将事务的获取和提交办法手动写入 process 办法中 使其纳入process 锁的束缚 @Autowiredprivate PlatformTransactionManager platformTransactionManager;@Autowiredprivate TransactionDefinition transactionDefinition;// 开启事务TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);// do something.// 提交事务platformTransactionManager.commit(transaction);

February 15, 2023 · 1 min · jiezi

关于java:Linux安装ElasticSearch

下载地址:https://www.elastic.co/cn/dow... 1 版本抉择ElasticSearch 7 及以上版本都是自带的 jdk,如果须要配置指定的 jdk 版本的话,能够在 es 的 bin 目录下找到elasticsearch-env.bat 这个文件,批改 elasticsearch-env.bat 文件,内容如下: if defined ES_JAVA_HOME ( set JAVA= "%ES_JAVA_HOME%\bin\java.exe" set JAVA_TYPE=ES_JAVA_HOME) else if defined JAVA_HOME ( rem fallback to JAVA_HOME echo "warning: usage of JAVA_HOME is deprecated, use ES_JAVA_HOME">&2 set JAVA="%JAVA_HOME%\bin\java.exe" set "ES_JAVA_HOME=%JAVA_HOME%" set JAVA_TYPE=JAVA_HOME) else ( rem use the bundled JDK (default) set JAVA="%ES_HOME%\jdk\bin\java.exe" set "ES_JAVA_HOME=%ES_HOME%\jdk" set JAVA_TYPE=bundled JDK)ElasticSearch 7.17.3 及其之前的版本反对 JDK 1.8,如果是最新版本,最低的 JDK 得 17 及其以上。 ...

February 15, 2023 · 2 min · jiezi

关于java:分布式事务解决方案

数据不会平白无故失落,也不会莫名其妙减少一、概述1、曾几何时,知了在一家小公司做我的项目的时候,都是一个服务打天下,所以波及到数据一致性的问题,都是间接用本地事务处理。2、随着工夫的推移,用户量增大了,发现一个Java服务扛不住了,于是技术大佬决定对于零碎进行降级。依据零碎的业务对于单体的一个服务进行拆分,而后对于开发人员也进行划分,一个开发人员只开发和保护一个或几个服务中的问题,大家各司其职,分工合作。 3、当然服务拆分不是欲速不达的,这是一个耗时耗力的宏大工程,大多数零碎都是进行多轮拆分,而后缓缓造成一个稳固的零碎。恪守一个核心思想:先按总体业务进行一轮拆分,前面再依据拆分后的服务模块,进行一个粗疏的拆分。 4、随着服务拆分之后,用户量是抗住了,然而发现数据都在不同的服务中存取,这就引出了一个新的问题:跨服务器,如何保证数据的一致性? 当然,跨服务的分布式系统中不仅仅这个问题,还有其余的一些列问题,如:服务可用性、服务容错性、服务间调用的网络问题等等,这里只探讨数据一致性问题。 5、说到数据一致性,大抵分为三种:强一致性、弱一致性、最终一致性。 强一致性:数据一旦写入,在任一时刻都能读取到最新的值。弱一致性:当写入一个数据的时候,其余中央去读这些数据,可能查到的数据不是最新的最终一致性:它是弱一致性的一个变种,不谋求零碎任意时刻数据要达到统一,然而在肯定工夫后,数据最终要达到统一。从这三种统一型的模型上来说,咱们能够看到,弱一致性和最终一致性一般来说是异步冗余的,而强一致性是同步冗余的,异步解决带来了更好的性能,但也须要解决数据的弥补。同步意味着简略,但也必然会升高零碎的性能。 二、实践上述说的数据一致性问题,其实也就是在说分布式事务的问题,当初有一些解决方案,置信大家多多少少都看到过,这里带大家回顾下。 2.1、二阶段提交2PC是一种强一致性设计方案,通过引入一个事务协调器来协调各个本地事务(也称为事务参与者)的提交和回滚。2PC次要分为2个阶段: 1、第一阶段:事务协调器会向每个事务参与者发动一个开启事务的命令,每个事务参与者执行筹备操作,而后再向事务协调器回复是否筹备实现。然而不会提交本地事务, 然而这个阶段资源是须要被锁住的。 2、第二阶段: 事务协调器收到每个事务参与者的回复后,统计每个参与者的回复,如果每个参与者都回复“能够提交”,那么事务协调器会发送提交命令,参与者正式提交本地事务,开释所有资源,完结全局事务。然而有一个参与者回复“回绝提交”,那么事务协调器发送回滚命令,所有参与者都回滚本地事务,待全副回滚实现,开释资源,勾销全局事务。 事务提交流程 事务回滚流程 当然2PC存在的问题这里也提一下,一个是同步阻塞,这个会耗费性能。另一个是协调器故障问题,一旦协调器产生故障,那么所有的参与者解决资源锁定状态,那么所有参与者都会被阻塞。 2.2、三阶段提交3PC次要是在2PC的根底上做了改良,次要为了解决2PC的阻塞问题。它次要是将2PC的第一阶段分为2个步骤,先筹备,再锁定资源,并且引入了超时机制(这也意味着会造成数据不统一)。 3PC的三个阶段包含:CanCommit、PreCommit 和 DoCommit 具体细节就不开展赘述了,就一个外围观点:在CanCommit的时候并不锁定资源,除非所有参与者都批准了,才开始锁资源。 2.3、TCC柔性事务相比拟后面的2PC和3PC,TCC和那哥俩的本质区别就是它是业务层面的分布式事务,而2PC和3PC是数据库层面的。TCC是三个单词的缩写:Try、Confirm、Cancel,也分为这三个流程。 Try:尝试,即尝试预留资源,锁定资源 Confirm:确认,即执行预留的资源,如果执行失败会重试 Cancel:勾销,撤销预留的资源,如果执行失败会重试 从上图可知,TCC对于业务的侵入是很大的,而且紧紧的耦合在一起。TCC相比拟2PC和3PC,试用范畴更广,可实现跨库,跨不同零碎去实现分布式事务。毛病是要在业务代码中去开发大量的逻辑实现这三个步骤,须要和代码耦合在一起,进步开发成本。 事务日志:在TCC模式中,事务发起者和事务参与者都会去记录事务日志(事务状态、信息等)。这个事务日志是整个分布式事务出现意外状况(宕机、重启、网络中断等),实现提交和回滚的要害。 幂等性:在TCC第二阶段,confirm或者cancel的时候,这两个操作都须要保障幂等性。一旦因为网络等起因导致执行失败,就会发动一直重试。 防悬挂:因为网络的不可靠性,有异常情况的时候,try申请可能比cancel申请更晚达到。cancel可能会执行空回滚,然而try申请被执行的时候也不会预留资源。 2.4、Seata对于seata这里就不多提了,用的最多的是AT模式,上回知了逐渐剖析过,配置完后只须要在事务发动的办法上增加@GlobalTransactional注解就能够开启全局事务,对于业务无侵入,低耦合。感兴趣的话请参考之前探讨Seata的内容。 三、利用场景知了之前在一家公司遇到过这样的业务场景;用户通过页面投保,提交一笔订单过去,这个订单通过上游服务,解决保单相干的业务逻辑,最初流入上游服务,解决业绩、人员降职、分润解决等等业务。对于这个场景,两边解决的业务逻辑不在同一个服务中,接入的是不同的数据库。波及到数据一致性问题,须要用到分布式事务。 对于下面介绍的几种计划,只是探讨了实践和思路,上面我来总结下这个业务场景中使用的一种实现计划。采纳了本地音讯表+MQ异步音讯的计划实现了事务最终一致性,也合乎过后的业务场景,绝对强一致性,实现的性能较高。上面是该计划的思路图 实在业务解决的状态可能会有多种,因而须要明确哪种状态须要定时工作弥补如果某条单据始终无奈解决完结,定时工作也不能无限度下发,所以本地音讯表须要减少轮次的概念,重试多少次后告警,人工染指解决因为MQ和定时工作的存在,难免会呈现反复申请,因而上游要做好幂等防重,否则会呈现反复数据,导致数据不统一对于落地实现,话不多说,间接上代码。先定义两张表tb_order和tb_notice_message,别离存订单信息和本地事务信息 CREATE TABLE `tb_order` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', `user_id` int(11) NOT NULL COMMENT '下单人id', `order_no` varchar(255) CHARACTER SET latin1 NOT NULL COMMENT '订单编号', `insurance_amount` decimal(16,2) NOT NULL COMMENT '保额', `order_amount` decimal(16,2) DEFAULT NULL COMMENT '保费', `create_time` datetime DEFAULT NULL COMMENT '创立工夫', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新工夫', `is_delete` tinyint(4) DEFAULT '0' COMMENT '删除标识:0-不删除;1-删除', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;CREATE TABLE `tb_notice_message` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', `type` tinyint(4) NOT NULL COMMENT '业务类型:1-下单', `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态:1-待处理,2-已解决,3-预警', `data` varchar(255) NOT NULL COMMENT '信息', `retry_count` tinyint(4) DEFAULT '0' COMMENT '重试次数', `create_time` datetime NOT NULL COMMENT '创立工夫', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新工夫', `is_delete` tinyint(4) NOT NULL DEFAULT '0' COMMENT '删除标识:0-不删除;1-删除', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;解决订单service,这里能够用到咱们之前说过的装璜器模式,去装璜这个service。把保留本地事务,发送mq音讯,交给装璜器类去做,而service只须要关怀业务逻辑即可,也合乎开闭准则。 ...

February 15, 2023 · 3 min · jiezi

关于java:面试官Lambda-表达式中的-forEach-如何提前终止这次被问倒了

情景展现 如上图所示,咱们想要终止for循环,应用return。 执行后果如下: 咱们能够看到,只有赵六没被打印进去,后续的数组元素仍旧被执行了。 也就是说,关键字"return",在这里执行的成果相当于一般for循环里的关键词continue"。 举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practice起因剖析 咱们晓得,在一般for循环外面,想要提前结束(终止)循环体应用"break"; 完结本轮循环,进行下一轮循环应用"continue"; 另外,在一般for里,如果应用"return",不仅强制完结for循环体,还会提前结束蕴含这个循环体的整个办法。 而在Java8中的 forEach() 中,"break"或"continue"是不被容许应用的,而return的意思也不是原来return代表的含意了。 咱们来看看源码: forEach(),说到底是一个办法,而不是循环体,完结一个办法的执行用什么? 当然是return啦; java8的forEach()和JavaScript的forEach()用法是何其的类似,感兴趣的能够去理解下(在文末)。 Java不是万能的,不要再吐槽它垃圾了。 解决方案 计划一:应用原始的foreach循环 应用过eclipse的老铁们应该晓得,当咱们输出:foreach,再按快捷键:Alt+/,就会呈现foreach的代码提醒。 如上图所示,这种格局的for循环才是真正意义上的foreach循环。 在idea中输出,依照上述操作是不会有任何代码提醒的,那如何能力在idea中,调进去呢? for循环能够提前终止。 形式一:break 形式二:return(不举荐应用) 计划二:抛出异样 咱们晓得,要想完结一个办法的执行,失常的逻辑是:应用return; 然而,在理论运行中,往往有很多不突发状况导致代码提前终止,比方:空指针异样,其实,咱们也能够通过抛出假异样的形式来达到终止forEach()办法的目标。 如果感觉这种形式不敌对,能够再包装一层。 这样,就完满了。 这里,须要留神的一点是:要确保你forEach()办法体内不能有其它代码可能会抛出的异样与本人手动抛出并捕捉的异样一样; 否则,当真正该因异样导致代码终止的时候,因为咱们手动捕捉了并且没做任何解决,岂不是搬起石头砸本人的脚吗? 起源:https://blog.csdn.net/weixin_... 近期热文举荐: 1.1,000+ 道 Java面试题及答案整顿(2022最新版) 2.劲爆!Java 协程要来了。。。 3.Spring Boot 2.x 教程,太全了! 4.别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!! 5.《Java开发手册(嵩山版)》最新公布,速速下载! 感觉不错,别忘了顺手点赞+转发哦!

February 15, 2023 · 1 min · jiezi

关于java:spring-event机制

前言在前端中咱们常常应用事件机制,如鼠标点击事件等,而在java中,java也为咱们设置了事件机制。咱们先模拟前端的事件机制,应用代码进行简略实现鼠标点击事件。 class Mouse { private List<mouselistener> listeners = new ArrayList<mouselistener>(); private int listenerCallbacks = 0; public void addListenerCallback() { listenerCallbacks++; } public int getListenerCallbacks() { return listenerCallbacks; } public void addListener(MouseListener listener) { listeners.add(listener); } public void click() { System.out.println("Clicked !"); for (MouseListener listener : listeners) { listener.onClick(this); } }} interface MouseListener { public void onClick(Mouse source);}public class EventBasedTest { @Test public void test() { Mouse mouse = new Mouse(); mouse.addListener(new MouseListener() { @Override public void onClick(Mouse mouse) { System.out.println("Listener#1 called"); mouse.addListenerCallback(); } }); mouse.addListener(new MouseListener() { @Override public void onClick(Mouse mouse) { System.out.println("Listener#2 called"); mouse.addListenerCallback(); } }); mouse.click(); }}打印输出如下所示 ...

February 14, 2023 · 2 min · jiezi

关于java:2023最新Java面试手册性能优化微服务架构并发编程开源框架

Java面试手册一、性能优化面试专栏1.1、 tomcat性能优化整顿 1.2、JVM性能优化整顿 1.3、Mysql性能优化整顿 二、微服务架构面试专栏2.1、SpringCloud面试整顿 2.2、SpringBoot面试整顿 2.3、Dubbo面试整顿 三、并发编程高级面试专栏 四、开源框架面试题专栏4.1、Spring面试整顿 4.2、SpringMVC面试整顿 4.3、MyBatis面试整顿 五、分布式面试专栏5.1、分布式限流面试整顿. 5.2、分布式通信面试整顿 5.3、分布式数据库面试整顿 注释一、性能优化专栏 1.1、tomcat性能优化整顿 二,微服务架构面试专栏1、SpringCloud面试整顿 1、什么是Spring Cloud? Spring cloud流应用程序启动器是基于Spring Boot的Spring集成应用程序,提供与内部零碎的集成。Spring cloud Task,一个生 命周期短暂的微服务框架,用于疾速构建执行无限数据处理的应用程序。 材料过多就不给大家一一展现了 获取这份面试手册的敌人们【点击此处】即可收费获取哦!

February 14, 2023 · 1 min · jiezi

关于java:这些JDK8-新特性我还是第一次听说

文章内容整顿自 博学谷狂野架构师概述什么是函数式接口?简略来说就是只有一个形象函数的接口。为了使得函数式接口的定义更加标准,java8 提供了@FunctionalInterface 注解通知编译器在编译器去查看函数式接口的合法性,以便在编译器在编译出错时给出提醒。为了更加标准定义函数接口,给出如下函数式接口定义规定:有且仅有一个形象函数必须要有@FunctionalInterface 注解能够有默认办法能够看出函数式接口的编写定义非常简单,不晓得大家有没有留神到,其实咱们常常会用到函数式接口,如Runnable 接口,它就是一个函数式接口:COPY@FunctionalInterfacepublic interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run();}过来咱们会应用匿名外部类来实现线程的执行体:COPYnew Thread(new Runnable() { @Override public void run() { System.out.println("Hello FunctionalInterface"); } }).start();当初咱们应用Lambda 表达式,这里函数式接口的应用没有体现函数式编程思维,这里输入字符到规范输入流中,产生了副作用,起到了简化代码的作用,当然还有装B。COPYnew Thread(()->{ System.out.println("Hello FunctionalInterface"); }).start();Java8 util.function 包下自带了43个函数式接口,大体分为以下几类:Consumer 生产接口Function 性能接口Operator 操作接口Predicate 断言接口Supplier 生产接口其余接口都是在此基础上变形定制化罢了。 ...

February 14, 2023 · 7 min · jiezi

关于java:开发宝典Java并发系列教程

作者:京东批发 刘跃明 Monitor概念Java对象的内存布局对象除了咱们自定义的一些属性外,还有其它数据,在内存中能够分为三个区域:对象头、实例数据、对齐填充,这三个区域组成起来才是一个残缺的对象。 对象头:在JVM中须要大量存储对象,存储时为了实现一些额定的性能,须要在对象中增加一些标记字段用于加强对象性能,这些标记字段组成了对象头。 实例数据:寄存类的属性数据信息,包含父类的属性信息。 对齐填充:因为虚拟机要求对象其实地址必须是8字节的整数倍,须要存在填充区域以满足8字节的整数倍,填充数据不是必须存在的,仅仅是为了字节对齐。 图1 Java对象头JVM中对象头的形式有以下两种(以32位虚拟机为例): 一般对象 Object Header (64 bits) Mark Word (32 bits)Klass Word (32 bits)数组对象 Object Header (96 bits) Mark Word(32bits)Klass Word(32bits)array length(32bits)Mark Word这部分次要用来存储对象本身的运行数据,如hashcode、gc分带年龄等,Mark Word的位长度为JVM的一个Word大小,也就是说32位JVM的Mark Word为32位,64位JVM为64位。为了让一个字大小存储更多的信息,JVM将字的最低两个位设置为标记位,不同标记位下的Mark Word示意如下: Mark Word (32 bits)State identity_hashcode:25age:4biased_lock:1lock:2Normal thread:23epoch:2age:4biased_lock:1lock:2Biasedptr_to_lock_record:30lock:2LightweightLocked ptr_to_heavyweight_monitor:30lock:2HeavyweightLocked lock:2Marked for GC 其中各局部的含意如下: lock: 2位的锁状态标记位,该标记的值不同,整个Mark Word示意的含意不同。 biased_locklock状态001无锁101偏差锁000轻量级锁010重量级锁011GC标记biased_lock: 对象是否启用偏差锁标记,只占1个二进制位,为1时示意对象启用偏差锁,为0时示意对象没有偏差锁。 age: 4位的Java对象年龄,在GC中,如果对象再Survivor区复制一次,年龄减少1,当对象达到设定的阈值时,将会降职到老年代,默认状况下,并行GC的年龄阈值为15,并发GC的年龄阈值为6,因为age只有4位,所以最大值为15,这就是-XX:MaxTenuringThreshold选项最大值为15的起因。 identity_hashcode: 25位的对象示意Hash码,采纳提早加载技术,调用办法System.idenHashcode()计算,并会将后果写到该对象头中,当对象被锁定时,该值会挪动到管程Monitor中。 thread: 持有偏差锁的线程ID。 epoch: 偏差工夫戳。 ...

February 14, 2023 · 6 min · jiezi

关于java:程序员健康最佳作息表建议收藏

起源:sleepyocean.github.io/pages/55d148/ 说到衰弱作息,还真是要好好总结一下,都说程序员这一行,猝死概率极高,究其原因还是很难有很好的作息法则。这里就带来“传说中”的“世界上最衰弱的作息时间表”,随时揭示本人吧,毕竟身材可是本人的哦。 7:30起床:英国威斯敏斯特大学的钻研人员发现,那些在早上5:22-7:21分起床的人,其血液中有一种能引起心脏病的物质含量较高,因而,在7:21之后起床对身体健康更加无益。 关上台灯:“一醒来,就将灯关上,这样将会从新调整体内的生物钟,调整睡眠和醒来模式。”拉夫堡大学睡眠钻研核心传授吉姆·霍恩说。喝一杯水:水是身材内成千上万化学反应得以进行的必须物质。早上喝一杯清水,能够补充早晨的缺水状态。 7:30-8:00在早饭之前刷牙:“在早饭之前刷牙能够避免牙齿的侵蚀,因为刷牙之后,能够在牙齿里面涂上一层含氟的保护层。要么,就等早饭之后半小时再刷牙。”英国牙齿协会衰弱和平安钻研人员戈登·沃特金斯说。 8:00-8:30吃早饭:“早饭必须吃,因为它能够帮忙你维持血糖程度的稳固。”伦敦大学国王学院营养师凯文·威尔伦说。早饭能够吃燕麦粥等,这类食物具备较低的血糖指数。 8:30-9:00防止静止:来自布鲁奈尔大学的钻研人员发现,在晚上进行锤炼的运动员更容易感化疾病,因为免疫系统在这个工夫的性能最弱。 步行下班:马萨诸塞州大学医学院的钻研人员发现,每天走路的人,比那些久坐不静止的人患感冒病的概率低25%。 9:30开始一天中最艰难的工作:纽约睡眠核心的钻研人员发现,大部分人在每天醒来的一两个小时内头脑最苏醒。 10:30让眼睛来到屏幕劳动一下:如果你应用电脑工作,那么每工作一小时,就让眼睛劳动3分钟。 11:00吃点水果:这是一种解决身材血糖降落的好办法。吃一个橙子或一些红色水果,这样做能同时补充体内的铁含量和维生素C含量。 13:00在面包上加一些豆类蔬菜:你须要一顿可口的午餐,并且可能迟缓地开释能量。“烘烤的豆类食品富含纤维素,番茄酱能够当作是蔬菜的一部分。”维伦博士说。 14:30-15:30午休一小会儿:雅典的一所大学钻研发现,那些每天中午午休30分钟或更长时间,每周至多午休3次的人,因心脏病死亡的概率会降落37%。 16:00喝杯酸奶:这样做能够稳固血糖程度。在每天三餐之间喝些酸牛奶,有利于心脏衰弱。 17:00-19:00锻炼身体:依据体内的生物钟,这个工夫是静止的最佳工夫,舍菲尔德大学运动学医生瑞沃·尼克说。 19:30晚餐少吃点:晚饭吃太多,会引起血糖升高,并减少消化系统的累赘,影响睡眠。晚饭应该多吃蔬菜,少吃富含卡路里和蛋白质的食物。吃饭时要细嚼慢咽。 21:45看会电视:这个工夫看会儿电视放松一下,有助于睡眠,但要留神,尽量不要躺在床上看电视,这会影响睡眠品质。 23:00洗个热水澡:“体温的适当升高有助于放松和睡眠。”拉夫堡大学睡眠钻研核心吉姆·霍恩传授说。 23:30上床睡觉:如果你早上7点30起床,当初入睡能够保障你享受8小时短缺的睡眠。 工夫、衰弱的小常识要晓得,任何试图更改生物钟的行为,都将给身材留下莫名其妙的疾病,等到20、30年之后再悔恨,曾经来不及了。上面再补充一些和工夫、衰弱无关的小常识,持续供大家参考: 早晨9-11点为免疫系统(淋巴)排毒工夫,此段时间应宁静或听音乐。晚间11-凌晨1点,肝的排毒,需在熟睡中进行。凌晨1-3点,胆的排毒,亦同。凌晨3-5点,肺的排毒。此即为何咳嗽的人在这段时间咳得最激烈,因排毒动作已走到肺;不利用止咳药,免得克制废积物的排除。凌晨5-7点,大肠的排毒,应上厕所排便。凌晨7-9点,小肠大量排汇养分的时段,应吃早餐。疗病者最好早吃,在6点半前,养生者在7点半前,不吃早餐者应扭转习惯,即便拖到9、10点吃都比不吃好。中午至凌晨4点为脊椎造血时段,必须酣睡,不宜熬夜。近期热文举荐: 1.1,000+ 道 Java面试题及答案整顿(2022最新版) 2.劲爆!Java 协程要来了。。。 3.Spring Boot 2.x 教程,太全了! 4.别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!! 5.《Java开发手册(嵩山版)》最新公布,速速下载! 感觉不错,别忘了顺手点赞+转发哦!

February 14, 2023 · 1 min · jiezi

关于java:文件上传工具类

package com.xiaoan.utils;import org.apache.commons.io.filefilter.SuffixFileFilter;import org.springframework.web.multipart.MultipartFile;import java.io.File;import java.io.IOException;import java.util.HashMap;import java.util.Map;import java.util.UUID;/** * @author 23105 * @version 1.0 * @description: 上传文件的工具类 * @date 13/2/2023 下午5:55 */public class UploadFile { //存储文件上传失败的错误信息 private static Map<String, Object> error_result = new HashMap<>(); //存储头像的上传后果信息 private static Map<String, Object> upload_result = new HashMap<>(); /** * @description: 效验所上传图片的大小及格局等信息... * @param: photo * @param: path * @return: java.util.Map<java.lang.String, java.lang.Object> */ private static Map<String, Object> uploadPhoto(MultipartFile photo, String path) { //限度头像大小(20M) int MAX_SIZE = 20971520; //获取图片的原始名称 String orginalName = photo.getOriginalFilename(); //如果保留文件的门路不存在,则创立该目录 File filePath = new File(path); if (!filePath.exists()) { filePath.mkdirs(); } //限度上传文件的大小 if (photo.getSize() > MAX_SIZE) { error_result.put("success", false); error_result.put("msg", "上传的图片大小不能超过20M哟!"); return error_result; } // 限度上传的文件类型 String[] suffixs = new String[]{".png", ".PNG", ".jpg", ".JPG", ".jpeg", ".JPEG", ".gif", ".GIF", ".bmp", ".BMP"}; SuffixFileFilter suffixFileFilter = new SuffixFileFilter(suffixs); if (!suffixFileFilter.accept(new File(path + orginalName))) { error_result.put("success", false); error_result.put("msg", "禁止上传此类型文件! 请上传图片哟!"); return error_result; } return null; } /** * @description: (提取公共代码 : 进步代码的可重用性)获取头像的上传后果信息 * @param: photo * @param: dirPaht * @param: portraitPath * @return: java.util.Map<java.lang.String, java.lang.Object> */ public static Map<String, Object> getUploadResult(MultipartFile photo, String dirPaht, String portraitPath) { if (!photo.isEmpty() && photo.getSize() > 0) { //获取图片的原始名称 String orginalName = photo.getOriginalFilename(); //上传图片,error_result:存储头像上传失败的错误信息 Map<String, Object> error_result = UploadFile.uploadPhoto(photo, dirPaht); if (error_result != null) { return error_result; } //应用UUID重命名图片名称(uuid__原始图片名称) String newPhotoName = UUID.randomUUID() + "__" + orginalName; //将上传的文件保留到目标目录下 try { photo.transferTo(new File(dirPaht + newPhotoName)); upload_result.put("success", true); upload_result.put("portrait_path", portraitPath + newPhotoName);//将存储头像的我的项目门路返回给页面 } catch (IOException e) { e.printStackTrace(); upload_result.put("success", false); upload_result.put("msg", "上传文件失败! 服务器端产生异样!"); return upload_result; } } else { upload_result.put("success", false); upload_result.put("msg", "头像上传失败! 未找到指定图片!"); } return upload_result; }}

February 13, 2023 · 2 min · jiezi

关于java:MD5加密

package com.xiaoan.utils;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;/** * @author 23105 * @version 1.0 * @description: TODO * @date 13/2/2023 下午5:52 */public final class MD5 { public static String encrypt(String strSrc) { try { char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; byte[] bytes = strSrc.getBytes(); MessageDigest md = MessageDigest.getInstance("MD5"); md.update(bytes); bytes = md.digest(); int j = bytes.length; char[] chars = new char[j * 2]; int k = 0; for (int i = 0; i < bytes.length; i++) { byte b = bytes[i]; chars[k++] = hexChars[b >>> 4 & 0xf]; chars[k++] = hexChars[b & 0xf]; } return new String(chars); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); throw new RuntimeException("MD5加密出错!!+" + e); } }}

February 13, 2023 · 1 min · jiezi

关于java:Java绘制验证码

package com.xiaoan.utils;import java.awt.*;import java.awt.image.BufferedImage;import java.util.Random;/** * @author 23105 * @version 1.0 * @description: 绘制验证码图片 * @date 13/2/2023 下午5:48 */public class CreateVerifiCodeImage { private static int WIDTH = 90; private static int HEIGHT = 35; private static int FONT_SIZE = 20; //字符大小 private static char[] verifiCode; //验证码 private static BufferedImage verifiCodeImage; //验证码图片 /** * @description: 获取验证码图片 * @param: no * @return: java.awt.image.BufferedImage */ public static BufferedImage getVerifiCodeImage() { verifiCodeImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_BGR);// create a image Graphics graphics = verifiCodeImage.getGraphics(); verifiCode = generateCheckCode(); drawBackground(graphics); drawRands(graphics, verifiCode); graphics.dispose(); return verifiCodeImage; } /** * @description: 获取验证码 * @param: no * @return: char[] */ public static char[] getVerifiCode() { return verifiCode; } /** * @description: 随机生成验证码 * @param: no * @return: char[] */ private static char[] generateCheckCode() { String chars = "0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char[] rands = new char[4]; for (int i = 0; i < 4; i++) { int rand = (int) (Math.random() * (10 + 26 * 2)); rands[i] = chars.charAt(rand); } return rands; } /** * @description: 绘制验证码 * @param: g * @param: rands * @return: void */ private static void drawRands(Graphics g, char[] rands) { g.setFont(new Font("Console", Font.BOLD, FONT_SIZE)); for (int i = 0; i < rands.length; i++) { g.setColor(getRandomColor()); g.drawString("" + rands[i], i * FONT_SIZE + 10, 25); } } /** * @description: 绘制验证码图片背景 * @param: g * @return: void */ private static void drawBackground(Graphics g) { g.setColor(Color.white); g.fillRect(0, 0, WIDTH, HEIGHT); // 绘制验证码烦扰点 for (int i = 0; i < 200; i++) { int x = (int) (Math.random() * WIDTH); int y = (int) (Math.random() * HEIGHT); g.setColor(getRandomColor()); g.drawOval(x, y, 1, 1); } } /** * @description: 获取随机色彩 * @param: no * @return: java.awt.Color */ private static Color getRandomColor() { Random ran = new Random(); return new Color(ran.nextInt(220), ran.nextInt(220), ran.nextInt(220)); }}

February 13, 2023 · 2 min · jiezi

关于java:easypoi-模板导出foreach单行多结果集合并单元格问题

上一篇文章的补充。解决遗留问题: 对mergedRegionHelper实现革新之后,不能反对模板配置为一行多个后果集、并且后果集都存在合并单元格的状况。比方: 导出数据,零碎会报错: 剖析了一下,是因为咱们尽管批改mergedRegionHelper的算法,在插入行之后不再对缓存数据做调整、而是记录了插入的行数,然而因为easypoi解决模板的的形式是从上到下、从左到右逐行、逐列解决模板的单元格。 如上图的模板,当解决到第2行第一列的时候碰到foreash,如果咱们给的数据集多于1条数据的话,就会插入行、调用mergedRegionHelper的shiftrow办法从而更新掉咱们新增的属性rowsSfhited。当持续解决到第2行的第二个foreach的时候,调用mergedRegionHelper判断是否是合并单元格的时候就会出问题,因为这个时候mergedRegionHelper的rowsShifted曾经被更新了: public boolean isMergedRegion(int row, int col) { //20230211 new added SHIFTMETHOD_KEEP_MERGEDCACHE if(shiftMethod == SHIFTMETHOD_KEEP_MERGEDCACHE) row -= rowsShifted; return mergedCache.containsKey(row + "_" + col); }想要判断的是第2行的数据,然而理论并不是第2行,所以导致谬误。 解决bug仔细分析一下批改后的mergedRegionHelper逻辑,其实咱们只有能做到当一行数据处理实现、筹备解决下一行数据的时候,更新mergedRegionHelper的rowsShfited属性,就不会有问题了。 所以咱们就找到这个逻辑的地位,在ExcelExportOfTemplateUtil#parseTemplate办法,须要初始化新增变量shiftCache(shiftCache是为了反对单行多个数据集而引入的缓存变量,用来记录每一个foreach行插入了多少行数据):而后在循环解决以后行所有列完结、要跳转到下一行的循环前,解决mergedRegionHelper: for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) { if (row.getCell(i) != null && !tempCreateCellSet .contains(row.getRowNum() + "_" + row.getCell(i).getColumnIndex())) { setValueForCellByMap(row.getCell(i), map); } } //20230212 check shifed rows from shiftCache and set to mergedRegionHelper // when we moved to the next row if(shiftCache.get(row.getRowNum()+1)!=null){ mergedRegionHelper.shiftRows(sheet, row.getRowNum(), shiftCache.get(row.getRowNum()+1), sheet.getLastRowNum()); }重跑,胜利失去后果: ...

February 13, 2023 · 1 min · jiezi

关于java:String类以及练习案例

1.1String类概述 String 类代表字符串,Java 程序中的所有字符串文字(例如“abc”)都被实现为此类的实例。也就是说,Java 程序中所有的双引号字符串,都是 String 类的对象。String 类在 java.lang 包下,所以应用的时候不须要导包! 1.2String类的特点字符串不可变,它们的值在创立后不能被更改尽管 String 的值是不可变的,然而它们能够被共享字符串成果上相当于字符数组( char[] ),然而底层原理是字节数组( byte[] )1.3String类的构造方法罕用的构造方法 办法名阐明public String()创立一个空白字符串对象,不含有任何内容public String(char[] chs)依据字符数组的内容,来创立字符串对象public String(byte[] bys)依据字节数组的内容,来创立字符串对象String s = “abc”;间接赋值的形式创立字符串对象,内容就是abc示例代码 public class StringDemo01 { public static void main(String[] args) { //public String():创立一个空白字符串对象,不含有任何内容 String s1 = new String(); System.out.println("s1:" + s1); //public String(char[] chs):依据字符数组的内容,来创立字符串对象 char[] chs = {'a', 'b', 'c'}; String s2 = new String(chs); System.out.println("s2:" + s2); //public String(byte[] bys):依据字节数组的内容,来创立字符串对象 byte[] bys = {97, 98, 99}; String s3 = new String(bys); System.out.println("s3:" + s3); //String s = “abc”; 间接赋值的形式创立字符串对象,内容就是abc String s4 = "abc"; System.out.println("s4:" + s4); }}1.4创立字符串对象两种形式的区别通过构造方法创立 ...

February 13, 2023 · 7 min · jiezi

关于java:为什么这11道JVM面试题这么重要附答案

本文内容整顿自 博学谷狂野架构师运行时数据区都蕴含什么 虚拟机的根底面试题程序计数器Java 虚拟机栈本地办法栈Java 堆办法区程序计数器程序计数器是线程公有的,并且是JVM中惟一不会溢出的区域,用来保留线程切换时的执行行数程序计数器(Program Counter Register)是一块较小的内存空间,能够看作是以后线程所执行字节码的行号指示器。分支、循环、跳转、异样解决、线程复原等根底性能都须要依赖这个计数器实现。 因为 Java 虚拟机的多线程是通过线程轮流切换并调配处理器执行工夫的形式实现的。为了线程切换后能复原到正确的执行地位,每条线程都须要一个独立的程序计数器,各线程之间的计数器互不影响,独立存储。 如果线程正在执行的是一个 Java 办法,计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是 Native 办法,这个计数器的值为空。程序计数器是惟一一个没有规定任何 OutOfMemoryError 的区域 虚拟机栈Java 虚拟机栈(Java Virtual Machine Stacks)是线程公有的,生命周期与线程雷同。虚拟机栈形容的是 Java 办法执行的内存模型:每个办法被执行的时候都会创立一个栈帧(Stack Frame),存储 每一个办法被调用到执行实现的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程 组成部分局部变量表操作数栈动静链接办法进口异常情况StackOverflowError:线程申请的栈深度大于虚拟机所容许的深度OutOfMemoryError:虚拟机栈扩大到无奈申请足够的内存时本地办法栈本地办法栈(Native Method Stacks)为虚拟机应用到的 Native 办法服务Java 堆Java 堆(Java Heap)是 Java 虚拟机中内存最大的一块。Java 堆在虚拟机启动时创立,被所有线程共享。作用:寄存对象实例。垃圾收集器次要治理的就是 Java 堆。Java 堆在物理上能够不间断,只有逻辑上间断即可。 蕴含元素对象数组非动态变量有什么异样java.lang.OutOfMemoryError: Java heap space:这种是java堆内存不够,一个起因是真不够,另一个起因是程序中有死循环java.lang.OutOfMemoryError: GC overhead limit exceeded:JDK6新增谬误类型,当GC为开释很小空间占用大量工夫时抛出办法区办法区(Method Area)被所有线程共享,用于存储已被虚拟机加载的类信息、常量、动态变量、即时编译器编译后的代码等数据。和 Java 堆一样,不须要间断的内存,能够抉择固定的大小,更能够抉择不实现垃圾收集。 垃圾回收算法有哪些罕用的垃圾回收算法有如下四种:标记-革除、复制、标记-整顿和分代收集。标记-革除算法从算法的名称上能够看出,这个算法分为两局部,标记和革除。首先标记出所有须要被回收的对象,而后在标记实现后对立回收掉所有被标记的对象。 这个算法简略,然而有两个毛病:一是标记和革除的效率不是很高;二是标记和革除后会产生很多的内存碎片,导致可用的内存空间不间断,当调配大对象的时候,没有足够的空间时不得不提前触发一次垃圾回收。执行过程如下图 复制算法为了解决效率问题,一种称为“复制”(Copying)的收集算法呈现了,他将可用内存按容量划分为大小相等的两块,每次只应用其中的一块。当这块的内存用完了,就将还存活这的对象复制到另外一块下面,而后再把已应用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存调配时也就不必思考内存碎片等简单状况,只有挪动堆顶指针,按程序分配内存即可,实现简略,运行高效。只是这种算法的代价是将内存放大为了原来的一半,未免太高了一点。 优缺点长处:简略高效毛病:代价是将内存放大为原来的一半,代价高执行过程如下图 标记-整顿算法复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。更要害的是如果不想节约50%的空间就要应用额定的空间进行调配担保(Handle Promotion当空间不够时,须要依赖其余内存),以应答被应用的内存中所有对象都100%存活的极其状况 对于“标记-整顿”算法,标记过程仍与“标记-革除”算法一样,然而后续步骤不是间接对可回收对象进行清理,而是让所有的存活对象都向一端挪动,而后间接清理掉端边界以外的内存,”标记-整顿“算法示意图如下: 标记-整顿算法解决了复制算法多复制效率低、空间利用率低的问题,同时也解决了内存碎片的问题。 分代收集算法依据对象生存周期的不同将内存空间划分为不同的块,而后对不同的块应用不同的回收算法。个别把Java堆分为新生代和老年代,新生代中对象的存活周期短,只有大量存活的对象,所以能够应用复制算法,而老年代中对象存活工夫长,而且对象比拟多,所以能够采纳标记-革除和标记-整顿算法。 判断对象是否无效援用计数算法 给对象增加一个援用计数器,每当一个中央援用它时,数据器加1;当援用生效时,计数器减1;计数器为0的即可被回收。长处:实现简略,判断效率高毛病:很难解决对象之间的互相循环援用(objA.instance = objB; objB.instance = objA)的问题,所以java语言并没有选用援用计数法治理内存根搜索算法 ...

February 13, 2023 · 1 min · jiezi

关于java:10分钟带你彻底搞懂-RPC-架构

大家好,我是不才陈某~ 当你在构建一个分布式系统时,势必须要思考的一个问题是:如何实现服务与服务之间的调用?当然,你能够应用 Dubbo 或 Spring Cloud 等分布式服务框架来封装技术实现的复杂性,以此实现这个指标。不过,如果当初没有这些框架,须要你本人来实现近程调用,你会怎么做呢? 关注公众号:码猿技术专栏,回复关键词:1111 获取阿里外部Java性能调优手册很多人会抉择实现一套 RPC 框架来调用近程服务。 那么你理解 RPC 架构的根本构造吗?如果你想要本人实现 RPC 框架来实现近程调用,又该构建怎么样的技术体系呢?接下来,我就给你具体介绍一下。 RPC 架构的根本构造想要构建一套残缺的 RPC 架构,就须要明确该架构所具备的根本构造,而 RPC 架构的根本构造中又存在很多组件。因而接下来,我就通过 RPC 根本构造演进的过程,来给你一一解说下。 首先,咱们通常把产生调用关系的两个服务别离称为服务的提供者(Provider)和消费者(Consumer)。所以,简略来说,RPC 就是服务的消费者向提供者发动近程调用并获取后果的过程,这是 RPC 最简略的一种表现形式。 如果想要实现服务提供者和消费者之间的无效交互,那么两者之间就须要确立与网络通信相干的网络协议以及通信通道。同时,服务的提供者须要把本人的服务调用入口裸露进去,并时刻筹备接管来自消费者的申请。 这里,咱们把通信通道和网络协议别离命名为 RpcChannel 和 RpcProtocol,而把服务提供者接管申请的组件称为 RpcAcceptor,把消费者发动申请的组件称为 RpcConnector。这样,RPC 架构就演变成了这个样子: 而后,对于服务提供者和消费者而言,为了单方可能失常辨认所发送的申请和所接管到的响应后果,须要定义对立的契约。咱们把这种契约称为近程 API(Remote API),以便与本地 API 加以区别。如此一来,基于同一套近程 API 的定义,RPC 架构就具备了依据业务来定义通信契约的能力。 相似地,为了更好地区分 RPC 架构中的角色,咱们把真正提供业务服务的组件称为 RpcServer,而把发动实在客户端申请的组件称为 RpcClient。这样,RpcServer 负责实现近程 API,而 RpcClient 负责调用近程 API。 当然,对于近程 API 而言,服务提供者和消费者的解决形式显然是不一样的。提供者须要依据消费者的申请来调用 RpcServer 的具体实现并返回后果,这部分的工作由 RpcInvoker 来执行,而消费者通过 RpcCaller 组件对申请进行编码之后,发送给服务方并期待后果。 最初,为了升高开发人员的开发难度,让近程调用的执行过程看上去就像在执行本地办法一样,在支流的 RPC 实现机制中,通常都会在客户端增加代理机制,以此提供近程服务本地化拜访的入口,咱们把这个代理组件称为 RpcProxy。 ...

February 13, 2023 · 2 min · jiezi

关于java:Terraform-101-从入门到实践-Terraform在公有云GCP上的应用

《Terraform 101 从入门到实际》这本小册在南瓜慢说官方网站和GitHub两个中央同步更新,书中的示例代码也是放在GitHub上,不便大家参考查看。Terraform反对的私有云有很多,如AWS、Azure、Google、Alibaba等。将Terraform利用于私有云,才最能施展其弱小的性能。 初始化GCP我的项目创立一个新我的项目首先咱们须要初始化一个GCP我的项目。GCP给开发者提供了收费试用的服务,咱们能够在不花钱的状况下学习GCP的性能。 要应用GCP,咱们须要创立一个我的项目,它所有的资源都是在我的项目之下治理的: 创立Service Account在理论开发中,咱们不能应用本人的账号在做操作,最好的形式是创立一个服务账号(Service Account),这应该也是所有云平台都举荐的形式。创立地位如下: 输出账号名字: 抉择角色,为了不便,我间接抉择Owner,会领有所有权限,但理论利用必定不能这样,要做好隔离: 创立密钥文件对于Service Account,不是通过用户名明码来受权的,而是通过密钥文件,创立如下: 抉择新建一个密钥,并格局为json。创立后,会主动下载key文件。 设置gcloud SDKKey文件拿到后,咱们能够设置环境变量:GOOGLE_APPLICATION_CREDENTIALS: $ export GOOGLE_APPLICATION_CREDENTIALS=/Users/larry/Software/google-cloud-sdk/pkslow-admin-for-all.json激活Service Account: $ gcloud auth activate-service-account admin-for-all@pkslow.iam.gserviceaccount.com --key-file=${GOOGLE_APPLICATION_CREDENTIALS}设置SDK的我的项目ID: $ gcloud config set project pkslow检查一下设置是否正确: $ gcloud auth list Credentialed AccountsACTIVE ACCOUNT* admin-for-all@pkslow.iam.gserviceaccount.comTo set the active account, run: $ gcloud config set account `ACCOUNT`$ gcloud config list[core]account = admin-for-all@pkslow.iam.gserviceaccount.comdisable_usage_reporting = Trueproject = pkslowYour active configuration is: [default]应用gcloud创立Pub/SubSDK设置好后,就能够应用了,咱们应用它来创立Pub/Sub试试。创立主题和订阅: $ gcloud pubsub topics create pkslow-testCreated topic [projects/pkslow/topics/pkslow-test].$ gcloud pubsub subscriptions create pkslow-sub --topic=pkslow-testCreated subscription [projects/pkslow/subscriptions/pkslow-sub].查看是否创立胜利: ...

February 13, 2023 · 2 min · jiezi

关于java:easypoi-模板导出时的公式及foreach合并单元格问题

插播一条对于easypoi的,因为这两天正好在用。 java我的项目中可能会碰到生成凭证、对账单之类的需要,用easypoi的模板导出性能应该是一个不错的抉择,因为easypoi简略易用轻量级,学习成本低、容易上手。 然而在应用过程中碰到如下问题(easypoi4.4.0): 应用foreach后,模板中设置的公式在生成的excel中不见了模板中的合并单元格问题不能反对excel中同一行搁置两个后果集foreach公式问题先形容一下问题。 设置一个模板,非常简单,应用$fe设置foreach输入后果集,而后对某一输入做共计: 保留模板为template1.xlsx,而后写一个简略的测试程序。为了不便调试并解决问题,测试程序的我的项目不是在引入easypoi包的独立我的项目中做的,而是间接从官网下载easypoi 4.4.0的源码,在源码我的项目下新建一个测试class做的。 测试代码比较简单,所以就不贴出残缺的代码了。数据筹备好之后绑定模板、调用exportExcel生成excel文件、保留生成的excel文件。 ...TemplateExportParams templateExportParams=new TemplateExportParams("F:/template1.xlsx"); Map<String,Object> map=new HashMap<String,Object>(); map.put("userList",userList); map.put("userList2",userList2); map.put("userList3",userList3); Workbook wk = ExcelExportUtil.exportExcel(templateExportParams,map); FileOutputStream fo=new FileOutputStream("f:/test1.xlsx"); //wk.setForceFormulaRecalculation(true); wk.write(fo); wk.close();而后关上生成的excel文件后,发现模板中设置的公式不见了: 重复测试后发现是模板的excel版本的问题,如果用excel的晚期版本xls就没有问题,然而如果模板是xlsx,就有问题。 然而发现问题的起因曾经是解决问题之后了。所以如果你也碰到了相似问题,能够抉择应用xls格局的模板,当然也能够尝试找找起因,看看是否能彻底解决问题。 公式失落的起因所以咱们就肯定要发挥钻牛角尖的程序员精力探索一番公式隐没的起因。 找到了ExcelExportOfTemplateUtil的addListDataToExcel办法,是专门解决foreach的(foreach指的就是模板中的fe、$fe等占位符,easypoi须要将此类占位符对应的数据集的每一行数据都循环写入到excel文件中)。 依据输出的map数据集实现对模板excel文件的shift(也就是在指标excel文件中插入行,以便对数据集中的数据进行循环写入)后,调用了PoiExcelTempUtil.reset对插入行之后的、程序向后shift的原模板内容进行了resest。 //修复不管前面有没有数据,都应该执行的是插入操作 if (isShift && datas.size() > 1 && datas.size() * rowspan > 1 && cell.getRowIndex() + rowspan <= cell.getRow().getSheet().getLastRowNum()) { int lastRowNum = cell.getRow().getSheet().getLastRowNum(); int shiftRows = lastRowNum - cell.getRowIndex() - rowspan; cell.getRow().getSheet().shiftRows(cell.getRowIndex() + rowspan, lastRowNum, (datas.size() - 1) * rowspan, true, true); mergedRegionHelper.shiftRows(cell.getSheet(), cell.getRowIndex() + rowspan, (datas.size() - 1) * rowspan, shiftRows); templateSumHandler.shiftRows(cell.getRowIndex() + rowspan, (datas.size() - 1) * rowspan); PoiExcelTempUtil.reset(cell.getSheet(), cell.getRowIndex() + rowspan + (datas.size() - 1) * rowspan, cell.getRow().getSheet().getLastRowNum()); }不太理解reset的用处,试着正文掉这行代码,貌似对我的这个小测试也没有什么影响,而且公式隐没不见的问题的确也解决了。 ...

February 12, 2023 · 1 min · jiezi

关于java:Java-创建线程的四种方式

1. 继承 Thread 类继承 Thread 类,重写 run() 办法。 在主线程中创立 MyThread 类对象,调用 start() 办法启动线程。 public class ThreadDemo { public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); } static class MyThread extends Thread { @Override public void run() { System.out.println("继承 Thread 创立线程"); } }2. 实现 Runnable 接口创立一个 MyRunnable 外部类实现 Runnable 接口,重写 run() 办法。 在创立 Thread 类对象时传入 MyRunnable 类对象。 也能够不独自写 Runnable 接口的实现类,间接应用 Lambda 表达式实现。 public class ThreadDemo { public static void main(String[] args) { //实现 Runnable 接口 Thread t1 = new Thread(new MyRunnable()); t1.start(); //间接应用 Lambda 缩写 new Thread(()->{ System.out.println("用 Lambda 缩写创立线程"); }).start(); } static class MyRunnable implements Runnable { @Override public void run() { System.out.println("实现 Runnable 接口创立线程"); } }}3. 实现 Callable 接口创立一个 MyCallable 外部类实现 Callable 接口,重写 call() 办法。 ...

February 12, 2023 · 2 min · jiezi

关于java:QA-不讲武德线上-1-亿-数据乱分页让我搞到半夜

作者:翁智华出处:https://www.cnblogs.com/wzh2010/ 背景一天早晨10点半,上班后欢快的坐在在回家的地铁上,心里想着周末的生存怎么安顿。 忽然电话响了起来,一看是咱们的一个开发同学,登时缓和了起来,本周的版本曾经公布过了,这时候打电话一般来说是线上出问题了。 果然,沟通的状况是线上的一个查问数据的接口被疯狂的失去理智般的调用,这个操作间接导致线上的MySql集群被拖慢了。 好吧,这问题算是重大了,下了地铁匆匆赶到家,开电脑,跟共事把Pinpoint上的慢查问日志捞进去。看到一个很奇怪的查问,如下 1 POST domain/v1.0/module/method?order=condition&orderType=desc&offset=1800000&limit=500domain、module 和 method 都是化名,代表接口的域、模块和实例办法名,前面的offset和limit代表分页操作的偏移量和每页的数量,也就是说该同学是在 翻第(1800000/500+1=3601)页。初步捞了一下日志,发现 有8000屡次这样调用。 这太神奇了,而且咱们页面上的分页单页数量也不是500,而是 25条每页,这个相对不是人为的在性能页面上进行一页一页的翻页操作,而是数据被刷了(阐明下,咱们生产环境数据有1亿+)。 具体比照日志发现,很多分页的工夫是重叠的,对方应该是多线程调用。 通过对鉴权的Token的剖析,根本定位了申请是来自一个叫做ApiAutotest的客户端程序在做这个操作,也定位了生成鉴权Token的账号来自一个QA的同学。立马打电话给同学,进行了沟通和解决。 剖析其实对于咱们的MySQL查问语句来说,整体效率还是能够的,该有的联表查问优化都有,该简略的查问内容也有,要害条件字段和排序字段该有的索引也都在,问题在于他一页一页的分页去查问,查到越前面的页数,扫描到的数据越多,也就越慢。 咱们在查看前几页的时候,发现速度十分快,比方 limit 200,25,霎时就进去了。然而越往后,速度就越慢,特地是百万条之后,卡到不行,那这个是什么原理呢。先看一下咱们翻页翻到前面时,查问的sql是怎么的: 1 select * from t_name where c_name1='xxx' order by c_name2 limit 2000000,25;这种查问的慢,其实是因为limit前面的偏移量太大导致的。比方像下面的 limit 2000000,25 ,这个等同于数据库要扫描出 2000025条数据,而后再抛弃后面的 20000000条数据,返回剩下25条数据给用户,这种取法显著不合理。 大家翻看《高性能MySQL》第六章:查问性能优化,对这个问题有过阐明: 分页操作通常会应用limit加上偏移量的方法实现,同时再加上适合的order by子句。但这会呈现一个常见问题:当偏移量十分大的时候,它会导致MySQL扫描大量不须要的行而后再摈弃掉。 数据模仿那好,理解了问题的原理,那就要试着解决它了。波及数据敏感性,咱们这边模仿一下这种状况,结构一些数据来做测试。 1、创立两个表:员工表和部门表 1 /*部门表,存在则进行删除 */ 2 drop table if EXISTS dep; 3 create table dep( 4 id int unsigned primary key auto_increment, 5 depno mediumint unsigned not null default 0, 6 depname varchar(20) not null default "", 7 memo varchar(200) not null default "" 8 ); 9 10 /*员工表,存在则进行删除*/11 drop table if EXISTS emp;12 create table emp(13 id int unsigned primary key auto_increment,14 empno mediumint unsigned not null default 0,15 empname varchar(20) not null default "",16 job varchar(9) not null default "",17 mgr mediumint unsigned not null default 0,18 hiredate datetime not null,19 sal decimal(7,2) not null,20 comn decimal(7,2) not null,21 depno mediumint unsigned not null default 022 );2、创立两个函数:生成随机字符串和随机编号 ...

February 12, 2023 · 4 min · jiezi

关于java:Terraform-101-从入门到实践-第五章-HCL语法

《Terraform 101 从入门到实际》这本小册在南瓜慢说官方网站和GitHub两个中央同步更新,书中的示例代码也是放在GitHub上,不便大家参考查看。介绍了Terraform一些比拟根底的概念后,咱们能够先理解一下Terraform的语法,也就是HCL的语法。 变量Variables变量是实现代码复用的一种形式,同样的代码不同的变量往往会有不同的成果。而在Terraform里,有一个概念十分重要,就是变量都是从属于模块的。变量无奈跨模块援用。即在模块A定义的变量X,无奈在模块B中间接援用。但父模块的变量,能够作为子模块的入参;而子模块的输入变量能够被父模块获取。 变量类型从语言角度跟任何编程语言一样,变量都是有类型的,Terraform的变量类型从语言的角度可分为两大类:根本类型和组合类型,具体如下: 根本类型: 字符串string,如"pkslow.com"数字number,如319或5.11布尔值bool,如true组合类型: 列表list(<T>),如["dev", "uat", "prod"]汇合set(<T>),如set(...)映射map(<T>),如{name="Larry", age="18"}对象object({name1=T1, name2=T2})元组tuple([T1,T2,T3...])如果不想指定某个类型,能够用any来示意任意类型;或者不指定,默认为任意类型。 从性能角度从性能角度来看,变量能够分为输出变量、输入变量和本地变量。 输出变量是模块接管内部变量的形式,它定义在variable块中,如下: variable "image_id" { type = string}variable "availability_zone_names" { type = list(string) default = ["us-west-1a"]}variable "docker_ports" { type = list(object({ internal = number external = number protocol = string })) default = [ { internal = 8300 external = 8300 protocol = "tcp" } ]}输入变量定义了一个模块对外返回的变量,通过output块来定义,如下: output "instance_ip_addr" { value = aws_instance.server.private_ip}本地变量是模块内定义且可援用的长期变量,在locals块中定义,如下: locals { service_name = "forum" owner = "Community Team"}输出变量Input Variable输出变量是定义在variable块中的,它就像是函数的入参。 ...

February 11, 2023 · 2 min · jiezi

关于java:Terraform-101-从入门到实践-第四章-States状态管理

《Terraform 101 从入门到实际》这本小册在南瓜慢说官方网站和GitHub两个中央同步更新,书中的示例代码也是放在GitHub上,不便大家参考查看。军书十二卷,卷卷有爷名。为什么须要状态治理Terraform的次要作用是治理云平台上的资源,通过申明式的HCL配置来映射资源,如果云平台上没有资源则须要创立,如果有则不必。那Terraform要实现这个性能有多种形式。 一种是每次执行apply命令时都调用API接口检查一下近程的云资源是否与配置文件统一,如果没有则创立,如果有但不同则须要批改,如果有且雷同则不必变更。这种机制能保障云平台的资源与HCL配置是统一的。毛病也是非常明显的,每次都须要调用API去查看近程资源,效率很低,特地是当资源特地多的场景。 另一种形式是每次变更资源的时候,都会创立一个映射文件,它保留云平台资源的状态。这样每次执行apply命令时,只须要查看HCL配置与映射文件的差别即可。 Terraform抉择的是第二种形式,通过映射文件来保留资源状态,在Terraform的世界里叫状态文件。Terraform这样做是基于以下思考: 云平台实在状态的映射,解析状态文件即能够晓得真实情况。元数据存储,如资源之间的依赖关系,须要通过依赖关系来晓得创立或销毁程序。晋升性能,特地是在大规模云平台上,屡次调用API去查问资源状态是很费时的。同步状态,通过近程状态文件来同步状态,这也是Terraform最佳的实际。讲到这里,曾经答复了之前在第一章留下的思考题: 如果再次执行apply会不会再次创立一个文件呢?还是创立失败,因为文件已存在?为什么?答案:不会创立,因为通过状态文件记录了变更,Terraform判断不再须要创立了。 状态治理的示例为了更多注意力放在状态治理上,咱们还是应用最简略的例子local_file,具体代码如下: resource "local_file" "terraform-introduction" { content = "https://www.pkslow.com" filename = "${path.root}/terraform-guides-by-pkslow.txt"}咱们以实际操作及景象来解说状态文件的作用和工作原理: 操作景象及阐明terraform apply生成资源:第一次生成terraform apply没有变动:状态文件生成,不须要再创立terraform destroy删除资源:依据状态文件的内容删除terraform apply生成资源:状态显示没有资源,再次生成删除状态文件没有变动terraform apply生成资源:没有状态文件,间接生成资源和状态文件(插件做了容错解决,已存在也会新生成笼罩)删除状态文件没有变动terraform destroy无奈删除资源,没有资源存在的状态咱们始终在讲状态文件,咱们先来看一下它的真面目。首先它的默认文件名是terraform.tfstate,默认会放在当前目录下。它是以json格局存储的信息,示例中的内容如下: { "version": 4, "terraform_version": "1.0.11", "serial": 1, "lineage": "acb408bb-2a95-65fd-02e6-c23487f7a3f6", "outputs": {}, "resources": [ { "mode": "managed", "type": "local_file", "name": "test-file", "provider": "provider[\"registry.terraform.io/hashicorp/local\"]", "instances": [ { "schema_version": 0, "attributes": { "content": "https://www.pkslow.com", "content_base64": null, "directory_permission": "0777", "file_permission": "0777", "filename": "./terraform-guides-by-pkslow.txt", "id": "6db7ad1bbf57df0c859cd5fc62ff5408515b5fc1", "sensitive_content": null, "source": null }, "sensitive_attributes": [], "private": "bnVsbA==" } ] } ]}能够看到它记录了Terraform的版本信息,还有资源的详细信息:包含类型、名字、插件、属性等。有这些信息便可间接从状态文件里解析出具体的资源。 ...

February 10, 2023 · 2 min · jiezi

关于java:腾讯架构师极力推荐Java多线程与Socket实战微服务框架

在这个技术不断更新的年代,跟不上时代变动的速度就会被刷掉,特地是咱们程序员这一群体,技术不断更新的同时也要同时提高,不然长江后浪推前浪,前浪...... 一个程序员从一个什么都不懂的小白在学到有肯定的Java根底的时候必定是要学习更多的技术空虚本人,甚至还要往架构师方向靠。然而一个优良的架构师必须要有扎实的编程功底和丰盛的理论知识,不光要能实现架构设计,更要有能力将设计转换为理论的产品。不会写代码、夸夸其谈的“架构师”设计进去的“架构”是靠不住的。 明天给大家举荐一本《Java多线程与Socket实战微服务框架》,本书从实战角度登程,首先介绍Java多线程、Socket、Spring、动静代理、动静字节码、序列化等技术在构建散布式微服务框架中的利用。而后介绍一种微服务框架的架构设计与编程实际,并将这一微服务框架合成为底层Socket通信、服务注册与发现、服务裸露与援用、近程办法调用等层面,逐个深刻解说。最初介绍微服务架构中配套的服务治理零碎的设计与实现计划,包含服务的设计、配置、治理与监控。 因为内容较多,以下只展现局部内容,须要残缺文档的小伙伴【点击此处】即可收费获取~废话少说,先来看看目录 第1章:多线程根底 第2章:Socket根底 第3章:Spring与Spring Cloud 第4章:动静代理 第5章:对象序列化 第6章:框架设计 第7章:办法调用 第8章:通信层实现 第9章:性能测试与调优 第10章:服务治理

February 10, 2023 · 1 min · jiezi

关于java:个人学习系列-解决拦截器操作请求参数后台无法获取

因为我的项目须要应用拦截器对申请参数进行操作,可是申请流只能操作一次,导致前面办法不能再获取流了。新建SpringBoot我的项目1. 新建拦截器WebConfig.java/** * @date: 2023/2/6 11:21 * @author: zhouzhaodong * @description: */@Configurationpublic class WebConfig implements WebMvcConfigurer { /** * 增加Web我的项目的拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { // 对所有拜访门路,都通过MyInterceptor类型的拦截器进行拦挡 // 放行登录页,登陆操作,动态资源 registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**") .excludePathPatterns("/", "/login", "/index.html", "/user/login", "/css/**", "/images/**", "/js/**", "/fonts/**"); }}2. 获取申请参数并解决逻辑/** * @date: 2023/2/6 12:46 * @author: zhouzhaodong * @description: 获取申请参数并解决 */public class RequestWrapper extends HttpServletRequestWrapper { private final Logger logger = LoggerFactory.getLogger(RequestWrapper.class); private final byte[] body; public RequestWrapper(HttpServletRequest request) { super(request); String sessionStream = getBodyString(request); body = sessionStream.getBytes(StandardCharsets.UTF_8); } public String getBodyString() { return new String(body, StandardCharsets.UTF_8); } /** * @date: 2023/2/6 12:46 * @author: zhouzhaodong * @description: 获取申请Body */ public String getBodyString(final ServletRequest request) { StringBuilder sb = new StringBuilder(); InputStream inputStream = null; BufferedReader reader = null; try { inputStream = cloneInputStream(request.getInputStream()); reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); String line = ""; while ((line = reader.readLine()) != null) { sb.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } logger.info("获取body申请参数:" + sb); return sb.toString(); } /** * @date: 2023/2/6 12:46 * @author: zhouzhaodong * @description: 复制输出流 */ public InputStream cloneInputStream(ServletInputStream inputStream) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; try { while ((len = inputStream.read(buffer)) > -1) { byteArrayOutputStream.write(buffer, 0, len); } byteArrayOutputStream.flush(); } catch (IOException e) { e.printStackTrace(); } return new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); } @Override public BufferedReader getReader() { return new BufferedReader(new InputStreamReader(getInputStream())); } @Override public ServletInputStream getInputStream() { final ByteArrayInputStream bais = new ByteArrayInputStream(body); return new ServletInputStream() { @Override public int read() { return bais.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; }}3. 实现HandlerInterceptor接口/** * @date: 2023/2/6 11:19 * @author: zhouzhaodong * @description: 实现HandlerInterceptor接口 */public class MyInterceptor implements HandlerInterceptor { private final Logger logger = LoggerFactory.getLogger(MyInterceptor.class); /** * @date: 2023/2/6 11:19 * @author: zhouzhaodong * @description: 拜访控制器办法前执行 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { logger.info("================进入拦截器======================"); logger.info(new Date() + "--preHandle:" + request.getRequestURL()); logger.info("***************************【RequestBeginning】***************************"); logger.info("----------------StartProcessingRequest----------------"); try { long currentTime = System.currentTimeMillis(); SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); Date date = new Date(currentTime); logger.info("CurrentTime: {}", formatter.format(date)); logger.info("ResponseTime: {}", (System.currentTimeMillis() - currentTime) + "ms"); String requestUrl = request.getRequestURI(); logger.info("RequestURL: {} ", requestUrl); logger.info("GetMethod: {}", handler); String method = request.getMethod(); logger.info("Method: {}", method); //获取申请参数 RequestWrapper requestWrapper = new RequestWrapper(request); //这里getBodyString()办法无参数 logger.info("RequestBody: {}", requestWrapper.getBodyString()); } catch (Exception e) { logger.error("MVC业务解决-拦截器异样:", e); } logger.info("-------------------------End-------------------------"); return true; } /** * @date: 2023/2/6 12:46 * @author: zhouzhaodong * @description: 拜访控制器办法后执行 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { logger.info(new Date() + "--postHandle:" + request.getRequestURL()); } /** * @date: 2023/2/6 12:46 * @author: zhouzhaodong * @description: postHandle办法执行实现后执行,个别用于开释资源 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { logger.info(new Date() + "--afterCompletion:" + request.getRequestURL()); }}4. application.ymlspring: main: # 当呈现雷同名字的类进行注册时,准许笼罩注册 allow-bean-definition-overriding: true5. 启动类增加@ServletComponentScan注解6. 新建TestController.java/** * @date: 2023/2/6 12:24 * @author: zhouzhaodong * @description: 测试 */@RestControllerpublic class TestController { @PostMapping("/one/abc") public String abc(@RequestBody User user){ return user.getName(); }}7. 不进行解决先测试看后果申请后果:控制台输入:能够看出,流被读取了一次而后后盾就获取不到了。 ...

February 10, 2023 · 3 min · jiezi

关于java:JVM说直接内存的使用

作者:京东物流 刘作龙 前言: 学习底层原理有的时候不肯定你是要用到他,而是学习他的设计思维和思路。再或者,当你在日常工作中遇到辣手的问题时候,能够多一条解决问题的形式 分享纲要: 本次分享次要由io与nio读取文件速度差别的状况,去理解nio为什么读取大文件的时候效率较高,查看nio是如何应用间接内存的,再深刻到如何应用间接内存 1 nio与io读写文件的效率比对首先上代码,有趣味的同学能够将代码拿下来进行调试查看 package com.lzl.netty.study.jvm;import lombok.extern.slf4j.Slf4j;import org.springframework.util.StopWatch;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.RandomAccessFile;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;/** * java对于间接内存应用的测试类 * * @author liuzuolong * @date 2022/6/29 **/@Slf4jpublic class DirectBufferTest { private static final int SIZE_10MB = 10 * 1024 * 1024; public static void main(String[] args) throws InterruptedException { //读取和写入不同的文件,保障互不影响 String filePath1 = "/Users/liuzuolong/CODE/OWN/netty-study/src/main/resources/ioInputFile.zip"; String filePath2 = "/Users/liuzuolong/CODE/OWN/netty-study/src/main/resources/nioDirectInputFile.zip"; String filePath3 = "/Users/liuzuolong/CODE/OWN/netty-study/src/main/resources/nioHeapInputFile.zip"; String toPath1 = "/Users/liuzuolong/CODE/OWN/netty-study/src/main/resources/ioOutputFile.zip"; String toPath2 = "/Users/liuzuolong/CODE/OWN/netty-study/src/main/resources/nioDirectOutputFile.zip"; String toPath3 = "/Users/liuzuolong/CODE/OWN/netty-study/src/main/resources/nioHeapOutputFile.zip"; Integer fileByteLength = SIZE_10MB; //新建io读取文件的线程 Thread commonIo = new Thread(() -> { commonIo(filePath1, fileByteLength, toPath1); }); //新建nio应用间接内存读取文件的线程 Thread nioWithDirectBuffer = new Thread(() -> { nioWithDirectBuffer(filePath2, fileByteLength, toPath2); }); //新建nio应用堆内存读取文件的线程 Thread nioWithHeapBuffer = new Thread(() -> { nioWithHeapBuffer(filePath3, fileByteLength, toPath3); }); nioWithDirectBuffer.start(); commonIo.start(); nioWithHeapBuffer.start(); } public static void commonIo(String filePath, Integer byteLength, String toPath) { //进行工夫监控 StopWatch ioTimeWatch = new StopWatch(); ioTimeWatch.start("ioTimeWatch"); try (FileInputStream fis = new FileInputStream(filePath); FileOutputStream fos = new FileOutputStream(toPath); ) { byte[] readByte = new byte[byteLength]; int readCount = 0; while ((readCount = fis.read(readByte)) != -1) { // 读取了多少个字节,转换多少个。 fos.write(readByte, 0, readCount); } } catch (Exception e) { e.printStackTrace(); } ioTimeWatch.stop(); log.info(ioTimeWatch.prettyPrint()); } public static void nioWithDirectBuffer(String filePath, Integer byteLength, String toPath) { StopWatch nioTimeWatch = new StopWatch(); nioTimeWatch.start("nioDirectTimeWatch"); try (FileChannel fci = new RandomAccessFile(filePath, "rw").getChannel(); FileChannel fco = new RandomAccessFile(toPath, "rw").getChannel(); ) { // 读写的缓冲区(调配一块儿间接内存) //要与allocate进行辨别 //进入到函数中 ByteBuffer bb = ByteBuffer.allocateDirect(byteLength); while (true) { int len = fci.read(bb); if (len == -1) { break; } bb.flip(); fco.write(bb); bb.clear(); } } catch (IOException e) { e.printStackTrace(); } nioTimeWatch.stop(); log.info(nioTimeWatch.prettyPrint()); } public static void nioWithHeapBuffer(String filePath, Integer byteLength, String toPath) { StopWatch nioTimeWatch = new StopWatch(); nioTimeWatch.start("nioHeapTimeWatch"); try (FileChannel fci = new RandomAccessFile(filePath, "rw").getChannel(); FileChannel fco = new RandomAccessFile(toPath, "rw").getChannel(); ) { // 读写的缓冲区(调配一块儿间接内存) //要与allocate进行辨别 ByteBuffer bb = ByteBuffer.allocate(byteLength); while (true) { int len = fci.read(bb); if (len == -1) { break; } bb.flip(); fco.write(bb); bb.clear(); } } catch (IOException e) { e.printStackTrace(); } nioTimeWatch.stop(); log.info(nioTimeWatch.prettyPrint()); }}1.主函数调用 为排除以后环境不同导致的文件读写效率不同问题,应用多线程别离调用io办法和nio办法 ...

February 10, 2023 · 3 min · jiezi

关于java:Quartz-Misfire

Misfire,看到很多文章翻译为“失火”,其实感觉这个翻译和他自身代表的含意差距比拟大。 Quartz中的fire示意触发器被触发的意思,Misfire则示意原本应该到了触发器被触发的工夫,然而理论却没有触发,是“错过触发”的意思。 Misfire的起因触发器Misfire的起因大略有以下几种: 触发器在初始化时设置的start工夫小于以后零碎工夫jobStore设置为JDBC(通过数据库长久化存储),零碎down机后再次启动任务调度线程阻塞没有可用工作执行线程(被其余正在执行中的工作占满)Misfire的解决策略产生Misfire之后,Quartz的不同Trigger会提供不同的解决策略。其中SimplerTrigger和CronTrigger的独特解决策略是: MISFIRE_INSTRUCTION_SMART_POLICY:smart policy,其实最终实现取决于Trigger实现类MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY:疏忽Misfire就当Misfire没有产生,意思是任务调度器错过了某一触发器的触发工夫之后,一旦该触发器取得执行机会后,会把所有错过触发的工夫补回来。比方simpleTrigger设置为每15秒执行一次,因为某种原因在最近5分钟内错过了触发,则一旦其取得执行机会后,会间断触发5*(60/15)=20次SimplerTrigger的解决策略包含: MISFIRE_INSTRUCTION_FIRE_NOW:对于一次性工作则立刻触发,对于设置了执行次数repeat count的循环执行的工作,则等同于MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT。MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT:立刻触发(不思考Calendar的限度),而且触发次数不受影响(即便Misfre也能保障触发次数),比方设置执行100次,已执行10次,Misfire了5次,则残余执行次数为100-10=90次(咱们称之为触发次数不受影响)。然而如果同时设置了EndTime,则须要恪守EndTime的限度(如果以后工夫曾经超过的EndTime则不再触发)。MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT:立刻触发(不思考Calendar的限度),然而触发次数会受到影响:将Misfire的次数也思考在内,比方设置为执行100次,已执行10次,Misfire了5次,则剩余次数为100-(10+5)=85次,所以错过的5次实际上还是被错过了。而且须要恪守EndTime的约定,如果以后工夫曾经超过的EndTime则不再触发。MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT:立刻触发(思考Calendar的限度),触发次数会受到影响,须要恪守EndTime的限度。MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT:立刻触发(思考Calendar的限度),需恪守EndTime的限度,触发次数不受影响。MISFIRE_INSTRUCTION_SMART_POLICY:默认解决策略,如果是不反复(只触发一次)触发器,等同于MISFIRE_INSTRUCTION_FIRE_NOW,如果是触发无数次的(永不进行)触发器,等同于MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT,否则如果是触发无限次数的触发器,等同于MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT。CronTrigger的解决策略: MISFIRE_INSTRUCTION_FIRE_ONCE_NOW:立刻触发。MISFIRE_INSTRUCTION_DO_NOTHING:疏忽Misfire就相当于Misfire没有产生过一样,具体来说就是用以后日期再次计算下次触发工夫(思考Calendar的限度),以后工夫并不触发。MISFIRE_INSTRUCTION_SMART_POLICY:默认的解决策略,等同于MISFIRE_INSTRUCTION_FIRE_ONCE_NOW。Misfire解决策略总结Misfire解决策略看起来非常复杂,尤其是SimpleTrigger的策略,然而个别状况下咱们并不需要这么简单的Misfire策略,所以绝大部分状况咱们只须要应用默认的策略就能够。 非凡状况下,比方严格要求到EndTime必须执行够多少次这类需要,就须要咱们认真钻研不同策略的区别,采纳适合的Misfire策略能力确保满足需要。 不论是SimplerTrigger还是CronTrigger,默认的Misfire解决策略都是MISFIRE_INSTRUCTION_SMART_POLICY,所谓smart policy其实就是能够依据Trigger的不同个性做出不同的解决。 Misfire的设置触发器创立的时候通过TriggerBuilder的ScheduleBuilder指定,SimpleSchduleBuilder对应设置SimpleTrigger的Misfire解决策略,CronScheduleBuilder对应设置CronTrigger的Misfire策略。 Trigger trigger = newTrigger() .withIdentity("myTriggger","MyGroup") .startNow() .withSchedule(simpleSchedule() .withIntervalInSeconds(20) .withMisfireHandlingInstructionFireNow()) .build();Misfire解决策略源码剖析任务调度线程QuartzSchedulerThread的run办法咱们后面曾经简略做过剖析,Quartz的任务调度就是在这里进行的。其中会调用JobStore的acquireNextTriggers办法获取在idleWaitTime工夫范畴内须要被调度的Trigger。 以RAMJobStore为例,acquireNextTriggers办法会逐个获取timeTriggers中的Trigger,之后首先调用applyMisfire(tw)进行Misfire解决。 applyMisfire(tw)办法首先判断Trigger的Misfire策略如果是IGNORE_MISFIRE_POLICY,或者Trigger的触发工夫大于零碎工夫减去零碎设置的Misfire容忍工夫,则不认为是Misfire,返回false。否则会认为是Misfire,进行Misfire时候的后续解决。 long misfireTime = System.currentTimeMillis(); if (getMisfireThreshold() > 0) { misfireTime -= getMisfireThreshold(); } Date tnft = tw.trigger.getNextFireTime(); if (tnft == null || tnft.getTime() > misfireTime || tw.trigger.getMisfireInstruction() == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) { return false; }这里须要留神的是第二个条件,“Trigger的触发工夫大于零碎工夫减去零碎设置的Misfire容忍工夫”,咱们须要举例简略剖析一下。 假如咱们设置的Misfire容忍工夫是60秒,Trigger的触发工夫为7点55分整。 如果以后零碎工夫是7点56,减去容忍工夫60秒之后(咱们临时称之为Misfire工夫)是7点55,Trigger的触发工夫7点55分并不大于Misfire工夫,零碎认为产生了Misfire。而且以后工夫如果大于7点56分的话,都会认为是产生了Misfire。 如果以后工夫是7点55分59秒,减去容忍工夫60秒之后的Misfire工夫是7点54分59秒,*Trigger的触发工夫7点55分大于Misfire工夫,所以零碎认为没有产生Misfire。 如果产生了Misfire,调用trigger的updateAfterMisfire办法进行产生Misfire后的解决,Misfire解决策略就是在这个updateAfterMisfire办法中失效的,updateAfterMisfire办法的解决逻辑体现了不同Trigger的Misfire解决策略。 updateAfterMisfire的解决逻辑其实就是Trigger的不同Misfire解决策略的实现过程,钻研updateAfterMisfire办法源码是了解Misfire解决策略的最好的方法。 如果applyMisfire(tw)办法返回true,也就是说Quartz认为产生了Misfire,则零碎判断通过Misfire解决之后的Trigger的下次触发工夫不为空的话,就会把以后trigger从新加回到timeTriggers中,继续执行下次循环。 if (applyMisfire(tw)) { if (tw.trigger.getNextFireTime() != null) { timeTriggers.add(tw); } continue; }其实咱们剖析Trigger的不同Misfire策略后会发现,只有产生了Misfire、而且在Misfire解决之后Trigger的下次执行工夫不为空,则不论是什么Misfire策略均示意要在以后工夫触发该Trigger。 ...

February 9, 2023 · 1 min · jiezi

关于java:JAVA中如何判断一个ResultSet结果集是否为空

问题形容ResultSet 示意 select 语句的查问后果集。ResultSet 对象具备指向其以后数据行的指针, 最后,指针被置于第一行记录之前,通过 next() 办法能够将指针挪动到下一行记录。 next() 办法在 ResultSet 对象没有一行记录时返回 false ,因而能够在 while 循环中应用它来遍历后果集,也能够利用该办法判断后果集是否为空。 示例代码如下: //此处省略连贯数据库的代码...Statement stmt =conn.createStatement(); ResultSet  rs     =stmr.executeQuery("select  *  from  Test");if(rs.next()){ System.out.println("后果集不为空!"); }else{ System.out.println("后果集为空!"); }此时呈现第一个坑:Java 的 ResultSet 对象,默认是不可更新的,仅有一个向前挪动的指针。 因而,只能遍历它一次,并且只能按从第一行到最初一行的程序进行。 当你应用了 rs.next() 进行判断后,会呈现第一行数据失落的状况。 这也是我一开始遇到的问题。 深究问题ResultSet 的 Type 属性遇到问题后我第一想法是在搜索引擎上搜寻相干解决办法,但看了一圈具体有以下“解法”: 调用 rs.last() 办法,以获取 ResultSet中 记录的总数,而后调用 rs.beforeFirst() 办法将光标移回到第一条记录后面 这种办法看上去可行,但当我理论批改后运行,却呈现报错 Operation not allowed for a result set of type ResultSet.TYPE_FORWARD_ONLY.这又是什么起因呢? 呈现这个报错的次要起因是: ResultSet.TYPE_FORWARD_ONLY 类型的 ResultSet 只容许向前遍历,不反对拜访先前的记录或确定其大小。因而,应用 last() 和 getRow() 等办法都是不可行。 ...

February 9, 2023 · 1 min · jiezi

关于java:解读-Java-云原生实践中的内存问题

作者:风敬(谢文欣) Java 凭借着本身沉闷的开源社区和欠缺的生态劣势,在过来的二十几年始终是最受欢迎的编程语言之一。步入云原生时代,蓬勃发展的云原生技术开释云计算红利,推动业务进行云原生化革新,减速企业数字化转型。 然而 Java 的云原生转型之路面临着微小的挑战,Java 的运行机制和云原生个性存在着诸多矛盾。企业借助云原生技术进行深层次老本优化,资源老本治理被回升到前所未有的高度。私有云上资源按量免费,用户对资源用量非常敏感。在内存应用方面,基于 Java 虚拟机的执行机制使得任何 Java 程序都会有固定的根底内存开销,相比 C++/Golang 等原生语言,Java 利用占用的内存微小,被称为“内存吞噬者”,因而 Java 利用上云更加低廉。并且利用集成到云上之后零碎复杂度减少,普通用户对云上 Java 利用内存没有清晰的意识,不晓得如何为利用合理配置内存,呈现 OOM 问题时也很难排障,遇到了许多问题。 为什么堆内存未超过 Xmx 却产生了 OOM?怎么了解操作系统和JVM的内存关系?为什么程序占用的内存比 Xmx 大不少,内存都用在哪儿了?为什么线上容器内的程序内存需要更大?本文将 EDAS 用户在 Java 利用云原生化演进实际中遇到的这些问题进行了抽丝剥茧的剖析,并给出云原生 Java 利用内存的配置倡议。 背景常识K8s 利用的资源配置云原生架构以 K8s 为基石,利用在 K8s 上部署,以容器组的状态运行。K8s 的资源模型有两个定义,资源申请(request)和资源限度(limit),K8s 保障容器领有 request数量的资源,但不容许应用超过limit数量的资源。以如下的内存配置为例,容器至多能取得 1024Mi 的内存资源,但不容许超过 4096Mi,一旦内存应用超限,该容器将产生OOM,而后被 K8s 控制器重启。  spec: containers: - name: edas image: alibaba/edas resources: requests: memory: "1024Mi" limits: memory: "4096Mi" command: ["java", "-jar", "edas.jar"]容器 OOM对于容器的 OOM 机制,首先须要来温习一下容器的概念。当咱们谈到容器的时候,会说这是一种沙盒技术,容器作为一个沙盒,外部是绝对独立的,并且是有边界有大小的。容器内独立的运行环境通过 Linux的Namespace 机制实现,对容器内 PID、Mount、UTS、IPD、Network 等 Namespace 进行了障眼法解决,使得容器内看不到宿主机 Namespace 也看不到其余容器的 Namespace;而所谓容器的边界和大小,是指要对容器应用 CPU、内存、IO 等资源进行束缚,不然单个容器占用资源过多可能导致其余容器运行迟缓或者异样。Cgroup 是 Linux 内核提供的一种能够限度单个过程或者多个过程所应用资源的机制,也是实现容器资源束缚的核心技术。容器在操作系统看来只不过是一种非凡过程,该过程对资源的应用受 Cgroup 的束缚。当过程应用的内存量超过 Cgroup 的限度量,就会被零碎 OOM Killer 无情地杀死。 ...

February 9, 2023 · 4 min · jiezi

关于java:一种配置多数据源的实现方式

创立一个 ComposeDataSource bean, 实现spring 的AbstractRoutingDataSource,并exclude spring AutoDatabaseConfiguration。在ComposeDataSource初始化办法里,初始化的多数据源,并设置到DataSourceMap中,其中key为数据源id,value为数据源实例。执行数据库操作的办法上应用自定义注解,指定数据源id。应用aspect,具体实现办法应用aspectj或者sping aspect,参考@Async文章,通过id查问数据源,并配置到localThread。执行数据库操作的办法时,调用ComposeDataSource的getConnect办法,从localThread取得理论数据源。

February 9, 2023 · 1 min · jiezi

关于java:如何通过极狐GitLab-平滑落地-Java-增量代码规范

本文来自:杨周 极狐GitLab 高级解决方案架构师代码越写越标准是优良开发者的成长之路,但很多人对老我的项目感到有心无力,因为太不标准了,所有人停下来一起修复也要花费很长时间,而且一次改变太多难以确保可靠性,怎么办? 有的语言能够借助 Git diff 把本次批改的代码挑出来,实现增量扫描,但 Java 很难这么做。 有的人在继续集成里配置了标准扫描工具,但报错之后须要在成千上万行 log 里查找,升高了研发效率。 Checkstyle 是业界出名的开源扫描工具,可扫描 Sun、Google 等代码标准,提供Maven、Gradle 插件。本文以 Java 我的项目配置 Checkstyle 扫描工具为例,分享毁灭这些问题的方法: 1. 将代码标准问题显示在「合并申请页面」,大幅度提高研发效率; 2. 增量代码标准报告。 下文别离介绍「Java Maven 我的项目」和「Java Gradle 我的项目」的配置办法。 通过极狐GitLab CI 平滑落地 Java 增量代码标准Checkstyle Maven在我的项目中引入 Checkstyle 插件,并下载代码标准: $ vi pom.xml<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-checkstyle-plugin</artifactId> <version>3.2.0</version> <configuration> <encoding>UTF-8</encoding> <consoleOutput>true</consoleOutput> <failsOnError>true</failsOnError> <violationSeverity>warning</violationSeverity> <configLocation>config/checkstyle/checkstyle.xml</configLocation> </configuration> </plugin>$ mkdir -p config/checkstyle/$ wget https://raw.githubusercontent.com/checkstyle/checkstyle/checkstyle-9.3/src/main/resources/google_checks.xml -O config/checkstyle/checkstyle.xml执行全量扫描命令,查看成果: $ ./mvnw checkstyle:check[WARN] Demo.java:6:1: 短少 Javadoc 。 [MissingJavadocType][WARN] Demo.java:9:1: 行内含有制表符 tab 。 [FileTabCharacter][WARN] Demo.java:9:9: 'method def modifier' 缩进了8个缩进符,应为2个。 [Indentation]在极狐GitLab 继续集成中执行强制扫描: ...

February 9, 2023 · 4 min · jiezi

关于java:Elasticsearch源码解析之HTTP请求响应处理

因为ES曾经存在多个版本,次要是每一个版本的启动流程都不一样,我这里不想独自去剖析某一个版本如何进行启动的,解析ES如何去响应HTTP申请的,以及背地如何去实现。上面简略给大家剖析下,HTTP服务器实现。 HTTP ServerElasticsearch Netty注册服务器 Netty4HttpServerTransport protected void doStart() { boolean success = false; try { serverBootstrap = new ServerBootstrap(); serverBootstrap.group(new NioEventLoopGroup(workerCount, daemonThreadFactory(settings, HTTP_SERVER_WORKER_THREAD_NAME_PREFIX))); // NettyAllocator will return the channel type designed to work with the configuredAllocator serverBootstrap.channel(NettyAllocator.getServerChannelType()); // Set the allocators for both the server channel and the child channels created serverBootstrap.option(ChannelOption.ALLOCATOR, NettyAllocator.getAllocator()); serverBootstrap.childOption(ChannelOption.ALLOCATOR, NettyAllocator.getAllocator()); serverBootstrap.childHandler(configureServerChannelHandler()); serverBootstrap.handler(new ServerChannelExceptionHandler(this)); serverBootstrap.childOption(ChannelOption.TCP_NODELAY, SETTING_HTTP_TCP_NO_DELAY.get(settings)); serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, SETTING_HTTP_TCP_KEEP_ALIVE.get(settings)); // 省略局部代码 final ByteSizeValue tcpSendBufferSize = SETTING_HTTP_TCP_SEND_BUFFER_SIZE.get(settings); if (tcpSendBufferSize.getBytes() > 0) { serverBootstrap.childOption(ChannelOption.SO_SNDBUF, Math.toIntExact(tcpSendBufferSize.getBytes())); } final ByteSizeValue tcpReceiveBufferSize = SETTING_HTTP_TCP_RECEIVE_BUFFER_SIZE.get(settings); if (tcpReceiveBufferSize.getBytes() > 0) { serverBootstrap.childOption(ChannelOption.SO_RCVBUF, Math.toIntExact(tcpReceiveBufferSize.getBytes())); } serverBootstrap.option(ChannelOption.RCVBUF_ALLOCATOR, recvByteBufAllocator); serverBootstrap.childOption(ChannelOption.RCVBUF_ALLOCATOR, recvByteBufAllocator); final boolean reuseAddress = SETTING_HTTP_TCP_REUSE_ADDRESS.get(settings); serverBootstrap.option(ChannelOption.SO_REUSEADDR, reuseAddress); serverBootstrap.childOption(ChannelOption.SO_REUSEADDR, reuseAddress); // 绑定端口和地址 bindServer(); success = true; } finally { if (success == false) { doStop(); // otherwise we leak threads since we never moved to started } } }用过Netty晓得下面代码什么意思,设置worker线程,TCP设置,设置管道handler。Netty的连贯进去个别都是在childHandler()设置ChannelInitializer 实现类中增加,看下configureServerChannelHandler()次要初始化了HttpChannelHandler,在initChannel()能看到增加了那个处理器。 ...

February 9, 2023 · 2 min · jiezi

关于java:PostConstruct

@PostConstruct 是一种初始化形式以下述代码为例 TestController中成员变量testService被@Autowired润饰TestService将会在TestController构造方法执行后注入@Componentpublic class TestService { public TestService() { System.out.println("TestService construct"); } public void init() { System.out.println("TestService init"); }}@RestControllerpublic class TestController { @Autowired private TestService testService; public TestController() { System.out.println("TestController construct"); testService.init(); }}此时启动Spring利用,则会呈现报错,其起因就是testService在执行TestController构造方法时并没有实现初始化和注入;TestController初始化时须要执行依赖中的办法时,这种写法就会引起问题;此时就能够应用@PostConstruct来解决问题 Caused by: java.lang.NullPointerException: nullat com.example.demo.my.view.TestController.<init>(TestController.java:20) ~[classes/:na]at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:na]at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:na]at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490) ~[na:na]调整代码后 @RestControllerpublic class TestController { @Autowired private TestService testService; public TestController() { System.out.println("TestController construct"); } @PostConstruct public void initBeforeConstruct() { System.out.println("TestController PostConstruct"); testService.init(); }}此时启动输入后果从中可见总体的执行程序 ...

February 9, 2023 · 1 min · jiezi

关于java:类和对象

1. 类和对象1.1 类和对象的了解客观存在的事物皆为对象 ,所以咱们也经常说万物皆对象。 类 类的了解 类是对现实生活中一类具备独特属性和行为的事物的形象类是对象的数据类型,类是具备雷同属性和行为的一组对象的汇合简略了解:类就是对事实事物的一种形容类的组成 属性:指事物的特色,例如:手机事物(品牌,价格,尺寸)行为:指事物能执行的操作,例如:手机事物(打电话,发短信)类和对象的关系 类:类是对现实生活中一类具备独特属性和行为的事物的形象对象:是可能看失去摸的着的实在存在的实体简略了解:类是对事物的一种形容,对象则为具体存在的事物1.2 类的定义类的组成是由属性和行为两局部组成 属性:在类中通过成员变量来体现(类中办法外的变量)行为:在类中通过成员办法来体现(和后面的办法相比去掉static关键字即可)类的定义步骤: ①定义类 ②编写类的成员变量 ③编写类的成员办法 public class 类名 { // 成员变量 变量1的数据类型 变量1; 变量2的数据类型 变量2; … // 成员办法 办法1; 办法2; }示例代码: /* 手机类: 类名: 手机(Phone) 成员变量: 品牌(brand) 价格(price) 成员办法: 打电话(call) 发短信(sendMessage) */public class Phone { //成员变量 String brand; int price; //成员办法 public void call() { System.out.println("打电话"); } public void sendMessage() { System.out.println("发短信"); }}1.3 对象的应用创建对象的格局: 类名 对象名 = new 类名();调用成员的格局: 对象名.成员变量对象名.成员办法();示例代码/* 创建对象 格局:类名 对象名 = new 类名(); 范例:Phone p = new Phone(); 应用对象 1:应用成员变量 格局:对象名.变量名 范例:p.brand 2:应用成员办法 格局:对象名.办法名() 范例:p.call() */public class PhoneDemo { public static void main(String[] args) { //创建对象 Phone p = new Phone(); //应用成员变量 System.out.println(p.brand); System.out.println(p.price); p.brand = "小米"; p.price = 2999; System.out.println(p.brand); System.out.println(p.price); //应用成员办法 p.call(); p.sendMessage(); }}1.4 学生对象-练习需要:首先定义一个学生类,而后定义一个学生测试类,在学生测试类中通过对象实现成员变量和成员办法的应用剖析: ...

February 9, 2023 · 5 min · jiezi

关于java:再有人问你分布式事务把这篇文章砸过去给他

本文内容整顿自 博学谷狂野架构师事务的具体定义 事务提供一种机制将一个流动波及的所有操作纳入到一个不可分割的执行单元,组成事务的所有操作只有在所有操作均能失常执行的状况下方能提交,只有其中任一操作执行失败,都将导致整个事务的回滚。简略地说,事务提供一种“要么什么都不做,要么做全套(All or Nothing)”机制 数据库本地事务说到数据库事务就不得不说,数据库事务中的四大个性,ACIDA:原子性(Atomicity) 一个事务(transaction)中的所有操作,要么全副实现,要么全副不实现,不会完结在两头某个环节。事务在执行过程中产生谬误,会被回滚(Rollback)到事务开始前的状态,就像这个事务素来没有执行过一样。 就像你买货色要么交钱收货一起都执行,要么要是发不出货,就退钱。 C:一致性(Consistency) 事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。如果事务胜利地实现,那么零碎中所有变动将正确地利用,零碎处于无效状态。如果在事务中呈现谬误,那么零碎中的所有变动将主动地回滚,零碎返回到原始状态。 I:隔离性(Isolation) 指的是在并发环境中,当不同的事务同时操纵雷同的数据时,每个事务都有各自的残缺数据空间。由并发事务所做的批改必须与任何其余并发事务所做的批改隔离。事务查看数据更新时,数据所处的状态要么是另一事务批改它之前的状态,要么是另一事务批改它之后的状态,事务不会查看到中间状态的数据。 打个比方,你买货色这个事件,是不影响其他人的 D:持久性(Durability) 指的是只有事务胜利完结,它对数据库所做的更新就必须永恒保留下来。即便产生零碎解体,重新启动数据库系统后,数据库还能复原到事务胜利完结时的状态。 打个比方,你买货色的时候须要记录在账本上,即便老板遗记了那也有据可查。 简略而言,ACID是从不同维度形容事务的个性: 原子性 —— 事务操作的整体性一致性 —— 事务操作下数据的正确性隔离性 —— 事务并发操作下数据的正确性持久性 —— 事务对数据批改的可靠性一个反对事务(Transaction)的数据库,须要具备这4种个性,否则在事务过程当中无奈保证数据的正确性,处理结果极可能达不到申请方的要求。 什么时候应用数据库事务 在介绍完事务基本概念之后,什么时候该应用数据库事务? 简略而言,就是业务上有一组数据操作,须要如果其中有任何一个操作执行失败,整组操作全副不执行并复原到未执行状态,要么全副胜利,要么全副失败。 在应用数据库事务时须要留神,尽可能短的放弃事务,批改多个不同表的数据的简短事务会重大障碍零碎中的所有其余用户,这很有可能导致一些性能问题。 什么是分布式事务分布式产生背景与概念 随着互联网疾速倒退,微服务,SOA等服务架构模式正在被大规模的应用,当初分布式系统个别由多个独立的子系统组成,多个子系统通过网络通信相互合作配合实现各个性能。 有很多用例会跨多个子系统能力实现,比拟典型的是电子商务网站的下单领取流程,至多会波及交易系统和领取零碎,而且这个过程中会波及到事务的概念,即保障交易系统和领取零碎的数据一致性,此处咱们称这种跨零碎的事务为分布式事务,具体一点而言,分布式事务是指事务的参与者、反对事务的服务器、资源服务器以及事务管理器别离位于不同的分布式系统的不同节点之上。 举个互联网罕用的交易业务为例: 上图中蕴含了库存和订单两个独立的微服务,每个微服务保护了本人的数据库。在交易系统的业务逻辑中,一个商品在下单之前须要先调用库存服务,进行扣除库存,再调用订单服务,创立订单记录。 能够看到,如果多个数据库之间的数据更新没有保障事务,将会导致呈现子系统数据不统一,业务呈现问题。 分布式事务的难点事务的原子性 事务操作跨不同节点,当多个节点某一节点操作失败时,须要保障多节点操作的**要么什么都不做,要么做全套(All or Nothing)**的原子性。##### 事务的一致性 当产生网络传输故障或者节点故障,节点间数据复制通道中断,在进行事务操作时须要保证数据一致性,保障事务的任何操作都不会使得数据违反数据库定义的束缚、触发器等规定。 ##### 事务的隔离性 事务隔离性的实质就是如何正确多个并发事务的解决的读写抵触和写写抵触,因为在分布式事务管制中,可能会呈现提交不同步的景象,这个时候就有可能呈现“局部曾经提交”的事务。此时并发利用拜访数据如果没有加以控制,有可能呈现“脏读”问题。 本文由传智教育博学谷狂野架构师教研团队公布。 如果本文对您有帮忙,欢送关注和点赞;如果您有任何倡议也可留言评论或私信,您的反对是我保持创作的能源。 转载请注明出处!

February 9, 2023 · 1 min · jiezi

关于java:30-个-IDEA-常用小技巧应有尽有让你的撸码效率直接起飞

IDEA 作为Java开发工具的后起之秀,简直以碾压之势把其余对手甩在了身后,次要起因还是归功于:好用;尽管有点重,但仍旧瑕不掩瑜,内置了十分多的性能,大大提高了日常的开发效率,上面汇总了罕用的30个应用小技巧,学会之后,让你的撸码效率间接腾飞... 查看代码历史版本调整idea的虚拟内存:idea设置成eclipse的快捷键设置提醒词疏忽大小写敞开代码查看设置文档正文模板显示办法分隔符设置多行tab疾速匹配办法的大括号地位代码结尾补全含糊搜寻办法预览某个类的代码查看办法在哪里被调用代码模板(代码快捷键)主动导包、主动移除没用的包codota插件:能够优先显示应用频率较高的类、办法疾速查看类、字段的正文括号色彩辨别微服务项目中 将不同我的项目增加到同一个启动窗口idea全局设置 (关上新窗口的设置)java mapper层代码文件和mapper.xml文件互相跳转设置idea背景图片maven tree (查看maven jar包依赖关系)快捷键切换回上一个点击开的tabidea自带的ssh连贯工具代码调用链路图插件获取以后线程dumpidea同个我的项目不同端口多开给代码增加书签单词翻译插件留神:不同idea版本菜单、目录可能有细微差别,本人稍加剖析都能找到1.查看代码历史版本鼠标在须要查看的java类 右键 找到Local History >> Show History 点开即可看到历史版本,罕用于本人遗记代码改了哪些内容 或须要复原至某个版本 (留神 只能看近期批改 太久了也是看不到的) 2.调整idea的虚拟内存只管实质都是去扭转 .vmoptions配置文件,但举荐应用Change Memory Settings去调整,抉择Edit Custom VM Options 或者在本地磁盘目录更改,通过某些办法破解的idea 很可能造成idea打不开的状况 3.idea设置成eclipse的快捷键这对eclipse转idea的开发人员来说 十分敌对,这样不须要记两套快捷键 4.设置提醒词疏忽大小写把这个勾去掉,(有的idea版本是抉择选项 抉择none即可),例如String 输出string 、String 都能够提醒 5.敞开代码查看与eclipse相似,idea也能够本人敞开代码查看 缩小资源应用,但不举荐全副敞开,(是大佬当我没说),把咱们我的项目中不会应用到的敞开就好了 6.设置文档正文模板文档正文快捷键及模板 https://blog.csdn.net/qq_3626...7.显示办法分隔符不便查看办法与办法之间的距离,在代码不标准的我的项目中 很好用! 8.设置多行tabidea默认是抉择显示单行的,咱们把这个去掉,就能够显示多行tab了,在关上tab过多时的场景十分不便! 8.1 tab过多会主动敞开 settings - editor - General - Editor tabs - tab limit 数值设大就好了 9.疾速匹配办法的大括号地位ctrl+[ ctrl+] 能够疾速跳转到办法大括号的起止地位,配合办法分隔符应用,不怕找不到办法在哪儿宰割了 10.代码结尾补全例如一行代码补全分号,或者是if(xxx) 补全大括号,按ctrl+shift+enter 无需切换鼠标光标,大幅度晋升了编码效率 ...

February 9, 2023 · 2 min · jiezi

关于java:CPU利用率在什么范围会对系统性能产生影响如何做性能调优

01 “妄言”10分钟内调优CPU利用率绝大部分开发在面试时都会被面试官问到一个问题: “请举一个在以前工作过程中你感觉本人做的十分不错的事例” 换言之:“请吹一个牛” 个别人呢,这个牛他会悠着点吹,大多数合乎“28定律”,8分瞎话2分润色 然而有一位不愿走漏姓名的高级开发同学曾大言不惭的说: “我只有10分钟就能疾速调优生产环境机器的CPU利用率” 02 同学,请你开展说说我的前东家是做社交电商的,前两年正是社交电商的风口,碰上风口猪都能飞,然而咱们零碎架构性能都太弱了,撑不起这头猪。比方用户常常会遇到: 查个商品,页面转啊转......下个单,页面转啊转......看个买家秀,页面转啊转......老板就下了死命令,两周内所有主流程接口的RT(接口响应工夫)必须优化到200ms以内!超出多少ms扣多少KPI。 同学,你不要展得太开了,说重点,回到CPU利用率调优上来!!! 哦哦哦,我须要先把这个问题背景交代分明: 咱们负责的利用有个接口,逻辑很简略,次要是数据计算失常耗时个别都在130ms左右但它总时不时的飚到200ms以上利用所在机器的内存、网络、磁盘等资源都失常,CPU在50%左右并发量不高共事查了一天,代码的计算逻辑曾经优化到极致,问题仍然没有解决。 03 这一波操作,秀!同一个申请、同一个逻辑,资源稳固,为什么有时候耗时高有时候失常? 解决问题的要害就是找出申请在执行过程中的不同之处。 我用Kindling程序摄像头别离捕获了失常和异样两种状况下的申请。 失常-200ms以下:异样-200ms以上:能够分明的看到,耗时200ms以上的申请,消耗了大量的工夫在做other事件 (即CPU runqueue,kindling开源团队目前还在调整,后续会将这个名词明确展现)。 “ 啥是CPU runqueue?什么状况下会导致程序CPU runqueue工夫长?援用这其实是咱们大学课程计算机原理里的基础知识:CPU runqueue 是一个示意期待 CPU 工夫的概念。它是一个零碎的流动队列,用于存储正在期待 CPU 资源的过程。援用当一个过程申请 CPU 资源时,它会被增加到 runqueue,期待 CPU 调配工夫片。当 CPU 工夫片调配给过程时,该过程会从 runqueue 中移除。援用runqueue 工夫是指过程在 runqueue 中期待 CPU 工夫的长度。如果 runqueue 工夫过长,则意味着 CPU 资源缓和,无奈及时处理所有申请。”援用另外能够切换到Kindling程序摄像头里这个耗时超200ms的简单视图: 持续滑动查看更多线程: 能够看到有上百个线程在并发执行工作 (后经查代码确认这是某开发在利用里写的定时工作) 这就意味着CPU runqueue里有很多工作在排队,尽管这台机器的CPU利用率是在50%左右,看似不高,但并发线程越多,CPU调度起来越慢,所以有些申请如果被排在前面,执行就会较慢。 找到根因,调优方法很简略: 减少CPU资源或者查看这些大量并发线程执行的工作是否可能优化,缩小CPU的开销。或者调整过程的优先级,来管制CPU资源的调配04 最初说点正经话CPU利用率太低意味着CPU没有失去正当利用,资源节约;过高又会对系统的性能造成影响。 大多数运维是依据教训去判断CPU的最高阀值,然而不同的业务状况,对CPU利用率的要求其实是不一样的。 大家都晓得CPU打满到100%必定会让利用解体,那80%对性能的影响又有多大?40%就靠谱了吗? 这个指标无奈作为利用性能的衡量标准,究其基本,CPU runqueue的工夫才是掂量要害。咱们须要依据理论状况调优。 而Kindling程序摄像头是一个很好的工具,如上文所举的案例,咱们能借助它“看到”不同CPU资源下,程序的理论执行状况,疾速找到调优方向。 05  附录 - Kindling程序摄像头技术介绍Kindling程序摄像头精准还原程序执行现场的能力能够帮忙咱们: 排障:分钟级内定位全资源品种故障根因调优:可视化展现资源配置对程序执行状况的影响**Kindling基于eBPF技术交融了Tracing,logging,metrics。 换句话说,它曾经把该接口执行时刻的所有数据: 网络、磁盘、内存等性能指标mysql、redis等网络申请的连贯信息和报文信息,日志,堆栈,锁信息以及文件IO信息.......(欢送来试用,发现Kindling更多能力)都筛选捕获进去,附着在对应的线程事件上,精准还原程序执行的现场。07  附录 - 对于Kindling的更多材料 如果想要理解它的实现原理,能够参考下文链接:eBPF程序摄像头——力争解决可观测性畛域将来最有价值且最有挑战的难题 ...

February 9, 2023 · 1 min · jiezi

关于java:Terraform-101-从入门到实践-第一章-Terraform初相识

《Terraform 101 从入门到实际》这本小册在南瓜慢说官方网站和GitHub两个中央同步更新,书中的示例代码也是放在GitHub上,不便大家参考查看。初闻不知Terraform,再闻已是云中人。什么叫基础设施即代码?在以前,当咱们须要把利用部署在服务器时,须要购买多台服务器和机房、组装交换机和网络、不间断电源UPS等。随着云时代的到来,咱们能够在IaaS(Infrastructure as a Service)平台间接购买所有的基础设施,包含服务器、专用网络、DNS、负载平衡等,而你只须要专一于利用层面即可。 IaaS(Infrastructure as a Service)的意思是基础设施即服务,它是云服务的根底。驰名的IaaS厂商有亚马逊、微软、谷歌和阿里云等。 云厂商为咱们解决了许多运维问题:咱们不再须要本人治理物理机器,而且可能依据须要随时创立和销毁云机器,还能依据业务和性能要求指定创立服务器的配置和数量。这种便当对于守业型的小公司和集体开发者尤其重要。 随时公司业务的良好倒退,所须要的硬件资源越来越多,架构越来越简单。通过界面操作手工创立服务器、数据库等资源的形式带来越来越多的问题。首先,只有是人工操作,都会有失误的可能,没有人能保障本人不会犯错;而人工操作在软件行业产生事变的案例不足为奇。其次,为保障正确率,人工操作个别只能串行,资源多的时候工夫会很长。最初,如果我须要依据开发环境的配置再创立一个测试环境和生产环境,人工操作可能会造成差别和谬误。 因而,对于这种简单须要,最佳的形式是通过代码来创立所有硬件资源。这种思维就是基础设施即代码(Infrastructure as Code,很简称IaC),通过代码与定义、部署、更新和销毁基础设施。把硬件映射为软件,而开发和运维人员通过治理代码来治理硬件。 IaC的益处有: 自动化:与软件代替人工,实现自动化,缩小危险和平安问题;效率高:软件能够并行创立资源,大大提高效率;记录与追踪:通过代码与执行状况,记录硬件变更,出问题也能够追溯;重用与复制:抽取公共模块实现重用,如创立一个Kubernetes集群的资源能够封装成一个模块。最终,实现疾速平安地利用部署交付(Devivery)。 IaC工具在IaC这方面的优良工具还是十分多的,而且不同的工具实现不同的职责,上面列出一些比拟常见的工具: 图标工具名GitHub STAR数<img src="https://pkslow.oss-cn-shenzhen.aliyuncs.com/images/other/terraform-101/pictures/01.introduction/logo.ansible.png" width="40">Ansible50.9k<img src="https://pkslow.oss-cn-shenzhen.aliyuncs.com/images/other/terraform-101/pictures/01.introduction/logo.terraform.png" width="80">Terraform30.2k<img src="https://pkslow.oss-cn-shenzhen.aliyuncs.com/images/other/terraform-101/pictures/01.introduction/logo.vagrant-logo.png" width="80">Vagrant23k<img src="https://pkslow.oss-cn-shenzhen.aliyuncs.com/images/other/terraform-101/pictures/01.introduction/logo.chef.png" width="40">Chef6.8k<img src="https://pkslow.oss-cn-shenzhen.aliyuncs.com/images/other/terraform-101/pictures/01.introduction/logo.puppet.jpg" width="40">Puppet6.4k<img src="https://pkslow.oss-cn-shenzhen.aliyuncs.com/images/other/terraform-101/pictures/01.introduction/logo.aws-cf.png" width="40">AWS CloudFormation <img src="https://pkslow.oss-cn-shenzhen.aliyuncs.com/images/other/terraform-101/pictures/01.introduction/logo.azure-resource-manager.jpg" width="40">Azure Resource Manager <img src="https://pkslow.oss-cn-shenzhen.aliyuncs.com/images/other/terraform-101/pictures/01.introduction/logo.google-deployment-manager.jpg" width="40">Google Cloud Deployment Manager 其中,Ansible在配置自动化应该是领头羊的位置。而Terraform则在服务开明上的事实标准。这里并不想给各个工具做具体介绍,感兴趣的能够去官网或GitHub理解。 注:有些文章或书籍会把Docker和Kubernetes也列为IaC工具,它们的主要职责是在容器与服务编排方面。 Terraform隆重退场Terraform是什么咱们的配角Terraform终于退场了。它是由HashiCorp公司研发的开源的IaC工具,它是由GO语言编写的,能够在各个平台上运行,反对Linux、Mac、Windows等。它简略易用,即便没有太多代码教训的人,也能读懂Terraform的配置代码HCL。 HCL,即HashiCorp Configuration Language,是HashiCorp公司开发的配置语言。后续咱们会介绍一些罕用语法。Terraform是一个平安高效的用于对基础设施进行创立和变更且进行版本控制的工具。它反对公有云和私有云,如AWS、Azure、GCP和阿里云等。它的官方网站为https://www.terraform.io。 个性次要个性有: 基础设施即代码:通过配置语言HCL来形容基础设施,也让代码更好地共享和重用。变更打算:在理论变更前能够依据代码和状态生成行将要产生变更的打算,它能通知你将要生成、扭转和销毁哪些资源。这能够在执行变更前再做最好的查看,为基础设施提供多一层爱护。资源视图:能够依据依赖关系创立出资源视图,能够直观地查看整个基础设施的关系。自动化:毋庸人工干预就能够实现变更。版本号截至2021年12月02日,Terraform的最新版本为1.0.11,而它在2021年6月8日才正式公布1.0.0版本。可见Terraform是如此年老且有生机。而在Terraform还不是1.0.0版本的时候,曾经有大量公司在生产环境上应用了。 架构与原理Terraform是一个由Go语言编写的程序,它会读取HCL语言编写的配置文件,而后将变更信息通过RPC与插件通信,由插件调用云厂商的API实现变更操作。这就是Terraform的工作原理,架构图如下: 基本概念Terraform core:Terraform的外围组件,相似于指挥官,负责解析配置、治理状态、模块等外围性能。 插件Plugin:实现具体变更的组件,因为Terraform反对多种平台,它并没有把对所有平台的反对都放到外围组件中实现,而是通过插件的形式来提供这些性能。须要对接什么平台,就退出什么平台的插件,十分方面。 模块module:能够将实现特定性能的HCL封装成一个模块,以实现代码复用。相似于其它编程语言中的函数或办法。有入参和出参,所有都可自定义。 状态state:状态存在专门的状态文件里,它是作用是记录理论基础设施的状态。当再次执行变更申请时,Terraform会读取状态文件,判断是否真的须要变更理论的基础设施。如果状态文件记录的状态与HCL形容的统一,就不必再执行变更操作了。 初体验下载安装Terraform就是一个二进制的程序,只有下载并增加到PATH中去就能够了。各个系统的装置形式没有太大差别。这里以Mac零碎为例,做个简略介绍。 下载程序: 能够间接到官网界面(https://www.terraform.io/down...)去下载,请依据本人的零碎抉择对应的文件: 下载后进行解压,并将该程序增加到环境变量中。 比方我的Terraform放在门路/Users/larry/Software/terraform中,则增加到环境变量的命令如下: export PATH=$PATH:/Users/larry/Software/terraform为了让它始终失效,我把下面命令放在home目录下的.bash_profile文件中。 查看是否装置胜利如下: $ terraform versionTerraform v1.0.11on darwin_amd64如果在纯终端的环境下,也能够通过命令进行下载和解压,命令如下: # 下载安装包$ wget https://releases.hashicorp.com/terraform/1.0.11/terraform_1.0.11_darwin_amd64.zip# 解压$ unzip terraform_1.0.11_darwin_amd64.zip最简略的工作:创立一个文件Terraform的次要利用场景是云服务的基础设施治理,但为了让大家能疾速的接触与体验Terraform,我会先抉择最简略的一个插件来入门,免得须要太多的环境设置。咱们的工作是创立一个文本文件,内容由咱们来指定。能够通过插件hashicorp/local来实现。 在当前目录创立一个main.tf文件,残缺的代码如下: terraform { required_version = "= v1.0.11" required_providers { local = { source = "hashicorp/local" version = "= 2.1.0" } }}resource "local_file" "terraform-introduction" { content = "Hi guys, this the tutorial of Terraform from pkslow.com" filename = "${path.module}/terraform-introduction-by-pkslow.txt"}而后执行上面命令: ...

February 9, 2023 · 4 min · jiezi

关于java:对线面试官浅聊一下-Java-虚拟机栈

对于 JVM(Java 虚拟机)来说,它有两个十分重要的区域,一个是栈(Java 虚拟机栈),另一个是堆。堆是 JVM 的存储单位,所有的对象和数组都是存储在此区域的;而栈是 JVM 的运行单位,它主管 Java 程序运行的。那么为什么它有这样的魔力?它存储的又是什么数据?接下来,咱们一起来看。 1.栈定义咱们先来看栈的定义,咱们这里的栈指的是 Java 虚拟机栈(Java Virtual Machine Stack)也叫做 JVM 栈,《Java虚拟机标准》对此区域的阐明如下: Each Java Virtual Machine thread has a private _Java Virtual Machine stack_, created at the same time as the thread. A Java Virtual Machine stack stores frames (§2.6). A Java Virtual Machine stack is analogous to the stack of a conventional language such as C: it holds local variables and partial results, and plays a part in method invocation and return. Because the Java Virtual Machine stack is never manipulated directly except to push and pop frames, frames may be heap allocated. The memory for a Java Virtual Machine stack does not need to be contiguous.In the First Edition of The Java® Virtual Machine Specification, the Java Virtual Machine stack was known as the Java stack.This specification permits Java Virtual Machine stacks either to be of a fixed size or to dynamically expand and contract as required by the computation. If the Java Virtual Machine stacks are of a fixed size, the size of each Java Virtual Machine stack may be chosen independently when that stack is created.A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of Java Virtual Machine stacks, as well as, in the case of dynamically expanding or contracting Java Virtual Machine stacks, control over the maximum and minimum sizes.The following exceptional conditions are associated with Java Virtual Machine stacks: ...

February 9, 2023 · 2 min · jiezi

关于java:Terraform-101-从入门到实践-前言

《Terraform 101 从入门到实际》这本小册在南瓜慢说官方网站和GitHub两个中央同步更新,书中的示例代码也是放在GitHub上,不便大家参考查看。Terraform 101 从入门到实际Terraform作为基础设施即代码(Infrastructure as Code,很简称IaC)的事实标准,十分值得大家学习。我是工作中会应用私有云,所以须要常常应用Terraform作为IaC工具以实现自动化部署;也花工夫考取了Terraform Associate的证书。所以对它的应用我还是有一些教训的。但Terraform自身倒退是比拟快的,国内的材料也绝对较少,所以我整顿了我的学习心得,心愿能够帮忙到大家。 因而,我做了一个决定,将知识点整顿成小册,叫《Terraform 101 从入门到实际》。该小册会一直减少和欠缺内容,所以初期会有很多不完满的中央。如果大家有问题能够提Issue,但后期不会解决。因为工作变动和育儿的起因,我须要学习和适应,没有ETA,缓缓更新吧。 但Terraform的基本概念是曾经介绍了的,理解与入门是够用了。我会尽量在工作之余、带娃之余、睡觉之余挤时间实现。这篇文章也算是立个Flag,并自我监督吧。 如果大家感觉不错,能够善意给个STAR反对一下哦。你的激励,是我的能源。 GitHub目录: 前言第一章 Terraform初相识第二章 Providers插件治理第三章 Modules模块化第四章 States状态治理第五章 HCL语法Functions函数Terraform常用命令Terraform在私有云GCP上的利用Terraform在私有云Azure上的利用Terraform问题定位与剖析(未开始)插件开发(未开始)最佳实际(未开始)开发套件(未开始)博客目录: 前言第一章 Terraform初相识第二章 Providers插件治理第三章 Modules模块化第四章 States状态治理第五章 HCL语法Functions函数Terraform常用命令Terraform在私有云GCP上的利用Terraform在私有云Azure上的利用最初,附上我的Terraform证书: <img src="https://pkslow.oss-cn-shenzhen.aliyuncs.com/images/other/terraform-101/pictures/00.preface/terraform-associate.certificate.png" width="300" alt="">

February 8, 2023 · 1 min · jiezi

关于java:大哥这是并发不是并行Are-You-Ok

本文内容整顿自 博学谷狂野架构师 多线程概述 根底概念过程和线程过程是程序运行资源分配的最小单位 过程是操作系统进行资源分配的最小单位,其中资源包含:CPU、内存空间、磁盘IO等,同一过程中的多条线程共享该过程中的全副系统资源,而过程和过程之间是互相独立的。过程是具备肯定独立性能的程序对于某个数据汇合上的一次运行流动,过程是零碎进行资源分配和调度的一个独立单位。 过程是程序在计算机上的一次执行流动。当你运行一个程序,你就启动了一个过程。显然,程序是死的、动态的,过程是活的、动静的。过程能够分为零碎过程和用户过程。但凡用于实现操作系统的各种性能的过程就是零碎过程,它们就是处于运行状态下的操作系统自身,用户过程就是所有由你启动的过程。 线程是CPU调度的最小单位,必须依赖于过程而存在 线程是过程的一个实体,是CPU调度和分派的根本单位,它是比过程更小的、能独立运行的根本单位。线程本人基本上不领有系统资源,只领有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),然而它可与同属一个过程的其余的线程共享过程所领有的全副资源。 线程无处不在 任何一个程序都必须要创立线程,特地是Java不论任何程序都必须启动一个main函数的主线程; Java Web开发外面的定时工作、定时器、JSP和 Servlet、异步音讯解决机制,近程拜访接口RM等,任何一个监听事件, onclick的触发事件等都离不开线程和并发的常识。 CPU外围数和线程数的关系 多外围:也指单芯片多处理器( Chip Multiprocessors,简称CMP),CMP是由美国斯坦福大学提出的,其思维是将大规模并行处理器中的SMP(对称多处理器)集成到同一芯片内,各个处理器并行执行不同的过程。这种依附多个CPU同时并行地运行程序是实现超高速计算的一个重要方向,称为并行处理 多线程: Simultaneous Multithreading.简称SMT.让同一个处理器上的多个线程同步执行并共享处理器的执行资源。 外围数、线程数:目前支流CPU都是多核的。减少外围数目就是为了减少线程数,因为操作系统是通过线程来执行工作的,个别状况下它们是1:1对应关系,也就是说四核CPU个别领有四个线程。但 Intel引入超线程技术后,使外围数与线程数造成1:2的关系 CPU工夫片轮转机制 为什么感触不到CPU线程数的限度咱们平时在开发的时候,感觉并没有受cpu外围数的限度,想启动线程就启动线程,哪怕是在单核CPU上,为什么?这是因为操作系统提供了一种CPU工夫片轮转机制。 工夫片轮转调度是一种最古老、最简略、最偏心且应用最广的算法,又称RR调度。每个过程被调配一个时间段,称作它的工夫片,即该过程容许运行的工夫。 什么是CPU轮转机制百度百科对CPU工夫片轮转机制原理解释如下: 如果在工夫片完结时过程还在运行,则CPU将被剥夺并调配给另一个过程。如果过程在工夫片完结前阻塞或结来,则CPU当即进行切换。调度程序所要做的就是保护一张就绪过程列表,当过程用完它的工夫片后,它被移到队列的开端 工夫片长度 工夫片轮转调度中惟一乏味的一点是工夫片的长度。从一个过程切换到另一个过程是须要定工夫的,包含保留和装入寄存器值及内存映像,更新各种表格和队列等。如果过程切( processwitch),有时称为上下文切换( context switch),须要5ms,再假如工夫片设为20ms,则在做完20ms有用的工作之后,CPU将破费5ms来进行过程切换。CPU工夫的20%被节约在了治理开销上了。 为了进步CPU效率,咱们能够将工夫片设为5000ms。这时节约的工夫只有0.1%。但思考到在一个分时系统中,如果有10个交互用户简直同时按下回车键,将产生什么状况?假如所有其余过程都用足它们的工夫片的话,最初一个可怜的过程不得不期待5s才取得运行机会。少数用户无法忍受一条简短命令要5能力做出响应,同样的问题在一台反对多道程序的集体计算机上也会发 论断能够归纳如下:工夫片设得太短会导致过多的过程切换,升高了CPU效率:而设得太长又可能引起对短的交互申请的响应变差。将工夫片设为100ms通常是一个比拟正当的折衷。 在CPU死机的状况下,其实大家不难发现当运行一个程序的时候把CPU给弄到了100%再不重启电脑的状况下,其实咱们还是有机会把它KILL掉的,我想也正是因为这种机制的缘故。 廓清并行和并发 咱们举个例子,如果有条高速公路A下面并排有8条车道,那么最大的并行车辆就是8辆此条高速公路A同时并排行走的车辆小于等于8辆的时候,车辆就能够并行运行。CPU也是这个原理,一个CPU相当于一个高速公路A,外围数或者线程数就相当于并排能够通行的车道;而多个CPU就相当于并排有多条高速公路,而每个高速公路并排有多个车道。 当议论并发的时候肯定要加个单位工夫,也就是说单位工夫内并发量是多少?来到了单位工夫其实是没有意义的。 俗话说,二心不能二用,这对计算机也一样,原则上一个CPU只能调配给一个过程,以便运行这个过程。咱们通常应用的计算机中只有一个CPU,也就是说只有一颗心,要让它一心多用同时运行多个过程,就必须应用并发技术。实现并发技术相当简单,最容易了解的是“工夫片轮转过程调度算法”。 综合来说: 并发:指利用可能交替执行不同的工作,比方单CPU外围下执行多线程并非是同时执行多个工作,如果你开两个线程执行,就是在你简直不可能察觉到的速度一直去切换这两个工作,已达到"同时执行成果",其实并不是的,只是计算机的速度太快,咱们无奈察觉到而已. 并行:指利用可能同时执行不同的工作,例:吃饭的时候能够边吃饭边打电话,这两件事件能够同时执行 两者区别:一个是交替执行,一个是同时执行. 感觉上是同时产生的,然而宏观上还是有区别的,并行是批准时刻产生的,并发是同一时刻交替执行 高并发的意义因为多核多线程的CPU的诞生,多线程、高并发的编程越来越受器重和关注。多线程能够给程序带来如下益处。1. 充分利用CPU的资源 从下面的CPU的介绍,能够看的进去,当初市面上没有CPU的内核不应用多线程并发机制的,特地是服务器还不止一个CPU,如果还是应用单线程的技术做思路,显著就out了。因为程序的根本调度单元是线程,并且一个线程也只能在一个CPU的一个核的一个线程跑,如果你是个i3的CPU的话,最差也是双核心4线程的运算能力:如果是一个线程的程序的话,那是要节约3/4的CPU性能:如果设计一个多线程的程序的话,那它就能够同时在多个CPU的多个核的多个线程上跑,能够充沛地利用CPU,缩小CPU的闲暇工夫,施展它的运算能力,进步并发量。 就像咱们平时坐地铁一样,很多人坐长线地铁的时候都在认真看书,而不是为了坐地铁而坐地铁,到家了再去看书,这样你的工夫就相当于有了两倍。这就是为什么有些人工夫很富余,而有些人老是说没工夫的一个起因,工作也是这样,有的时候能够并发地去做几件事件,充分利用咱们的工夫,CPU也是一样,也要充分利用。 2. 放慢响应用户的工夫 比方咱们常常用的迅雷下载,都喜爱多开几个线程去下载,谁都不违心用一个线程去下载,为什么呢?答案很简略,就是多个线程下载快啊。 咱们在做程序开发的时候更应该如此,特地是咱们做互联网我的项目,网页的响应工夫若晋升1s,如果流量大的话,就能减少不少转换量。做过高性能web前端调优的都晓得,要将动态资源地址用两三个子域名去加载,为什么?因为每多一个子域名,浏览器在加载你的页面的时候就会多开几个线程去加载你的页面资源,晋升网站的响应速度。多线程,高并发真的是无处不在。 3. 能够使你的代码模块化,异步化,简单化 例如咱们实现电商零碎,下订单和给用户发送短信、邮件就能够进行拆分,将给用户发送短信、邮件这两个步骤独立为独自的模块,并交给其余线程去执行。这样既减少了异步的操作,晋升了零碎性能,又使程序模块化,清晰化和简单化。 ...

February 8, 2023 · 1 min · jiezi

关于java:解读-Java-云原生实践中的内存问题

Java 凭借着本身沉闷的开源社区和欠缺的生态劣势,在过来的二十几年始终是最受欢迎的编程语言之一。步入云原生时代,蓬勃发展的云原生技术开释云计算红利,推动业务进行云原生化革新,减速企业数字化转型。 然而 Java 的云原生转型之路面临着微小的挑战,Java 的运行机制和云原生个性存在着诸多矛盾。企业借助云原生技术进行深层次老本优化,资源老本治理被回升到前所未有的高度。私有云上资源按量免费,用户对资源用量非常敏感。在内存应用方面,基于 Java 虚拟机的执行机制使得任何 Java 程序都会有固定的根底内存开销,相比 C++/Golang 等原生语言,Java 利用占用的内存微小,被称为“内存吞噬者”,因而 Java 利用上云更加低廉。并且利用集成到云上之后零碎复杂度减少,普通用户对云上 Java 利用内存没有清晰的意识,不晓得如何为利用合理配置内存,呈现 OOM 问题时也很难排障,遇到了许多问题。为什么堆内存未超过 Xmx 却产生了 OOM?怎么了解操作系统和JVM的内存关系? 为什么程序占用的内存比 Xmx 大不少,内存都用在哪儿了?为什么线上容器内的程序内存需要更大?本文将 EDAS 用户在 Java 利用云原生化演进实际中遇到的这些问题进行了抽丝剥茧的剖析,并给出云原生 Java 利用内存的配置倡议。 背景常识K8s 利用的资源配置云原生架构以 K8s 为基石,利用在 K8s 上部署,以容器组的状态运行。K8s 的资源模型有两个定义,资源申请(request)和资源限度(limit),K8s 保障容器领有 request数量的资源,但不容许应用超过limit数量的资源。以如下的内存配置为例,容器至多能取得 1024Mi 的内存资源,但不容许超过 4096Mi,一旦内存应用超限,该容器将产生OOM,而后被 K8s 控制器重启。 spec: containers: - name: edas image: alibaba/edas resources: requests: memory: "1024Mi" limits: memory: "4096Mi" command: ["java", "-jar", "edas.jar"]容器 OOM对于容器的 OOM 机制,首先须要来温习一下容器的概念。当咱们谈到容器的时候,会说这是一种沙盒技术,容器作为一个沙盒,外部是绝对独立的,并且是有边界有大小的。容器内独立的运行环境通过 Linux的Namespace 机制实现,对容器内 PID、Mount、UTS、IPD、Network 等 Namespace 进行了障眼法解决,使得容器内看不到宿主机 Namespace 也看不到其余容器的 Namespace;而所谓容器的边界和大小,是指要对容器应用 CPU、内存、IO 等资源进行束缚,不然单个容器占用资源过多可能导致其余容器运行迟缓或者异样。Cgroup 是 Linux 内核提供的一种能够限度单个过程或者多个过程所应用资源的机制,也是实现容器资源束缚的核心技术。容器在操作系统看来只不过是一种非凡过程,该过程对资源的应用受 Cgroup 的束缚。当过程应用的内存量超过 Cgroup 的限度量,就会被零碎 OOM Killer 无情地杀死。 ...

February 8, 2023 · 4 min · jiezi

关于java:Java导出word文档

最近公司做我的项目,须要导出word或者PDF文档,PDF实现文档曾经驾轻就熟了,想钻研搞一下word文档。通过调研发现了一个好用的开源我的项目Poi-tl http://deepoove.com/poi-tl poi-tl是一个基于Apache POI的Word模板引擎,也是一个收费开源的Java类库,你能够十分不便的退出到你的我的项目中,并且领有着让人喜悦的个性 性能很弱小,能够基于模板生成,写了一个demo public class Demo { public static void main(String[] args) throws IOException { InputStream inputStream = Demo.class.getResourceAsStream("/template.docx"); String upgrade = "{\"upgradeStrategy\":0,\"fileDownloadModel\":0,\"downloadUrl\":\"http://downloadurl\",\"userName\":\"admin\",\"password\":\"admin\",\"bucket\":\" test\",\"path\":\"test/test.zip\",\"fileName\":\"test.zip\",\"fileSize\":10000,\"signatureMethod\":0,\"signatureValue\":\"123456asadsasdsa\",\"fileVersion\":1.0,\"upgradeStartTime\":\"2022-10-12 18:00:00\",\"extend\":{\"key1\":\"value2\",\"key2\":\"value2\"},\"timestamp\":\"2022-07-11 16:06:54\"}" ; JSONObject jsonObject = JSONObject.parseObject(upgrade); HighlightRenderData code = new HighlightRenderData(); code.setCode(JSONObject.toJSONString(jsonObject, true)); code.setLanguage("javascript"); code.setStyle(HighlightStyle.builder().withShowLine(false).withTheme("vs").build()); List<Goods> goods = new ArrayList<>(); Goods good = new Goods(); good.setCount(4); good.setName("墙纸"); good.setDesc("书房卧室"); good.setDiscount(1500); good.setPrice(400); good.setTax(new Random().nextInt(10) + 20); good.setTotalPrice(1600); good.setPicture(Pictures.ofUrl("http://deepoove.com/images/icecream.png") .size(100, 100).create()); goods.add(good); goods.add(good); goods.add(good); List<Params> paramsList = new ArrayList<>(); Params params1 = new Params(); params1.setProductKey("productKey"); params1.setParamType("String"); params1.setDescText("要发送音讯产品的ProductKey"); paramsList.add(params1); Params params2 = new Params(); params2.setProductKey("upgradeStrategy"); params2.setParamType("String"); params2.setDescText("降级策略(0:立刻降级 1:定时降级 2:勾销降级 3:仅下载 4:仅降级)"); paramsList.add(params2); Params params3 = new Params(); params3.setProductKey("downloadUrl"); params3.setParamType("String"); params3.setDescText(null); paramsList.add(params3); LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy(); Configure config = Configure.builder().bind("code", new HighlightRenderPolicy()).bind("goods", policy).bind("paramsList",policy) .useSpringEL() .build(); XWPFTemplate template = XWPFTemplate.compile(inputStream, config).render( new HashMap<String, Object>() {{ put("title", "Hi, poi-tl Word模板引擎"); put("code", code); put("goods", goods); put("paramsList",paramsList); }}); template.writeAndClose(new FileOutputStream("output"+UUID.randomUUID().toString().replace("-","")+".docx")); }}word 模板: ...

February 8, 2023 · 1 min · jiezi

关于java:面试必备多线程&高并发通关手册面试源码脑图

前言当你开始开始去跳槽面试的时候,明明只是一份15K的工作,却问你会不会多线程,懂不懂高并发,火箭造得让你猝及不防,后果就是凉凉;现如今市场,多线程、高并发编程、分布式、负载平衡、集群等能够说是当初高级后端开发求职的必备技能。 很多人领有大厂梦,却因为多线程与高并发败下阵来。实际上,多线程与高并发并不难,明天这份最全的多线程与高并发总结,助你向大厂“开炮”,面试不再被多线程与高并发难倒。 留神:对于多线程与高并发的内容整顿,包含了面试题、学习笔记、应用文档以及Xmind思维图几个局部,须要高清完整版《多线程与高并发》的敌人【点击此处】即可收费获取!一、多线程与高并发(面试题汇合总结)多线程与高并发面试题(根底局部) 你如何确保main()办法所在的线程是Java程序最初完结的线程?ThreadLocal原理 ThreadLocal内存结构图 什么是死锁(Deadlock)?如何剖析和防止死锁?什么是Java Timer类?如何创立一个有特定工夫距离的工作?什么是线程池?如何创立一个Java线程池?什么是并发容器的实现?Executors类是什么?说说CountDownLatch与CyclicBarrier区别 多线程与高并发面试题(高级进阶局部) 在静态方法上应用同步时会产生什么事?在一个对象上两个线程能够调用两个不同的同步实例办法吗?Fork/Join框架的了解 什么是死锁volatile 是什么?能够保障有序性吗?CAS?CAS 有什么缺点,如何解决? Thread 类中的start() 和 run() 办法有什么区别?Java中interrupted 和 isInterruptedd办法的区别?如何检测死锁?怎么预防死锁?死锁四个必要条件 多线程与高并发面试答案解析 多线程与高并发的关系区别“高并发和多线程”总是被一起提起,给人感觉两者如同相等,实则高并发 ≠ 多线程 1.多线程 多线程是java的个性,因为当初cpu都是多核多线程的,能够同时执行几个工作,为了进步jvm的执行效率,java提供了这种多线程的机制,以加强数据处理效率。多线程对应的是cpu,高并发对应的是拜访申请,能够用单线程解决所有拜访申请,也能够用多线程同时解决拜访申请。 在过来单CPU时代,单任务在一个工夫点只能执行繁多程序。之后倒退到多任务阶段,计算机能在同一时间点并行执行多任务或多过程。尽管并不是真正意义上的“同一时间点”,而是多个工作或过程共享一个CPU,并交由操作系统来实现多任务间对CPU的运行切换,以使得每个工作都有机会取得肯定的工夫运行。 再起初倒退到多线程技术,使得在一个程序外部能领有多个线程并行执行。一个线程的执行能够被认为是一个CPU在执行该程序。当一个程序运行在多线程下,就如同有多个CPU在同时执行该程序。 总之,多线程即能够这么了解:多线程是解决高并发的一种编程办法,即并发须要用多线程实现。 2.高并发 高并发不是JAVA的专有的货色,是语言无关的狭义的,为提供更好互联网服务而提出的概念。 典型的场景,例如:12306抢火车票,天猫双十一秒杀流动等。该状况的产生会导致系统在这段时间内执行大量操作,例如对资源的申请,数据库的操作等。如果高并发解决不好,不仅仅升高了用户的体验度(申请响应工夫过长),同时可能导致系统宕机,重大的甚至导致OOM异样,零碎进行工作等。 如果要想零碎可能适应高并发状态,则须要从各个方面进行系统优化,包含,硬件、网络、零碎架构、开发语言的选取、数据结构的使用、算法优化、数据库优化等……而多线程只是其中解决办法之一。 对于多线程与高并发的理论利用Java 高并发编程详解:多线程与架构设计 第一局部:多线程根底 次要论述 Thread 的基础知识,具体介绍线程的 API 应用、线程平安、线程间数据通信,以及如何爱护共享资源等内容,它是深刻学习多线程内容的根底。 第二局部:Java ClassLoader 引入了 ClassLoader,这是因为 ClassLoader 与线程不无关系,咱们能够通过 synchronized 关键字,或者 Lock 等显式锁的形式在代码的编写阶段对共享资源进行数据一致性爱护,那么一个 Class 在实现初始化的整个过程到后在办法区(JDK8 当前在元数据空间)其数据结构是怎么确保数据一致性的呢?这就须要对 ClassLoader 有一个比拟全面的意识和理解。第三局部:深刻了解volatile关键字 第三局部具体、深刻地介绍 volatile 关键字的语义,volatile 关键字在 Java 中十分重要,能够说它奠定了 Java 外围并发包的高效运行,在这一部分中,咱们通过实例展现了如何应用 volatile 关键字以及十分具体地介绍了 Java 内存模型等常识。 ...

February 8, 2023 · 1 min · jiezi

关于java:Java-CompletableFuture-异步超时实现探索

作者:京东科技 张天赐 前言JDK 8 是一次重大的版本升级,新增了十分多的个性,其中之一便是 CompletableFuture。自此从 JDK 层面真正意义上的反对了基于事件的异步编程范式,补救了 Future 的缺点。 在咱们的日常优化中,最罕用伎俩便是多线程并行执行。这时候就会波及到 CompletableFuture 的应用。 常见应用形式上面举例一个常见场景。 如果咱们有两个 RPC 近程调用服务,咱们须要获取两个 RPC 的后果后,再进行后续逻辑解决。 public static void main(String[] args) { // 工作 A,耗时 2 秒 int resultA = compute(1); // 工作 B,耗时 2 秒 int resultB = compute(2); // 后续业务逻辑解决 System.out.println(resultA + resultB);}能够预估到,串行执行起码耗时 4 秒,并且 B 工作并不依赖 A 工作后果。 对于这种场景,咱们通常会抉择并行的形式优化,Demo 代码如下: public static void main(String[] args) { // 仅简略举例,在生产代码中可别这么写! // 统计耗时的函数 time(() -> { CompletableFuture<Integer> result = Stream.of(1, 2) // 创立异步工作 .map(x -> CompletableFuture.supplyAsync(() -> compute(x), executor)) // 聚合 .reduce(CompletableFuture.completedFuture(0), (x, y) -> x.thenCombineAsync(y, Integer::sum, executor)); // 期待后果 try { System.out.println("后果:" + result.get()); } catch (ExecutionException | InterruptedException e) { System.err.println("工作执行异样"); } });}输入:[async-1]: 工作执行开始:1[async-2]: 工作执行开始:2[async-1]: 工作执行实现:1[async-2]: 工作执行实现:2后果:3耗时:2 秒能够看到耗时变成了 2 秒。 ...

February 8, 2023 · 4 min · jiezi

关于java:订单流量录制与回放探索实践

1.背景介绍1.1 得物pandora介绍什么是流量录制回放?流量录制回放是利用端通过挂载注入录制器探针主动注册到服务端造成录制流量回流,将所有内部调用依赖的响应内容(如数据库、分布式缓存、内部服务响应等)进行残缺记录。由平台向回放器散发流量回放指令。其外围价值是通过间接录制生产的实在数据,将生产实在数据转化成可复用、可执行的流量,疾速地在测试环境中进行回放比对接口返回值和两头链路的验证。 得物版本的流量录制回放平台pandora在官网开源版本上进行了很大的拓展,反对了很多官网版本不反对的子调用和入口调用。此外,平台还对得物的中间件进行了诸多适配工作,防止了大量的回放失败乐音。 1.2 市场工具比照目前市场上已知的流量录制回放平台大部分都是在Jvm-Sandbox-Repeater根底上进行二次开发和革新,并且少数都是只反对Java语言。外围原理也都是通过录制线上实在流量而后在测试环境进行回放,验证代码逻辑正确性。 2.实际落地2.1 合作模式在具体的施行层面,目前采纳的是业务测试,平台研发,业务研发三方协同的模式。工作分拆如下图所示。 2.2 阶段利用流量回放在各阶段的现实施行利用: 提测阶段卡点:聚焦外围场景,低成本验证每次提测对于外围场景的影响; 测试回归阶段卡点:全量场景,重点谋求笼罩场景全面性,验证新性能对历史性能的影响; 预发环境回归:目前预发跟生产同库,将来会推动落地基于预发&生产环境的流量回放,尽可能拉近录制时环境和回放时环境的仿真差别,从而升高回放阶段的乐音影响; 在得物的整体QA体系中,流量回放短期聚焦在回归兜底保障上。 2.3 实际落地流量回放的发展自发动后,在本域由摸索尝试阶段逐步过渡到利用场景拓展阶段。 订单流量回放模式 在通过一段时间的摸索,摸索出了一套实用于本域迭代的模式。 Part1、尝试接入团队开始发展流量回放的专项之后,通过调研,选取了40%的服务优先接入。 阶段指标实现30%P0利用top10 接口100%场景笼罩,造成迭代落地品质卡点,实现适用性和提效剖析;减少订单域流量回放人员投入,落地品质卡点,笼罩5%回归场景;实施方案调研利用的个性,尝试接入流量录制回放;梳理服务的P0接口及用例,配置对应的接口及用例标签;用例主动积淀到用例集后,在回归阶段尝试进行流量回放。收益成绩实现30%利用造成落地品质卡点,落地15%用例回归场景,验证计划可行性和易用性,摸索研发测试协同机制。Part2、摸索降级上一阶段破费大量的工夫梳理接口配置标签,用例积淀速度迟缓,并且收益与投入不成正比,因而调整了策略,利用智能化剖析进行提效,疾速积淀用例,扩充用例量及笼罩的接口量。45%业务利用接入并均实现强卡点落地,配合平台侧优化,解决大部分组件适配和应用问题,迭代利用流程以及利用指标剖析机制根本跑顺。 阶段指标利用:接入的利用交由对应的服务负责人,负责对应服务的接口保护经营及积淀、排错剖析;用例:尝试摸索新的用例积淀形式,进一步扩充用例量,减少笼罩的接口量;排错:依据服务的用例量以及接入的工夫,晋升测试排错能力,阶段2完结测开排错达到五五开;2.收益成绩 从开始试点到利用卡点,积淀的用例量也在利用热点流量计划之后开始了降级之路。接入的利用数也超过原定指标达到50%且均实现强卡点落地。利用智能化剖析策略提效成果显著,积淀的用例数成指数型增长,接入利用的P0接口覆盖率达到100%。测试排错能力晋升,每迭代流量回放发现的bug数也在减少,新计划的可施行性和可推广性根本合乎预期。Part3、专项提速在积淀的用例case大量的减少、用例积淀速度提效显著的前提下,流量回放在迭代的利用中发现更多的缺点,布局扩充接入的利用以及笼罩的接口范畴。 阶段指标利用接入:新增40%利用接入,接入利用占比共计90%;排错:晋升测试的排错能力,新版本排错由平台研发转交业务研发,测试开发排错占比五五开;用例量:减速积淀用例量,扩充笼罩的范畴,至多65%的利用实现全量用例积淀;卡点:接入利用达到100%卡点,晋升排错速度,局部利用由生产卡点转为预发卡点;全域接入利用接口维度覆盖率98%以上,接口配置欠缺度98%以上,全量用例门路覆盖率60%以上。收益成绩随着利用的接入,积淀的用例量也在扩充,发现的问题数也在增多。同时也减少覆盖率的指标来掂量流量回放用例笼罩的代码占总代码行的比值。随着对覆盖率的关注,平台采样策略也进行了一个调整,删除所有历史积淀用例,仅积淀新策略施行之后录制的流量。 流量回放接入90%利用,扩充利用接入和case积淀,超预期达成指标,积淀利用Case量是原打算的3倍,此阶段累计发现缺点数占全域流量回放发现的bug数的45%,充沛验证了落地策略的有效性;从阶段3本域发现的缺点统计来看,其中回归类BUG占比38%,发现线上自有/暗藏问题占比8%,迭代过程中代码问题(日志报错)和代码标准类问题占比46%,性能问题占比8%;接口配置欠缺度100%;接口维度覆盖率96.49%;全量用例门路覆盖率79.32%,全量代码覆盖率均匀39.8%;3.总结剖析3.1 问题归类剖析3.1.1 累计发现的缺点分类: 3.1.2 累计发现的缺点起源分类: 3.1.3 典型案例:回放时零碎异样,排查之后定位为NPE类问题,如: response返回的业务字段diff比照不统一,如: 通过对缺点以及缺点起源的归类不难看出: 流量回放发现拦挡的问题近一半都是会引起生产业务报错的,其中包含像金额不对波及资损的问题以及字段传值不对、枚举类型取错等缺点;作为生产公布前的最初阶段的防线之一,充沛展示了流量录制回放作为对测试回归的兜底能力的补充伎俩的重要性。45%左右的问题是手工测试过程中难以发现暗藏比拟深的代码层面问题,例如NPE报错、入参出参字段未序列化等,这些问题如果仅仅通过前端测试或接口测试不看日志不一一比照所有字段势必会将问题带到生产环境,最终影响生产环境的稳定性。6%左右的性能问题,例如存在重复子调用,影响接口RT,如果不在生产公布前发现解决,势必给用户体验带来肯定的挑战。从缺点的起源上看,发现的缺点起源还是集中在我的项目迭代需要和技术优化上,充沛验证了流量回放整体提速后的有效性以及对测试笼罩兜底能力的补充。通过对失败用例的排错剖析教训的累积和分享培训,参加专项的测试团队的整体技术水平通过流量回放专项提速在技术气氛上有显著晋升,造就了多位同学对本身负责模块的实现的代码走读能力,以及深挖缺点的code diff能力。3.2 适用性剖析实用场景实用于返回数据量大、业务流量也很大,以及读取业务占比大的场景,如ToC产品。不实用场景挂载沙箱后开启录制会导致RT霎时飙高,影响生产服务的稳定性。异步场景目前流量回放平台不反对。须要验证数据库的落地,节点的流转的链路测试,须要自动化。先投入能迅速造成能卡点有收益的利用(迭代代码变更绝对少,分层构造比拟好,异步少,写操作少),把看失去的应用成果做进去。 流量回放是否齐全代替手工回归以及自动化? 目前来看,答案是否定的。首先,从沙箱挂载到接口配置再到流量录制这一套流程下来,也须要较长的工夫能力达到较高的用例笼罩,对于一些边界极其场景还是须要手工设计;其次,流量录制回放是后置的回归兜底,更侧重于对历史逻辑的回归验证。 1、接口笼罩不全。迭代需要新接口,未配置关联录制,不在流量回放的录制范畴。 2、全量代码覆盖率不高。接口曾经配置笼罩了,然而因为采样比例小场景极其等起因,接口的分支场景并没有录制到未被笼罩。 3、排错能力的高下影响。接口笼罩了,排错的时候因为新加了子调用,导致失败的用例在排错的时候容易被简略定义为代码变更。 4、平台问题。diff比对异样,显示回放胜利,异步线程的回放是一个待攻克的难点。 3.3 面临的挑战3.3.1 排错的效率录制流量后对流量进行回放,发现回放后果比对失败的很多。通过对失败起因的排查与剖析,有些是代码bug导致的失败,但更多的失败不肯定是代码bug,常见乐音次要蕴含: 代码批改,新增或删除了子调用,导致mock失败平台不反对的子调用,导致失败工夫戳相干的子调用,diff不统一子调用中应用随机参数相干,导致mock匹配不上repeater代码本身缺点业务自增数据差别配置核心数据不统一返回无序元素汇合,造成后果比照误差失败起因很多,真正无效的失败数很少。如此一来,每次回放失败的排查老本就十分高。给业务的推动造成了微小的妨碍。 原版repeater上报的信息不够丰盛,很多状况须要看日志能力排查。目前也没有公开成熟的参考的计划。平台也进行了一些初步的摸索,对回放失败的场景主动进行归类,上报更丰盛的数据信息提供排查指引,帮忙排查人员聚焦定位问题。同时平台也针对一些乐音进行自动识别并在回放时主动过滤降噪。 3.3.2 异步线程录制回放问题入口主线程不等子线程执行完就返回的异步场景,以后的策略是用户可配置对异步子线程的多调用疏忽,只关注主线程的执行状况。这一形式尽管能够晋升这种异步线程场景的回放成功率,然而损失了异步子线程业务逻辑的回归能力。 下面的案例就是因为利用开启了排查提效优先的开关,疏忽了异步子线程的调用,导致diff比对异样,显示回放胜利。该接口在生产公布时报了异样,String类型长度超长被try catch,埋点失落。 4.瞻望&将来布局流量录制回放作为测试畛域的一个新兴事物,在诞生初期就吸引了宽广测试同仁的关注,市场上也有些公司也对此进行了一些实际。咱们对流量录制回放的实际还处于起步的阶段,一些问题的解法也在摸索中 。 预发只读接口非mock回放 在得物预发环境是联通生产环境的数据库和上游利用,因而对于预发进行不mock的回放,特地是对只读接口进行不mock的回放可能在上线前的最初阶段进行一次兜底的回归校验。最难解决的问题是,以后是只读的接口难以保障后续的变更不会引入写操作。在以后阶段凋谢这一性能会引入额定的资损类危险敞口。 对此问题,每次回放前都进行人工校验可能能够解决,然而又引入了极大的效率问题。如何高效地保障在预发/灰度环境进行不mock流量回放不会产生资损危险,是一个值得摸索的问题,须要研发跟测试的共同努力。 计划1-单回放(准实时回放) 计划1落地遇到的问题: 1.配置核心的数据不统一,乐音比拟大 2.时效问题,有10S的时差,一些业务对时效要求比拟高 计划2-双回放(实时回放) 计划2不仅防止了下面计划1的问题,另外后续布局还能够依据覆盖率积淀无效用例集,手工增加异样用例。 ...

February 7, 2023 · 1 min · jiezi

关于java:京东一面MySQL-中的-distinct-和-group-by-哪个效率更高问倒一大遍

先说大抵的论断(残缺论断在文末):在语义雷同,有索引的状况下:group by和distinct都能应用索引,效率雷同。在语义雷同,无索引的状况下:distinct效率高于group by。起因是distinct 和 group by都会进行分组操作,但group by可能会进行排序,触发filesort,导致sql执行效率低下。基于这个论断,你可能会问: 为什么在语义雷同,有索引的状况下,group by和distinct效率雷同?在什么状况下,group by会进行排序操作?带着这两个问题找答案。接下来,咱们先来看一下distinct和group by的根底应用。 举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practicedistinct的应用 distinct用法SELECT DISTINCT columns FROM table_name WHERE where_conditions;例如: mysql> select distinct age from student;+------+| age |+------+| 10 || 12 || 11 || NULL |+------+4 rows in set (0.01 sec)DISTINCT 关键词用于返回惟一不同的值。放在查问语句中的第一个字段前应用,且作用于主句所有列。 如果列具备NULL值,并且对该列应用DISTINCT子句,MySQL将保留一个NULL值,并删除其它的NULL值,因为DISTINCT子句将所有NULL值视为雷同的值。 distinct多列去重distinct多列的去重,则是依据指定的去重的列信息来进行,即只有所有指定的列信息都雷同,才会被认为是反复的信息。 SELECT DISTINCT column1,column2 FROM table_name WHERE where_conditions;mysql> select distinct sex,age from student;+--------+------+| sex | age |+--------+------+| male | 10 || female | 12 || male | 11 || male | NULL || female | 11 |+--------+------+5 rows in set (0.02 sec)group by的应用对于根底去重来说,group by的应用和distinct相似:单列去重语法: ...

February 7, 2023 · 3 min · jiezi

关于java:Java-Agent-踩坑之-appendToSystemClassLoaderSearch-问题

从 Java Agent 报错开始,到 JVM 原理,到 glibc 线程平安,再到 pthread tls,逐渐探索 Java Agent 诡异报错。 背景因为阿里云多个产品都提供了Java Agent 给用户应用,在多个 Java Agent 一起应用的场景下,造成了总体 Java Agent 耗时减少,各个 Agent 各自存储,导致内存占用、资源耗费减少。 所以咱们发动了 one-java-agent 我的项目,可能协同各个 Java Agent;同时也反对更加高效、不便的字节码注入。 其中,各个 Java Agent 作为 one-java-agent 的 plugin,在 premain 阶段是通过多线程启动的形式来加载,从而将启动速度由 O(n) 升高到 O(1),升高了整体 Java Agent 整体的加载工夫。 问题但最近在新版 Agent 验证过程中,one-java-agent 的 premain 阶段,发现有如下报错: 2022-06-16 09:51:09 [oneagent plugin a-java-agent start] ERROR c.a.o.plugin.PluginManagerImpl -start plugin error, name: a-java-agentcom.alibaba.oneagent.plugin.PluginException: start error, agent jar::/path/to/one-java-agent/plugins/a-java-agent/a-java-agent-1.7.0-SNAPSHOT.jar at com.alibaba.oneagent.plugin.TraditionalPlugin.start(TraditionalPlugin.java:113) at com.alibaba.oneagent.plugin.PluginManagerImpl.startOnePlugin(PluginManagerImpl.java:294) at com.alibaba.oneagent.plugin.PluginManagerImpl.access$200(PluginManagerImpl.java:22) at com.alibaba.oneagent.plugin.PluginManagerImpl$2.run(PluginManagerImpl.java:325) at java.lang.Thread.run(Thread.java:750)Caused by: java.lang.InternalError: null at sun.instrument.InstrumentationImpl.appendToClassLoaderSearch0(Native Method) at sun.instrument.InstrumentationImpl.appendToSystemClassLoaderSearch(InstrumentationImpl.java:200) at com.alibaba.oneagent.plugin.TraditionalPlugin.start(TraditionalPlugin.java:100) ... 4 common frames omitted2022-06-16 09:51:09 [oneagent plugin b-java-agent start] ERROR c.a.o.plugin.PluginManagerImpl -start plugin error, name: b-java-agentcom.alibaba.oneagent.plugin.PluginException: start error, agent jar::/path/to/one-java-agent/plugins/b-java-agent/b-java-agent.jar at com.alibaba.oneagent.plugin.TraditionalPlugin.start(TraditionalPlugin.java:113) at com.alibaba.oneagent.plugin.PluginManagerImpl.startOnePlugin(PluginManagerImpl.java:294) at com.alibaba.oneagent.plugin.PluginManagerImpl.access$200(PluginManagerImpl.java:22) at com.alibaba.oneagent.plugin.PluginManagerImpl$2.run(PluginManagerImpl.java:325) at java.lang.Thread.run(Thread.java:855)Caused by: java.lang.IllegalArgumentException: null at sun.instrument.InstrumentationImpl.appendToClassLoaderSearch0(Native Method) at sun.instrument.InstrumentationImpl.appendToSystemClassLoaderSearch(InstrumentationImpl.java:200) at com.alibaba.oneagent.plugin.TraditionalPlugin.start(TraditionalPlugin.java:100) ... 4 common frames omitted相熟 Java Agent 的同学可能能留神到,这是调用 Instrumentation.appendToSystemClassLoaderSearch 报错了。 ...

February 7, 2023 · 2 min · jiezi

关于java:手把手教你集成Google-Authenticator实现多因素认证MFA

近年来层出不穷的安全漏洞表明,单单只通过明码不能保障真正的平安,为了进一步加强身份认证的过程本文在校验用户名和明码之后再减少一层基于Goole Authenticator的认证来进步零碎的安全性。操作形式:1、手机利用商店下载Google Authenticator2、调用LoginService的generateGoogleAuthQRCode办法生成二维码3、应用手机关上Google Authenticator扫描该二维码进行绑定,绑定后会每隔30秒生成一次6位动静验证码4、调用LoginService的login办法进行登录(需传入手机上显示的6位动静验证码,否则校验不被通过)以下分享一次Spring Boot集成Goole Authenticator的案例关键性代码 @Servicepublic class LoginServiceImpl implements LoginService { private final UserService userService; public LoginServiceImpl(UserService userService) { this.userService = userService; } /** * 登录接口 * @param loginParam {"username":"用户名", "password":"明码", "mfaCode":"手机利用Google Authenticator生成的验证码"} * @param servletRequest * @return */ @Override public UserVo login(LoginParam loginParam, HttpServletRequest servletRequest) { // 校验用户名和明码是否匹配 User user = getUserWithValidatePass(loginParam.getUsername(), loginParam.getPassword()); // 验证数据库保留的密钥和输出的验证码是否匹配 boolean verification = GoogleAuthenticatorUtils.verification(user.getGoogleAuthenticatorSecret(), loginParam.getMfaCode()); if (!verification) { throw new BadRequestException("验证码校验失败"); } // 用户信息保留到session中 servletRequest.getSession().setAttribute("user", user); UserVo userVo = new UserVo(); BeanUtils.copyProperties(user, userVo); return userVo; } /** * 生成二维码的Base64编码 * 能够应用手机利用Google Authenticator来扫描二维码进行绑定 * @param username * @param password * @return */ @Override public String generateGoogleAuthQRCode(String username, String password) { // 校验用户名和明码是否匹配 User user = getUserWithValidatePass(username, password); String secretKey; if (StringUtils.isEmpty(user.getGoogleAuthenticatorSecret())) { secretKey = GoogleAuthenticatorUtils.createSecretKey(); }else { secretKey = user.getGoogleAuthenticatorSecret(); } // 生成二维码 String qrStr; try(ByteArrayOutputStream bos = new ByteArrayOutputStream()){ String keyUri = GoogleAuthenticatorUtils.createKeyUri(secretKey, username, "Demo_System"); // Demo_System 服务标识不参加运算,可任意设置 QRCodeUtils.writeToStream(keyUri, bos); qrStr = Base64.encodeBase64String(bos.toByteArray()); }catch (WriterException | IOException e) { throw new ServiceException("生成二维码失败", e); } if (StringUtils.isEmpty(qrStr)) { throw new ServiceException("生成二维码失败"); } user.setGoogleAuthenticatorSecret(secretKey); userService.updateById(user); return "data:image/png;base64," + qrStr; } private User getUserWithValidatePass(String username, String password) { String mismatchTip = "用户名或者明码不正确"; // 依据用户名查问用户信息 User user = userService.getByUsername(username) .orElseThrow(() -> new BadRequestException(mismatchTip)); // 比对明码是否正确 String encryptPassword = SecureUtil.md5(password); if (!encryptPassword.equals(user.getPassword())) { throw new BadRequestException(mismatchTip); } return user; }}GoogleAuthenticatorUtils提供了生成密钥、校验验证码是否和密钥匹配等性能 ...

February 7, 2023 · 7 min · jiezi

关于java:我是如何用CAP和BASE两个基础理论卷死其他组员的

本文内容整顿自博学谷狂野架构师 CAP 定理又被称作布鲁尔定理,是加州大学的计算机科学家布鲁尔在 2000 年提出的一个猜测。2002 年,麻省理工学院的赛斯·吉尔伯特和南希·林奇发表了布鲁尔猜测的证实,使之成为分布式计算畛域公认的一个定理。 布鲁尔在提出CAP猜测时并没有具体定义 Consistency、Availability、Partition Tolerance 这3个词的含意,不同材料的具体定义也有差异,为了更好地解释,上面抉择Robert Greiner的文章《CAP Theorem》作为参考根底。 CAP实践的定义在一个分布式系统(指相互连贯并共享数据的节点的汇合)中,当波及读写操作时,只能保障一致性(Consistence)、可用性(Availability)、分区容错性(PartitionTolerance)三者中的两个,另外一个必须被就义。Consistency、Availability、Partition Tolerance具体解释如下: C - Consistency 一致性A read is guaranteed to return the most recent write for a given client.对某个指定的客户端来说,读操作保障可能返回最新的写操作后果。 这里并不是强调同一时刻领有雷同的数据,对于零碎执行事务来说,在事务执行过程中,零碎其实处于一个不统一的状态,不同的节点的数据并不完全一致。 一致性强调客户端读操作可能获取最新的写操作后果,是因为事务在执行过程中,客户端是无奈读取到未提交的数据的,只有等到事务提交后,客户端能力读取到事务写入的数据,而如果事务失败则会进行回滚,客户端也不会读取到事务两头写入的数据。 A - Availability 可用性A non-failing node will return a reasonable response within a reasonable amount of time (no error or timeout).非故障的节点在正当的工夫内返回正当的响应(不是谬误和超时的响应)。 这里强调的是正当的响应,不能超时,不能出错。留神并没有说“正确”的后果,例如,应该返回 100 但实际上返回了 90,必定是不正确的后果,但能够是一个正当的后果。 P - Partition Tolerance 分区容忍性The system will continue to function when network partitions occur.当呈现网络分区后,零碎可能持续“履行职责”。这里网络分区是指:一个分布式系统外面,节点组成的网络原本应该是连通的。然而可能因为一些故障(节点间网络连接断开、节点宕机),使得有些节点之间不连通了,整个网络就分成了几块区域,数据就分布在了这些不连通的区域中。 ...

February 7, 2023 · 2 min · jiezi

关于java:Quartz-Job-JobDetail

咱们明天剖析Quartz中与作业相干的3个概念: JobJobDetailJobDataMapJob上一篇文章曾经简略做过剖析:Job是工作接口,蕴含一个execute办法。Job与JDK Timer中的TimerTask相似,是提供给利用实现工作逻辑的API。 应用层须要关注的其实就是这个Job接口,作业须要实现的业务逻辑就在Job接口的实现类的execute办法中实现。 JobDetailJobDetail用来持有Job实现类的类名,最终绑定到任务调度器中的不是Job而是JobDetail。JobDetail接口不须要利用关怀、也不须要应用层实现,Quartz提供了一个JobDetail的实现类JobDetailImpl,通过JobBuilder来创立。 JobDetail有一个类型为JobKey的重要属性key,相当于是该工作的键值,JobDetail注册到任务调度器Schedule中的时候,key值不容许反复。整个任务调度过程中,Quartz都是通过Jobkey来惟一辨认JobDetail的。试图将反复键值的JobDetail注册到任务调度器中而不指定笼罩的话,是不被容许的。 JobKey能够通过JobBuiler的withIdentity办法指定,该办法接管name或name+group参数,从而惟一确定一个工作JobDetail。 如果在JobDetail创立过程中不指定JobKey的话,Quartz会通过UUID的形式为该工作生成一个惟一的key值。 所以,同一个Job实现类(也就是同一个工作),能够通过不同的JobKey值注册到任务调度器中、绑定不同的触发器执行! Job的调度形式Quartz的工作执行线程在调度Job工作的时候,是通过JobDetail持有的Job实现类的类名调用newInstance办法创立新的对象来实现的: JobDetailImpl为什么会持有Job实现类的类名、而不是间接持有Job对象、通过该对象间接执行工作? 集体认为这么做的目标之一是为了实现多线程任务调度过程中Job的线程安全性。因为如果间接持有Job实现类的对象的话,就意味着每次任务调度器触发并执行该工作的时候,都是通过雷同的Job实现类的对象来执行工作的,则Job实现类的状态肯定是当前任务执行实现之后的状态,这样的话就要求客户端程序员务必关注对Job实现类状态的解决,稍有不慎可能就会导致意想不到的后果。 每一个工作线程都是通过新的工作对象来执行工作,也能够防止多线程任务调度过程中的工作安全性问题。 这种实现形式其实也要求咱们的Job实现类必须提供无参结构器,否则Quartz在创立工作对象的时候会抛出SchedulerException异样。 JobDataMapJobDataMap是不限个数的一组数据集,能够通过JobDataMap在创立工作的时候传递参数给该工作、在工作执行的时候能够获取到该数据集。 比方咱们后面说过,一个Job实现类能够通过创立多个不同的JobDetail(通过不同的JobKey辨别)绑定到任务调度器schedule中,这种状况下能够就通过JobDataMap传递不同的参数给JobDetail从而辨别他们的行为。Quartz官网中举例说明的“SalesReportForJoe”、“SalesReportForMike”就是这个意思。 举例: public class HelloJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { log.info("I dont know want should i do ..."+Thread.currentThread().getId()+ " and I am :" + this + " and jobname="+jobExecutionContext.getJobDetail().getKey()); JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap(); if(jobDataMap!=null){ log.info("JD:"+jobDataMap.get("JD")); } } public static void main(String[] args) { log.info("I am running..."); JobDetail jobDetail = newJob(HelloJob.class) .withDescription("This is my first quartz job") .usingJobData("JD","This is JD") .withIdentity("MyJob") .build(); JobDetail jobDetail1 = newJob(HelloJob.class) .withDescription("This is my first quartz job") .usingJobData("JD","This is JD1") .withIdentity("MyJob1") .build(); Trigger trigger = newTrigger() .withIdentity("myTriggger","MyGroup") .startNow() .withSchedule(simpleSchedule() .withIntervalInSeconds(20) .repeatForever()) .build(); Trigger trigger1 = newTrigger() .withIdentity("myTriggger1","MyGroup1") .startNow() .withSchedule(simpleSchedule() .withIntervalInSeconds(20) .repeatForever()) .build(); try { Scheduler sche = new StdSchedulerFactory().getScheduler(); sche.scheduleJob(jobDetail,trigger); sche.scheduleJob(jobDetail1,trigger1); sche.start(); }catch(Exception e){ e.printStackTrace(); } log.info("i am done"); }}创立HelloJob实现Job接口的execute办法,该办法只是打印以后作业的线程id、以后Job对象、以及获取到的JobDataMap。 ...

February 1, 2023 · 2 min · jiezi

关于java:开发小白的高光逆袭竟然能一眼断定生产环境接口响应时间慢是磁盘性能问题引起的

01 问题背景某接口在测试环境耗时600~700ms左右,但在生产环境耗时在1.4s以上,接口实现逻辑蕴含数据库操作、文件操作、上游微服务调用和其余业务逻辑计算代码,该如何疾速排查? 团队里的其余开发同学还在慌手慌脚地按以下这些惯例步骤排查: 确定问题源:剖析日志、代码等数据信息,确定接口是因为哪一部分逻辑代码引起的异样耗时依据问题源,逐渐排查是否是资源故障:查看磁盘、CPU、内存的利用率,看是否有任何资源被适度应用;查看磁盘是否有性能瓶颈;查看网络利用率,是否存在网络拥挤。查看硬件......这是采纳排除法倒推,依赖教训,排查工夫因集体的能力而异。另外查看某些指标还须要和运维合作,而且指标也是通过工夫范畴去进行历史搜寻,看个大略值,可能存在误差。 02 开发小白高光逆袭,一眼定位根因就像犯罪现场的监控视频能让警察一眼看到真正的凶手是谁一样,有一个机智的开发同学借助Kindling程序摄像头精准还原接口执行现场的能力,一眼定位根因。 他用程序摄像头捕获了生产环境该接口的执行Trace,从Span剖析上看,只看到文件操作占了大量耗时,无奈确定其中起因,所以像Skywalking这种常见的Trace追踪工具,只能排查到这一步,无奈晓得在1.47s异样耗时内,程序做了哪些事件。而Kindling还能看到更底层的“接口执行现场”信息:生产环境:该问题接口Trace中的Span剖析当他持续点击span,看到Trace执行主线程的事件剖析,他发现了问题苗头:生产环境:该问题接口Trace剖析如上图,该Trace的工作主线程,消耗了大量的工夫在做fileopen事件,实践上,fileopen(即操作系统关上存储在磁盘上的指标文件)只需几个ms足矣。次要耗时应该只是cpu做的running事件,即零碎将文件数据从内核态拷贝到用户态。于是,他再次用程序摄像头捕获了测试环境下该接口的Trace:测试环境:该问题接口Trace剖析不言而喻,测试环境fileopen事件耗时失常,所以接口响应工夫失常。由此他判定该接口响应工夫在生产环境异常是因为磁盘性能问题导致的。 03 排障总结接下来的思路就简略分明了,查看磁盘,最初发现该磁盘损坏,替换后恢复正常。当大家遇到云服务器磁盘性能呈现问题时,能够通过下列办法解决: 优化磁盘读写性能:如果发现磁盘读写性能较差,能够思考将文件系统格式化为更高效的格局,并且启用磁盘缓存。更换磁盘:如果磁盘读写性能的确过差,能够思考更换磁盘,以便取得更好的性能。更改云服务器硬件配置:如果云服务器磁盘性能不够,能够思考更改云服务器硬件配置,以进步云服务器磁盘性能。优化系统配置:能够思考批改系统配置,以便优化磁盘读写性能,如更改文件系统缓存大小等。查看磁盘状态:如果磁盘性能问题无奈解决,能够思考查看磁盘状态,以便找出磁盘故障。其余共事依照惯例排障思路,最初也能定位到是磁盘性能的问题,但期间投入的工夫是不可控的,下文是对于应用Kindling程序摄像头技术排障的介绍,我认为它是颠覆性的工具,有趣味的同学欢送持续往下看。 04 附录 - Kindling程序摄像头技术介绍kindling程序摄像头精准还原现场,10分钟黄金时间排障很多公司违心花高薪招聘资深开发,有很大一部分起因是花钱买他的教训,借助专家能力保障系统的稳定性和性能。但很多一般开发者从业教训深浅不一,咱们不是专家,难道咱们就只能吭哧吭哧敲CURD代码,一遇到生产故障就毫无脉络,只能找大佬吗?kindling程序摄像头的初衷就是,以标准化步骤,帮忙所有开发实现分钟级定位全资源品种故障根因,升高专家门槛。 以标准化步骤找:通过Trace零碎,联合工夫点,找出相干可能存在问题的要害Trace查:通过要害Trace,查问其对应的Span信息剖析:剖析Span信息中的何种指标与预期不符其实这个观点一开始我是回绝的,故障千奇百怪,怎么可能通过3条规范步骤就排查出根因?这牛是不是吹得有点过了?然而,通过屡次试验重复论证,我逐步意识到Kindling敢这么“吹牛”的起因:生产环境是黑盒子,大多数状况下,咱们都是从故障后果反推过程而后排除各种可能性,最初失去根因。而Kindling程序摄像头以零碎内核级别线程事件剖析的角度,精准还原程序执行现场。它让咱们从过程剖析根因,“雁过留痕”,所有故障都会在程序执行过程中产生和失常状况下不同的痕迹,这3条规范步骤就是带咱们找到这个痕迹,进而定位根因。 分钟级别定位:行业内排障时效性指标,1分钟发现-5分钟响应-10复原没有Kindling,我照样还是能排查出故障根因,话虽如此,条条路线通罗马,但生产环境排障时效性是要害。没有任何人、任何排障工具能保障1-5-10的时效性指标。在以往排障过程中,咱们须要在数据库、日志、终端、apm等排查工具来回切换,和运维合作,从海量的数据中筛选组织出无效的信息。这一过程是最耗时、最依赖集体教训的。而恰好Kindling的程序摄像头技术就是帮开发&运维实现了这一过程,它基于eBPF技术交融了Tracing,logging,metrics。换句话说,它曾经把该接口相干的所有数据(比方,mysql、redis等网络申请的连贯信息和报文信息、日志、堆栈、锁信息、文件IO信息等等)都筛选捕获进去,附着在对应的线程事件上。如下图是数据库网络连接事件样例,点击事件即可查看具体信息:基于此,对于问题咱们不会再毫无脉络、无从下手,也不再须要去看这个查那个,浪费时间,咱们只须要查看哪个指标异于预期,进而剖析根因。 定位全资源品种故障根因正如上一点提到的,Kindling程序摄像头技术交融了很多指标数据,后续也会持续把接口执行时刻的网络指标(比方带宽、rtt等),CPU利用率,磁盘性能指标、内存利用率等等信息捕获交融到Trace剖析中,以实现全资源品种故障根因定位。

February 1, 2023 · 1 min · jiezi

关于java:分享会上狂吹MySQL的4大索引结构没想到大家的鉴赏能力如此的

文章内容整顿自【博学谷狂野架构师】索引(index)是帮忙MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还保护着满足 特定查找算法的数据结构,这些数据结构以某种形式援用(指向)数据, 这样就能够在这些数据结构 上实现高级查找算法,这种数据结构就是索引。 优缺点: 长处: 进步数据检索效率,升高数据库的IO老本通过索引列对数据进行排序,升高数据排序的老本,升高CPU的耗费毛病: 索引列也是要占用空间的索引大大提高了查问效率,但升高了更新的速度,比方 INSERT、UPDATE、DELETE索引构造索引构造形容B+Tree最常见的索引类型,大部分引擎都反对B+树索引Hash底层数据结构是用哈希表实现,只有准确匹配索引列的查问才无效,不反对范畴查问R-Tree(空间索引)空间索引是 MyISAM 引擎的一个非凡索引类型,次要用于天文空间数据类型,通常应用较少Full-Text(全文索引)是一种通过建设倒排索引,疾速匹配文档的形式,相似于 Lucene, Solr, ES上述是MySQL中所反对的所有的索引构造,接下来,咱们再来看看不同的存储引擎对于索引构造的反对 状况。索引InnoDBMyISAMMemoryB+Tree索引反对反对反对Hash索引不反对不反对反对R-Tree索引不反对反对不反对Full-text5.6版本之后反对反对不反对留神: 咱们平时所说的索引,如果没有特地指明,都是指B+树结构组织的索引。二叉树如果说MySQL的索引构造采纳二叉树的数据结构,比拟现实的构造如下: 如果主键是程序插入的,则会造成一个单向链表,构造如下: 所以,如果抉择二叉树作为索引构造,会存在以下毛病: 程序插入时,会造成一个链表,查问性能大大降低。大数据量状况下,层级较深,检索速度慢。此时大家可能会想到,咱们能够抉择红黑树,红黑树是一颗自均衡二叉树,那这样即便是程序插入数据,最终造成的数据结构也是一颗均衡的二叉树,构造如下: 然而,即使如此,因为红黑树也是一颗二叉树,所以也会存在一个毛病: 大数据量状况下,层级较深,检索速度慢。所以,在MySQL的索引构造中,并没有抉择二叉树或者红黑树,而抉择的是B+Tree,那么什么是B+Tree呢?在详解B+Tree之前,先来介绍一个B-Tree。 B-TreeB-Tree,B树是一种多路衡查找树,绝对于二叉树,B树每个节点能够有多个分支,即多叉。以一颗最大度数(max-degree)为5(5阶)的b-tree为例,那这个B树每个节点最多存储4个key,5个指针: 树的度数指的是一个节点的子节点个数。咱们能够通过一个数据结构可视化的网站来简略演示一下。B-Tree Visualization (usfca.edu)(opens new window) 插入一组数据: 100 65 169 368 900 556 780 35 215 1200 234 888 158 90 1000 88 120 268 250 。而后察看一些数据插入过程中,节点的变动状况。 特点: 5阶的B树,每一个节点最多存储4个key,对应5个指针。一旦节点存储的key数量达到5,就会裂变,两头元素向上决裂。在B树中,非叶子节点和叶子节点都会存放数据。B+TreeB+Tree是B-Tree的变种,咱们以一颗最大度数(max-degree)为4(4阶)的b+tree为例,来看一下其构造示意图: 咱们能够看到,两局部: 绿色框框起来的局部,是索引局部,仅仅起到索引数据的作用,不存储数据。红色框框起来的局部,是数据存储局部,在其叶子节点中要存储具体的数据。咱们能够通过一个数据结构可视化的网站来简略演示一下。B+ Tree Visualization (usfca.edu)(opens new window) 插入一组数据: 100 65 169 368 900 556 780 35 215 1200 234 888 158 90 1000 88 120 268 250 。而后察看一些数据插入过程中,节点的变动状况。 ...

February 1, 2023 · 1 min · jiezi

关于java:复工第一天请马上卸载这个恶心的软件

大家好,我是栈长。 停工第一天:倡议大家马上卸载 Notepad++ 这个恶心的软件!!! 大家都晓得,Notepad++ 是 Windows 零碎上用的比拟多的一款编辑器,之前就频频作妖被宽广程序员抵制,不晓得哪里来的底气,最近 Notepad++ 又开始作妖了: 不批准 Notepad++ 的政治观点,就往源代码增加随机字符??好家伙,私货还能这么夹带??这骚操作,把我整不会了,这尼玛也太恶心了吧。。 Notepad++ 这一款编辑器,原本因为其开源、简略、好用,失去泛滥程序员的青睐。当初倒好,有点开始飘了,不好好晋升用户体验,非得搞这些恶心的事件,这么瞎搞上来,话说大伙还敢用吗? 比 Notepad++ 好用的编辑器多得去了,大家不必惯着它,比方栈开举荐以下几款好用的编辑器。 Notepad--Notepad-- 是一款国产开源的文本编辑器,这款软件的指标是要替换 Notepad++,不仅开源、收费、简洁,还能反对跨平台,软件目前反对在 Windows、macOS 以及 Linux 操作系统上装置应用,无任何广告,也无任何性能限度。 Notepad-- 可代替 Notepad++ 等第三方编辑器软件,不仅界面非常简洁,性能上也十分的实用,举荐大家装置应用。 Sublime TextSublime Text 也是一款老牌的代码编辑器,也反对跨平台,性能、应用体验也比 Notepad++ 丰盛得多,最大的亮点就是反对丰盛的插件。 Sublime Text 3 开始免费了,不过貌似不是强制免费的,能够始终进行试用。 VS CodeVS Code 被称为宇宙最弱小的编辑器,VS Code 全称是 Visual Studio Code,是微软开发的一款开源、收费、跨平台、高性能、轻量级的代码编辑器。 最牛逼的代码编辑器,没有之一? UltraEditUltraEdit 是一款功能强大的老牌文本编辑器,也是应用最宽泛的编辑器之一,它能够编辑文本、十六进制、ASCII 码等,解决文本极快,性能真的十分弱小。 栈长工作时,就有大佬在用这款编辑器了,性能是真心弱小,毛病就是免费。 Notepad++ 增加随机字符真的无比恶心,所以,真的不倡议大家应用了。。 对于 Windows 平台编辑器 Notepad++ 的代替,大家还有别的举荐么,欢送留言分享~ 近期热文举荐: 1.1,000+ 道 Java面试题及答案整顿(2022最新版) ...

January 31, 2023 · 1 min · jiezi

关于java:为什么大家都说-SELECT-效率低

无论在工作还是面试中,对于SQL中不要用“SELECT *”,都是大家听烂了的问题,虽说听烂了,但广泛了解还是在很浅的层面,并没有多少人去追本溯源,探索其原理。 效率低的起因先看一下最新《阿里java开发手册(泰山版)》中 MySQL 局部形容: 【强制】在表查问中,一律不要应用 * 作为查问的字段列表,须要哪些字段必须明确写明。阐明: 减少查问分析器解析老本。增减字段容易与 resultMap 配置不统一。无用字段减少网络 耗费,尤其是 text 类型的字段。开发手册中比拟概括的提到了几点起因,让咱们深刻一些看看: 1. 不须要的列会减少数据传输工夫和网络开销 用“SELECT * ”数据库须要解析更多的对象、字段、权限、属性等相干内容,在 SQL 语句简单,硬解析较多的状况下,会对数据库造成惨重的累赘。增大网络开销;* 有时会误带上如log、IconMD5之类的无用且大文本字段,数据传输size会几何增涨。如果DB和应用程序不在同一台机器,这种开销非常明显即便 mysql 服务器和客户端是在同一台机器上,应用的协定还是 tcp,通信也是须要额定的工夫。2. 对于无用的大字段,如 varchar、blob、text,会减少 io 操作 精确来说,长度超过 728 字节的时候,会先把超出的数据序列化到另外一个中央,因而读取这条记录会减少一次 io 操作。(MySQL InnoDB) 3. 失去MySQL优化器“笼罩索引”策略优化的可能性 SELECT * 杜绝了笼罩索引的可能性,而基于MySQL优化器的“笼罩索引”策略又是速度极快,效率极高,业界极为举荐的查问优化形式。 例如,有一个表为t(a,b,c,d,e,f),其中,a为主键,b列有索引。 那么,在磁盘上有两棵 B+ 树,即汇集索引和辅助索引(包含单列索引、联结索引),别离保留(a,b,c,d,e,f)和(a,b),如果查问条件中where条件能够通过b列的索引过滤掉一部分记录,查问就会先走辅助索引,如果用户只须要a列和b列的数据,间接通过辅助索引就能够晓得用户查问的数据。 如果用户应用select *,获取了不须要的数据,则首先通过辅助索引过滤数据,而后再通过汇集索引获取所有的列,这就多了一次b+树查问,速度必然会慢很多。 因为辅助索引的数据比汇集索引少很多,很多状况下,通过辅助索引进行笼罩索引(通过索引就能获取用户须要的所有列),都不须要读磁盘,间接从内存取,而汇集索引很可能数据在磁盘(外存)中(取决于buffer pool的大小和命中率),这种状况下,一个是内存读,一个是磁盘读,速度差别就很显著了,简直是数量级的差别。 索引常识延申下面提到了辅助索引,在MySQL中辅助索引包含单列索引、联结索引(多列联结),单列索引就不再赘述了,这里提一下联结索引的作用。 联结索引 (a,b,c) 联结索引 (a,b,c) 理论建设了 (a)、(a,b)、(a,b,c) 三个索引 咱们能够将组合索引想成书的一级目录、二级目录、三级目录,如index(a,b,c),相当于a是一级目录,b是一级目录下的二级目录,c是二级目录下的三级目录。要应用某一目录,必须先应用其下级目录,一级目录除外。 联结索引的劣势1) 缩小开销建一个联结索引 (a,b,c) ,理论相当于建了 (a)、(a,b)、(a,b,c) 三个索引。每多一个索引,都会减少写操作的开销和磁盘空间的开销。对于大量数据的表,应用联结索引会大大的缩小开销! 2)笼罩索引对联结索引 (a,b,c),如果有如下 sql 的, SELECT a,b,c from table where a='xx' and b = 'xx';那么 MySQL 能够间接通过遍历索引获得数据,而无需回表,这缩小了很多的随机 io 操作。缩小 io 操作,特地是随机 io 其实是 DBA 次要的优化策略。所以,在真正的理论利用中,笼罩索引是次要的晋升性能的优化伎俩之一。 ...

January 31, 2023 · 1 min · jiezi

关于java:在spring-boot3中使用native-image

简介在之前spring boot3文章中咱们介绍了,spring boot3的一个重要个性就是反对把spring boot3的利用编译成为GraalVM的Native Image。 明天咱们用具体的例子来给大家演示一下如何正确的将spring boot3的利用编译成为native image。 装置GraalVM如果要把spring boot3的app编译成为native利用,须要GraalVM的反对。 什么是GraalVM呢? 从名字就可以看进去GraalVM是一个虚拟机,它的次要指标就是晋升java应用程序的性能,并且耗费更少的资源。 它在java HotSpot JVM的根底上增加了JIT编译器和AOT来实现将利用编译成为本地可执行文件。除了java之外,GraalVM还反对JavaScript、Ruby、Python等多种编程语言。 所以,为什么要用GraalVM呢?一个字:快。 装置GraalVM也比较简单,咱们进入它的官网下载页面下载对应的版本即可:https://www.oracle.com/downlo...。 GraalVM跟JDK一样也有两个版本,社区版和企业版本,大家能够依据须要自行抉择。 要留神的是spring boot3须要GraalVM 22.3以上的版本反对,大家可不要下载错了。下载实现之后,咱们能够像失常装置JDK一样来装置GraalVM,这里以mac为例,如果咱们装置的目录是/Library/Java/JavaVirtualMachines/graalvm-ee-java17-22.3.0,那么咱们须要配置对应的JAVA_HOME和PATH环境变量如下: export PATH=/Library/Java/JavaVirtualMachines/graalvm-ee-java17-22.3.0/Contents/Home/bin:$PATH export JAVA_HOME=/Library/Java/JavaVirtualMachines/graalvm-ee-java17-22.3.0/Contents/HomePATH中有一个十分重要的命令叫做gu,如果不增加PATH,那么在应用中就可能遇到上面的异样: 'gu' tool wasn't found. This probably means that JDK at isn't a GraalVM distribution.装置结束之后能够通过上面的命令来进行验证: java -versionjava version "17.0.5" 2022-10-18 LTSJava(TM) SE Runtime Environment GraalVM EE 22.3.0 (build 17.0.5+9-LTS-jvmci-22.3-b07)Java HotSpot(TM) 64-Bit Server VM GraalVM EE 22.3.0 (build 17.0.5+9-LTS-jvmci-22.3-b07, mixed mode, sharing)如果是在mac环境下,还须要执行上面的命令来解除对graalvm的隔离限度: sudo xattr -r -d com.apple.quarantine /path/to/graalvm否则在应用中就会遇到上面的问题: ...

January 30, 2023 · 4 min · jiezi

关于java:Object中的wait和notify方法详解

咱们从一个IllegalMonitorStateException的解决来开始咱们的解说。小A写的代码抛出了 java.lang.IllegalMonitorStateException 异样信息。 public class WaitDemo { public static void main(String[] args) throws Exception { Object o = new Object(); o.wait(); //业务逻辑代码 }}小A通过查看源码,确认了抛出IllegalMonitorStateException 异样是因为调用wait办法的时以后线程没有获取到调用对象的锁。 Throws:IllegalMonitorStateException – if the current thread is not the owner of the object's monitor.依据谬误起因,将代码改成如下,业务代码失常运行。 public class WaitDemo { public static void main(String[] args) throws Exception { Object o = new Object(); synchronized (o){ o.wait(); } //业务逻辑代码 }}通过这个异样的解决小A意识到本人对于wait和notify办法不足足够的理解,导致了异样的产生,上面咱们一起来学习下wait和notify办法 wait和notify办法介绍wait和notify是Object类中定义的办法。调用这两个办法的前提条件:以后线程领有调用者的锁。 wait办法有好几个重载办法,但最终都调用了如下的wait本地办法。调用wait办法后,以后线程会进入waiting状态直到其余线程调用此对象的notify、notifyAll办法或者指定的等待时间过来。 public final native void wait(long timeout) throws InterruptedException;notify和notifyAll办法,两者的区别是notify办法唤醒一个期待在调用对象上的线程,notifyAll办法唤醒所有的期待在调用对象上的线程。 ...

January 30, 2023 · 1 min · jiezi

关于java:文件上传组件X-Spring-File-Storag使用

X Spring File Storage能够简化上传文件代码,能够配置多上传平台。须要引入的依赖<!-- spring-file-storage 必须要引入 --><dependency> <groupId>cn.xuyanwu</groupId> <artifactId>spring-file-storage</artifactId> <version>0.7.0</version></dependency> <!-- 华为云 OBS 不应用的状况下能够不引入 --><dependency> <groupId>com.huaweicloud</groupId> <artifactId>esdk-obs-java</artifactId> <version>3.22.3.1</version></dependency>配置文件spring: file-storage: #文件存储配置 default-platform: local-1 #默认应用的存储平台, thumbnail-suffix: ".min.jpg" #缩略图后缀,例如【.min.jpg】【.png】 local: # 本地存储(不举荐应用),不应用的状况下能够不写 - platform: local-1 # 存储平台标识 enable-storage: true #启用存储 enable-access: true #启用拜访(线上请应用 Nginx 配置,效率更高) domain: "http://127.0.0.1:9966/test/file/" # 拜访域名,例如:“http://127.0.0.1:8030/test/file/”,留神前面要和 path-patterns 保持一致,“/”结尾,本地存储倡议应用相对路径(/test/file/),不便前期更换域名 base-path: E:/Temp/test/ # 存储地址 path-patterns: /test/file/** # 拜访门路,开启 enable-access 后,通过此门路能够拜访到上传的文件 huawei-obs: # 华为云 OBS ,不应用的状况下能够不写 - platform: huawei-obs-1 # 存储平台标识 enable-storage: true # 启用存储 access-key: ak secret-key: sk end-point: ep bucket-name: bn domain: / # 拜访域名,留神“/”结尾,例如:http://abc.obs.com/ base-path: / # 根底门路留神配置每个平台后面都有个-号,通过以下形式能够配置多个local: - platform: local-1 # 存储平台标识 enable-storage: true enable-access: true domain: "" base-path: D:/Temp/test/ path-patterns: /test/file/** - platform: local-2 # 存储平台标识,留神这里不能反复 enable-storage: true enable-access: true domain: "" base-path: D:/Temp/test2/ path-patterns: /test2/file/**启动类调整@EnableFileStorage@SpringBootApplicationpublic class SpringTestApplication{ public static void main(String[] args) { SpringApplication.run(SpringTestApplication.class, args); }}简略应用@RestControllerpublic class FileDetailController { @Autowired private FileStorageService fileStorageService;//注入实列 /** * 上传文件,胜利返回文件 url */ @PostMapping("/upload") public String upload(MultipartFile file) { FileInfo fileInfo = fileStorageService.of(file) .setPath("upload/") //保留到相对路径下,为了方便管理,不须要能够不写 .setObjectId("0") //关联对象id,为了方便管理,不须要能够不写 .setObjectType("0") //关联对象类型,为了方便管理,不须要能够不写 .putAttr("role","admin") //保留一些属性,能够在切面、保留上传记录、自定义存储平台等中央获取应用,不须要能够不写 .setPlatform("huawei-obs-1") //应用指定的存储平台,不写则应用默认存储平台 .upload(); //将文件上传到对应中央 return fileInfo == null ? "上传失败!" : fileInfo.getUrl(); }}X Spring File Storage上传不仅反对本地和华为云obs上传,还反对阿里云OSS,腾讯云 COS,百度云BOS等更多平台,还有对于X Spring File Storage的更多上传,查问,删除文件等办法详见官网:链接

January 30, 2023 · 1 min · jiezi

关于java:Whats-new-in-Dubbo-315-and-320beta4

在 1 月 27 日,新年伊始,Dubbo 3.1.5 和 3.2.0-beta.4 正式通过投票公布。本文将介绍公布的变动一览。 Dubbo 3.1.5 版本是目前 Dubbo 3 的最新稳固版本,咱们倡议所有的用户都降级到最新的稳固版本。Dubbo 3.2.0-beta.4 版本是目前 Dubbo 3 的最新个性版本,包含了如 Spring Boot 3、JDK 17、服务粒度的线程池隔离等新个性的反对,欢送大家尝鲜应用。 Dubbo 3.1.5 新个性Dubbo QoS 反对记录申请的记录,便于进行审计反对在服务映射失败当前定时进行重试,升高因为元数据中心抖动带来的影响反对在初始化 Nacos Client 的时候进行健康检查,如果失败则在肯定次数限度下进行重试,升高因为 Nacos 性能问题带来的稳定性影响反对序列化类查看机制,默认开启日志告警模式Bugfix修复资源加载器的日志级别修复 Dubbo 配置类对 Scope Model 进行懒加载,防止触发非预期的默认模块初始化修复 ReferenceConfig 中获取 ClassLoader 的逻辑修复 Metadata Service 在获取订阅服务列表时呈现 NPE 的问题修复对接 Spring Cloud Rest 模式的时候 Metadata 配置笼罩的问题修复 Spring 懒加载时可能呈现死锁的问题修复端口反复的有效日志修复 Active Limit Filter 不失效的问题修复服务映射时 Nacos CAS 查看写入有效的问题修复 Zookeeper 注册核心对接的利用级服务发现在服务公布的时候呈现单节点服务找不到的问题修复服务映射在抵触当前未期待导致的抵触率高的问题修复利用级服务发现下节点更新失败的问题修复利用级配置笼罩不失效的问题修复在利用级地址刷新之后原 Revision 的元数据无奈获取的问题修复 Zookeeper 注册核心在利用级服务发现下退订阅后无奈重订阅的问题兼容 Nacos 在频繁刷新时最终一致性谬误的问题敞开 Nacos 本地缓存获取的开关修复 Triple 传递大写 Attachment 有效的问题修复 Triple 解决特定类反序列化谬误的问题修复 Protobuf 依赖不存在时抛出非预期异样的问题修复 CountDown 性能有效的问题修复 Triple 在反序列化时类加载器未切换的问题FAQ本次公布中有 5 个提交波及异样日志 FAQ 的欠缺。对于错误码机制请参考官网错误码机制介绍一文。(https://cn.dubbo.apache.org/z...) ...

January 30, 2023 · 2 min · jiezi

关于java:Spring-Boot-的几种统一处理方式

为了程序返回数据敌对,返回给前端的数据信息是可读的,往往会思考将异样进行封装或者组织为结构化返回。 基于 Spring Boot 体系,本来曾经提供了一些形式实现,咱们明天次要聊的也是基于 Spring Boot 去解决上述问题。 @ExceptionHandler@ExceptionHandler 能够作为对立拦挡异样形式,对于指定的异样依照你想的形式自在组装返回的数据信息和构造。自由度很高,这里须要留神的一点,往往大家会在这里就间接通过response对象返回响应后果,从而导致ResponseBodyAdvice、HandlerInterceptor之类的后续解决不再触发。 所以在应用该形式时,尽可能不间接应用response.write形式返回,而是应用对立的数据结构作为解决返回值。 // 举荐 @ResponseStatus(value = HttpStatus.OK) @ExceptionHandler(value = ConstraintViolationException.class) @ResponseBody public Resp<Void> onBadMethodArgumentTypeMismatchException(ConstraintViolationException e) { return Resp.badRequest(e.getConstraintViolations().stream().findFirst().get().getMessage()); }// 不举荐 @ExceptionHandler(Exception.class) public void exception(Exception e, HttpServletResponse response) throws IOException { response.setContentType("application/json;charset=UTF-8"); log.error("零碎异样:", e); response.getWriter().write($.json.toJsonString(Resp.customize(RpcResult.SERVER_ERROR, "服务器异样,请稍后再试")); }ErrorControllerSpring Boot 在产生异样的时候,如果没有异样捕获器存在,会默认调用/error接口(能够通过server.error.path批改),相似写接口一样,对异样进行捕获解决。 该形式优先级上会弱一点,但也是一种好形式,还能够本人实现通过配置形式解决异样,能够参考:Dew。 课外拓展执行优先级阐明1、HandlerInterceptor.preHandle()2、 业务办法3、@ExceptionHandler4、ResponseBodyAdvice.supports()5、ResponseBodyAdvice.beforeBodyWrite()6、HandlerInterceptor.postHandle()7、HandlerInterceptor.afterCompletion()

January 30, 2023 · 1 min · jiezi

关于java:String-为什么是-final

源码现状浏览源码能够发现,String被final润饰,其value变量也被final润饰,这是2件事;首先,String类被final润饰,类不能够被继承。躲避了有人想尝试通过继承重写来毁坏String外部的数据;其次,外部成员变量char value[] 被final润饰,value援用地址不可变; 起因可分为平安1.应用平安,String是最罕用的对象,不可变躲避了间接在堆中间接扭转对象内容,除非被动批改援用地址,否则咱们将String传递进任何办法中,他都不会扭转,避免一不小心就在其余函数内被更改了;2.线程平安,并发应用String时,不须要再去思考他的线程平安问题; 性能1.字符串缓冲池,应用享元模式,缩小String对象的产生,而享元模式的弊病就是对象的外部状态不可变;2.hash算法,因为String初始化就不可变,所以一个String的hashcode是固定的不变的,能够只计算一次,并且String是最适宜作为hashMap中的Key; public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L; /** * Class String is special cased within the Serialization Stream Protocol. * * A String instance is written into an ObjectOutputStream according to * <a href="{@docRoot}/../platform/serialization/spec/output.html"> * Object Serialization Specification, Section 6.2, "Stream Elements"</a> */ private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; /** * Initializes a newly created {@code String} object so that it represents * an empty character sequence. Note that use of this constructor is * unnecessary since Strings are immutable. */ public String() { this.value = "".value; } /** * Initializes a newly created {@code String} object so that it represents * the same sequence of characters as the argument; in other words, the * newly created string is a copy of the argument string. Unless an * explicit copy of {@code original} is needed, use of this constructor is * unnecessary since Strings are immutable. * * @param original * A {@code String} */ public String(String original) { this.value = original.value; this.hash = original.hash; }}

January 29, 2023 · 2 min · jiezi

关于java:Overload-Override

overload 重载示意类的外部,某个办法能够有不同的参数列表,即同名的办法,能够依据参数的不同,抉择多种不同的运行逻辑; void save(String key, String value) {}void save(String key, String value, boolean forceSave) {}int save(String key) { return 0;}override 重写override 示意子类和父类之间的多态的体现,子类的办法名称和参数列表均与父类雷同,则子类在将会对父类的办法可进行重写; 重写时不能抛出比父类还要多的异样,或只能抛出父类异样的子异样,因为重写应失去的异样要比父类的少; 被重写的办法必须为public(定义interface时已默认pulibc,不须要独自润饰)

January 29, 2023 · 1 min · jiezi

关于java:开发常用工具及插件

1.mybatisX 可能东岱连贯到mapper和接口2.jmetter 压测工具3.spotbugs findbugs后续版本4.burp suite 申请拦挡,批改参数工具5.mobaterm xshell ssh连贯工具6.jcomplier 反编译工具7.arthas java 生产环境问题查看工具8.maven helper idea maven插件9.zabbix 主机监控工具10.memcoched 内存数据库11.zipkin 是一款分布式试试数据追踪零碎12.MinIO 分布式对象存储系统13.Nexus 一种近程仓库,也能够叫做私服。14.skywalking 分布式跟踪应用程序性能监控零碎

January 29, 2023 · 1 min · jiezi

关于java:Quarkus入门体验22ms启动一个Web服务

简介Quarkus是相似于Spring Boot的框架,能够不便大家进行Java开发。利用GraalVM的魔力,能更好的适应云原生的场景,极快的启动速度。 创立我的项目在IDEA就间接有创立Quarkus我的项目的初始化工具,间接依据本人须要填好即可,十分不便: 抉择本人须要的一些组件和依赖,我这里只抉择Web Reactive。这跟Spring Boot挺像的。 生成的Java代码就一个文件,很简略玲珑: 编译运行创立胜利后,把编译指标改为11,因为我用的是JDK11。通过mvn clean package尝试打包,下载依赖包。编译胜利后,IDEA反对间接跑Quarkus程序,如下: 启动胜利如下: Quarkus在首页提供了一些开发信息和工具,如下: 拜访服务如下: 间接批改Java代码: @GET@Produces(MediaType.TEXT_PLAIN)public String hello() { return "Hello from pkslow.com";}不必重启就能够失效: 在Docker上运行打包成Native的Docker镜像,命令如下: $ mvn clean package -Dnative -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=docker第一次可能比拟长时间,须要下载镜像。但这种打镜像的办法是把文件放在镜像里面。通过-v的形式来运行。 所以咱们再通过上面命令来生成镜像: $ docker build -f src/main/docker/Dockerfile.native -t pkslow/quarkus-quickstart .Sending build context to Docker daemon 55.41MBStep 1/7 : FROM registry.access.redhat.com/ubi8/ubi-minimal:8.68.6: Pulling from ubi8/ubi-minimala6577091999b: Pull complete Digest: sha256:33931dce809712888d1a8061bfa676963f517daca993984afed3251bc1fb5987Status: Downloaded newer image for registry.access.redhat.com/ubi8/ubi-minimal:8.6 ---> abb1ba1bceabStep 2/7 : WORKDIR /work/ ---> Running in b1f6c5c33919Removing intermediate container b1f6c5c33919 ---> 44961ddcb521Step 3/7 : RUN chown 1001 /work && chmod "g+rwX" /work && chown 1001:root /work ---> Running in e1c1a83e964fRemoving intermediate container e1c1a83e964f ---> 225868ceda2cStep 4/7 : COPY --chown=1001:root target/*-runner /work/application ---> 55b2bba61da1Step 5/7 : EXPOSE 8080 ---> Running in 9b90514423ebRemoving intermediate container 9b90514423eb ---> 00f981b47b0eStep 6/7 : USER 1001 ---> Running in bd5d1b723784Removing intermediate container bd5d1b723784 ---> 14d55159d2d9Step 7/7 : CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] ---> Running in c60a96727644Removing intermediate container c60a96727644 ---> 77fdda464a6aSuccessfully built 77fdda464a6aSuccessfully tagged pkslow/quarkus-quickstart:latest通过Docker来启动: ...

January 29, 2023 · 2 min · jiezi

关于java:GraalVM和Spring-Native尝鲜一步步让Springboot启动飞起来66ms完成启动

简介GraalVM是高性能的JDK,反对Java/Python/JavaScript等语言。它能够让Java变成二进制文件来执行,让程序在任何中央运行更快。这或者是Java与Go的一场和平? 下载安装GraalVM装置GraalVM首先到官网下载,我是间接到GitHub Release Page下载的,请下载对应的零碎包,我下载如下: graalvm-ce-java11-darwin-amd64-22.3.0.tar.gz 下载后解压到某个目录,我的如下: /Users/larry/Software/graalvm-ce-java11-22.3.0 接着测试对应的程序是否能够失常执行,如java --version。在Mac上会报错如下: is damaged and can’t be opened.。 所以须要执行上面语句: $ sudo xattr -r -d com.apple.quarantine /Users/larry/Software/graalvm-ce-java11-22.3.0留神批改对应的目录。 而后就能够执行了: $ ./java --versionopenjdk 11.0.17 2022-10-18OpenJDK Runtime Environment GraalVM CE 22.3.0 (build 11.0.17+8-jvmci-22.3-b08)OpenJDK 64-Bit Server VM GraalVM CE 22.3.0 (build 11.0.17+8-jvmci-22.3-b08, mixed mode, sharing)装置native-image这个工具用来把Java程序转化为本地二进制包,装置如下: $ ./gu install native-imageDownloading: Component catalog from www.graalvm.orgProcessing Component: Native ImageDownloading: Component native-image: Native Image from github.comInstalling new component: Native Image (org.graalvm.native-image, version 22.3.0)配置环境配置环境变量因为这个GraalVM还不够成熟,我不想始终应用,就通过一个命令来切换,配置如下: ...

January 29, 2023 · 2 min · jiezi

关于java:完整的-javakotlin-生成-echarts-图片方法

一. 办法摸索后盾生成图片的办法不多,依据我在网上的查找,有如下几种办法: 前台服务提供接口,联合图表提供的生成图片,申请后返回图片数据。搭建服务,与第一点相似,同样是发送数据。若有配合的前端服务,能够在前端发动下载时生成图片数据,传送回后盾。利用 phantomjs,将图表数据整顿成 html,再联合对应的 javascript 脚本,即可生成图片,这种办法也是本篇文章要介绍的办法。这几种办法我通过比拟,发现还是应用 phantomjs 这种形式劣势比拟大。 第一,它不须要依赖额定的服务。 第二,生成的形式自主可控,你可能灵活处理数据,也可能管制生成图片的品质和大小。 第三,实用的范畴更加宽泛,你不仅能够应用 echarts,也能够应用 highchart,并且包含不限于图表,只有你能找到图片化的办法。 惟一的毛病就是你须要装置它。 二. 灵感起源本篇文章的灵感来源于 ECharts-Java issuse,在寻找后端如何生成前端图表图片办法的过程中,我找到了这个 issuse,并由作者之一的 incandescentxxc 指引,找到了 Snapshot-PhantomJS 这个我的项目。 然而我没有间接应用 Snapshot-PhantomJS,因为它自身源码不多,因而我抉择排汇其中的外围源码,并针对性的进行了缩减与优化。 三. 所需工具Echarts-Java<dependency> <groupId>org.icepear.echarts</groupId> <artifactId>echarts-java</artifactId> <version>1.0.7</version></dependency>该工具的作用有两点: 不便的将数据整顿成 echarts 所需的 option。可能将 option 转化成所须要的 html,可能间接在浏览器中关上看到图表。如果你应用了 slf4j,最好移除掉所有的 org.slf4j,否则会有抵触问题。(这问题我认为不应该呈现,第三方 jar 自身应该思考到这个问题) phantomjs作用有点相当于一个运行在后盾的浏览器,在后盾运行 html 界面。 javascript 脚本var page = require("webpage").create();var system = require("system");var file_type = system.args[1];var delay = system.args[2];var pixel_ratio = system.args[3];var snapshot = " function(){" + " var ele = document.querySelector('div[_echarts_instance_]');" + " var mychart = echarts.getInstanceByDom(ele);" + " return mychart.getDataURL({type:'" + file_type + "', pixelRatio: " + pixel_ratio + ", excludeComponents: ['toolbox']});" + " }";var file_content = system.stdin.read();page.setContent(file_content, "");window.setTimeout(function () { var content = page.evaluateJavaScript(snapshot); phantom.exit();}, delay);该脚本的作用是在外部生成一个 webpage,用来加载你传递的含有图表数据的 html,期待一段时间加载实现后,获取图片的 dataURL,实际上也就是图片的 base64 数据。 ...

January 29, 2023 · 3 min · jiezi

关于java:ORM哪家强javacphppythongo-逐一对比-网友直呼全面客观

前言最近一段时间,我应用golang开发了一个新的ORM库。 为了让这个库更好用,我比拟钻研了各语言的支流ORM库,发现有一些语言的ORM库的确很好用,而有另外一些语言的库那不是个别的难用。 而后我总结了他们呢的一些共性和差别点,于是造成了本文的次要内容。 本文会先阐明什么是SQL编写难题,以及探讨一下 code first 和 database first 的优缺点。而后根据这两个问题的论断去扫视目前支流后端语言java, c#, php, python, go各自的orm库,比照钻研下他们的优缺点。最初给出总结和参考文档。 如果你须要做技术选型,或者做技术钻研,或者相似于我做框架开发,或者单纯地理解各语言的差别,或者就是想吹个牛,倡议保留或珍藏。如果本文所波及到的内容有任何不正确,欢送批评指正。 舒适提醒,本文会有一些戏谑或者调侃成分,并非对某些语言或者语言的使用者有任何歧视意见。如果对你造成了某些挫伤,请多包涵。 什么是SQL编写难题如果你是做web开发,那么必然须要保留数据到数据库,这个时候你必须相熟应用sql语句来读写数据库。 sql自身不难,命令也就那几个,关键字也不算多,然而为什么编写sql会成为难题呢? 比方上面的sql select * from user insert user (name,mobile) values ('tang','18600000000')它有什么难题? 简略的单表操作嘛,一点难题没有,凡是学过点sql的程序员都能写进去,并且保障正确。我预计比例能超过90% 然而,如果你须要写上面的sql呢? SELECT article.*, person.name as person_name FROM article LEFT JOIN person ON person.id=article.person_id WHERE article.type = 0 AND article.age IN (18,20)这个也不简单,就是你在做查问列表的时候,会常常用到的联表查问。你是否还有勇气说,写进去的sql相对正确。我预计比例不超过70% 再略微简单点,如果是上面的sql? SELECT o.*, d.department_name, (SELECT Sum(so.goods_fee) AS task_detail_target_completed_tem FROM sale_order so WHERE so.merchant_id = '356469725829664768' AND so.create_date BETWEEN (20230127) AND (20230212) AND so.delete_state = 2 AND so.department_id = o.department_id ) AS task_detail_target_completed FROM task_detail o LEFT JOIN department d ON d.department_id=o.department_id WHERE o.merchant_id = '356469725829664768' AND o.task_id = '356469725972271104768'这是我我的项目里实在的sql语句,目标是统计出所有部门在某时间段内各自的业绩。逻辑上也不太简单,但你是否还有勇气说,写进去的sql相对正确。我预计比例不超过40% ...

January 29, 2023 · 6 min · jiezi

关于java:CompletableFuture实现异步编排

为什么须要异步执行?场景:电商零碎中获取一个残缺的商品信息可能分为以下几步:①获取商品根本信息 ②获取商品图片信息 ③获取商品促销流动信息 ④获取商品各种类的根本信息 等操作,如果应用串行形式去执行这些操作,假如每个操作执行1s,那么用户看到残缺的商品详情就须要4s的工夫,如果应用并行形式执行这些操作,可能只须要1s就能够实现。所以这就是异步执行的益处。 JDK5的Future接口Future接口用于代表异步计算的后果,通过Future接口提供的办法能够查看异步计算是否执行实现,或者期待执行后果并获取执行后果,同时还能够勾销执行。 列举Future接口的办法: get():获取工作执行后果,如果工作还没实现则会阻塞期待直到工作执行实现。如果工作被勾销则会抛出CancellationException异样,如果工作执行过程产生异样则会抛出ExecutionException异样,如果阻塞期待过程中被中断则会抛出InterruptedException异样。get(long timeout,Timeunit unit):带超时工夫的get()办法,如果阻塞期待过程中超时则会抛出TimeoutException异样。cancel():用于勾销异步工作的执行。如果异步工作曾经实现或者曾经被勾销,或者因为某些起因不能取消,则会返回false。如果工作还没有被执行,则会返回true并且异步工作不会被执行。如果工作曾经开始执行了然而还没有执行实现,若mayInterruptIfRunning为true,则会立刻中断执行工作的线程并返回true,若mayInterruptIfRunning为false,则会返回true且不会中断工作执行线程。isCanceled():判断工作是否被勾销,如果工作在完结(失常执行完结或者执行异样完结)前被勾销则返回true,否则返回false。isDone():判断工作是否曾经实现,如果实现则返回true,否则返回false。须要留神的是:工作执行过程中产生异样、工作被勾销也属于工作已实现,也会返回true。应用Future接口和Callable接口实现异步执行: public static void main(String[] args) { // 疾速创立线程池 ExecutorService executorService = Executors.newFixedThreadPool(4); // 获取商品根本信息(能够应用Lambda表达式简化Callable接口,这里为了便于察看不应用) Future<String> future1 = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { return "获取到商品根本信息"; } }); // 获取商品图片信息 Future<String> future2 = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { return "获取商品图片信息"; } }); // 获取商品促销信息 Future<String> future3 = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { return "获取商品促销信息"; } }); // 获取商品各种类根本信息 Future<String> future4 = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { return "获取商品各种类根本信息"; } }); // 获取后果 try { System.out.println(future1.get()); System.out.println(future2.get()); System.out.println(future3.get()); System.out.println(future4.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }finally { executorService.shutdown(); }}既然Future能够实现异步执行并获取后果,为什么还会须要CompletableFuture?简述一下Future接口的弊病: ...

January 29, 2023 · 7 min · jiezi

关于java:阿里的又一款数据高效同步工具DataX真香

大家好,我是不才陈某~ 有个我的项目的数据量高达五千万,然而因为报表那块数据不太精确,业务库和报表库又是跨库操作,所以并不能应用 SQL 来进行同步。过后的打算是通过 mysqldump 或者存储的形式来进行同步,然而尝试后发现这些计划都不切实际: 举荐Java工程师技术指南:https://github.com/chenjiabin... 关注公众号:码猿技术专栏,回复关键词:1111 获取阿里外部Java性能调优手册! mysqldump:不仅备份须要工夫,同步也须要工夫,而且在备份的过程,可能还会有数据产出(也就是说同步等于没同步) 存储形式:这个效率太慢了,要是数据量少还好,咱们应用这个形式的时候,三个小时才同步两千条数据… 常见数据异构的几款中间件的区别如下: 后面介绍过阿里的Canal:实战!Spring Boot 整合 阿里开源中间件 Canal 实现数据增量同步! 明天介绍另外一款不错的中间件:DataX DataX 简介DataX 是阿里云 DataWorks 数据集成 的开源版本,次要就是用于实现数据间的离线同步。 DataX 致力于实现包含关系型数据库(MySQL、Oracle 等)、HDFS、Hive、ODPS、HBase、FTP 等 各种异构数据源(即不同的数据库) 间稳固高效的数据同步性能。 为了 解决异构数据源同步问题,DataX 将简单的网状同步链路变成了星型数据链路 ,DataX 作为两头传输载体负责连贯各种数据源;当须要接入一个新的数据源时,只须要将此数据源对接到 DataX,便能跟已有的数据源作为无缝数据同步。DataX3.0 框架设计DataX 采纳 Framework + Plugin 架构,将数据源读取和写入形象称为 Reader/Writer 插件,纳入到整个同步框架中。 角色作用Reader(采集模块)负责采集数据源的数据,将数据发送给 Framework。Writer(写入模块)负责一直向 Framework 中取数据,并将数据写入到目标端。Framework(中间商)负责连贯 Reader 和 Writer,作为两者的数据传输通道,并解决缓冲,流控,并发,数据转换等核心技术问题。DataX3.0 外围架构DataX 实现单个数据同步的作业,咱们称为 Job,DataX 接管到一个 Job 后,将启动一个过程来实现整个作业同步过程。DataX Job 模块是单个作业的中枢治理节点,承当了数据清理、子工作切分、TaskGroup 治理等性能。 DataX Job 启动后,会依据不同源端的切分策略,将 Job 切分成多个小的 Task (子工作),以便于并发执行。接着 DataX Job 会调用 Scheduler 模块,依据配置的并发数量,将拆分成的 Task 重新组合,组装成 TaskGroup(工作组)每一个 Task 都由 TaskGroup 负责启动,Task 启动后,会固定启动 Reader --> Channel --> Writer 线程来实现工作同步工作。DataX 作业运行启动后,Job 会对 TaskGroup 进行监控操作,期待所有 TaskGroup 实现后,Job 便会胜利退出(异样退出时 值非 0 )DataX 调度过程: ...

January 29, 2023 · 6 min · jiezi

关于java:如何让Java编译器帮你写代码

作者:京东批发 刘世杰 导读 本文联合京东监控埋点场景,对解决样板代码的技术选型计划进行剖析,给出最终解决方案后,联合实践和实际进一步开展。通过关注文中的技术剖析过程和技术场景,读者可播种一种样板代码思维过程和解决思路,并对Java编译器底层有初步理解。 一、背景监控是服务端利用须要具备的一个十分重要的能力,通过监控能够直观的看到外围业务指标、服务运行品质等,而要做到可监控就须要进行相应的监控埋点。大家在埋点过程中常常会编写大量反复代码,虽能实现基本功能,但耗时耗力,不够优雅。依据“DRY(Don't Repeat Yourself)"准则,这是代码中的“坏滋味”,对有代码洁癖的人来讲,这种反复是不可承受的。 那有什么办法解决这种“反复”吗?通过综合调研,基于前端编译器插桩技术,实现了一个埋点组件,通过织入埋点逻辑,让Java 编译器帮咱们写代码。通过一直打磨,曾经被包含京东APP主站服务端在内的很多团队宽泛应用。 本文次要是联合监控埋点这个场景分享一种解决样板化代码的思路,心愿能起到抛砖引玉的作用。上面将从组件介绍、技术选型过程、实现原理及局部源码实现逐渐开展解说。 二、组件介绍京东外部监控零碎叫UMP,与所有的监控零碎一样,外围局部有埋点、上报、剖析整合、报警、看板等等,本文讲的组件次要是为对监控埋点原生能力的加强,提供一种更优雅简洁的实现。 上面先来看下传统硬编码的埋点形式,次要分为创立埋点对象、可用率记录、提交埋点 3 个步骤: 通过上图能够看到,真正的逻辑只有红框中的范畴,为了实现埋点要把这段代码都围绕起来,代码层级变深,可读性差,所有埋点都是这样的样板代码。 上面来看下应用组件后的埋点形式: 通过比照很容易看到,应用组件后的形式只有在办法上加一个注解就能够了,代码可读性有显著的晋升。 组件由埋点封装API和AST操作处理器 2 局部组成。 埋点API封装:在运行时被调用,对原生埋点做了封装和形象,不便使用者进行监控KEY的扩大。 AST操作处理器:在编译期调用,它将依据注解@UMP把埋点封装API依照规定织入办法体内。 (注:联合京东理论业务场景,组件实现了fallback、自定义可用率、重名办法辨别、配套的IDE插件、监控key自定义生成规定等细节性能,因为本文次要是解说底层实现原理,具体性能不在此赘述) 三、技术选型过程通过下面的示例代码,置信很多人感觉这个性能很简略,用 Spring AOP 很快就能搞定了。确实很多团队也是这么做的,不过这个计划并不是那么完满,上面的选型剖析中会有相干的解释,请急躁往下看。如下图,从软件的开发周期来看,可织入埋点的机会次要有 3 个阶段:编译期、编译后和运行期。 3.1 编译前这里的编译期指将Java源文件编译为class字节码的过程。Java编译器提供了基于 JSR 269 标准[1]的注解处理器机制,通过操作AST (形象语法树,Abstract Syntax Tree,下同)实现逻辑的织入。业内有不少基于此机制的利用,比方Lombok 、MapStruct 、JPA 等;此机制的长处是因为在编译期执行,能够将问题前置,没有多余依赖,因而做进去的工具应用起来比拟不便。毛病也很显著,要纯熟操作 AST并不是想的那么简略,不了解前后关联的流程写进去的代码不够稳固,因而要花大量工夫相熟编译器底层原理。当然这个过程对使用者来讲是没有感知的。 3.2 编译后编译后是指编译成 class 字节码之后,通过字节码进行加强的过程。此阶段插桩须要适配不同的构建工具:Maven、Gradle、Ant、Ivy等,也须要应用方减少额定的构建配置,因而存在开发量大和应用不够不便的问题,首先要排除掉此选项。可能只有极少数场景下才会须要在此阶段插桩。 3.3 运行期运行期是指在程序启动后,在运行时进行加强的过程,这个阶段有 3 种形式能够织入逻辑,依照启动程序,能够分为:动态 Agent、AOP 和动静 Agent。 3.3-1 动态 Agent JVM 启动时应用 -javaagent 载入指定 jar 包,调用 MANIFEST.MF 文件里的 Premain-Class 类的 premain 办法触发织入逻辑。是技术中间件最常应用的形式,借助字节码工具实现相干工作。利用此机制的中间件有很多,比方:京东外部的链路监控 pfinder、内部开源的 skywalking 的探针、阿里的 TTL 等等。这种形式长处是整体比拟成熟,毛病次要是兼容性问题,要测试不同的 JDK 版本代价较大,呈现问题只能在线上发现。同时如果不是业余的中间件团队,还是存在肯定的技术门槛,保护老本比拟高; ...

January 29, 2023 · 2 min · jiezi

关于java:线程校验中断刷新

校验以后线程是否中断否则进行刷新refreshThead = new Thread(() -> { logger.info("RMQ对应接口消费者状态刷新..."); while (!Thread.currentThread().isInterrupted()) { try { try { Thread.sleep(1000 * QContext.RMQ_CONSUMER_REFRESH_INTERVAL); } catch (InterruptedException ex) { } if (logger.isDebugEnabled()) { logger.debug("执行RMQ对应接口消费者状态刷新......"); } EsbCacheManager cacheManager = BeanFactoryHelper.getBean("esbCacheManager", EsbCacheManager.class); QContext.rmqConsumerActionIds.forEach((k, v) -> cacheManager.recordActionIdForConsumerOk(v, QContext.RMQ_CONSUMER_TTL)); } catch (Exception e) { logger.error("RMQ对应接口消费者状态刷新出错", e); try { Thread.sleep(10000); } catch (InterruptedException ex) { } } } });校验线程是否中断Thread.currentThread()返回以后线程对象,isInterrupted()校验以后对象是否中断,不中断循环while内容一直得刷新

January 28, 2023 · 1 min · jiezi

关于java:类是如何加载的

在 Java 中,类加载的流程有一个专门的机制叫做“类加载机制”。类加载机制是指一个类在 Java 虚拟机(JVM)中的执行流程,它也是 Java 程序可能失常执行的关键所在,那它的具体执行流程是啥?接下来咱们一起来看。 流程概述在 JVM 中,类加载会经验以下 5 个阶段: 加载阶段(Loading)验证阶段(Verification)筹备阶段(Preparation)解析阶段(Resolution)初始化阶段(Initialization)其中:验证阶段、筹备阶段和解析阶段合起来又称为连贯阶段,所以以上 5 个阶段又能够划分为 3 大类: 加载阶段(Loading)连贯阶段(Linking) 验证阶段(Verification)筹备阶段(Preparation)解析阶段(Resolution)初始化阶段(Initialization)具体分类如下图所示:这 3 大类、5 个流程的具体执行细节是这样的。 1.加载阶段简略来说,加载阶段就是将类文件加载到内存中的过程。在加载阶段,JVM 须要实现以下 3 件事: 通过一个类的全限定名来获取定义此类的二进制字节流;将这个字节流所代表的动态存储构造转化为办法区的运行时数据结构;在内存中生成一个代表这个类的 java.lang.Class 对象,作为办法区这个类的各种数据的拜访入口。 2.连贯阶段连贯阶段又分为:验证阶段(Verification)、筹备阶段(Preparation)和解析阶段(Resolution),具体执行的细节如下。 2.1 验证阶段验证阶段也叫做校验阶段,它次要是用来验证加载到内存中的类是否是平安合规的文件,验证的次要动作大略有以下几个(当然,以下细节如果切实记不住也没关系): 文件格式校验包含常量池中的常量类型、Class 文件的各个局部是否被删除或被追加了其余信息等;元数据校验包含父类正确性校验(查看父类是否有被 final 润饰)、抽象类校验等;字节码校验,此步骤最为要害和简单,次要用于校验程序中的语义是否非法且合乎逻辑;符号援用校验,对类本身以外比方常量池中的各种符号援用的信息进行匹配性校验。 ### 2.2 筹备阶段 筹备阶段就开始给类中的动态变量设置默认值了,留神这里不是给动态变量设置初始值,而是设置默认值,二者还是有很大区别的。 举个例子,比方代码中写的内容是: public static int number = 10;那么此时是给 number 变量设置的 int 值是默认值 0,而非初始值 10。 2.3 解析阶段解析阶段就是将常量池中的符号援用更换成间接援用了,所谓的符号援用是指以一组符号来形容所援用的指标,符号能够是任何模式的字面量,只有应用时能无歧义地定位到指标即可;而间接援用是能够间接指向指标的指针、绝对偏移量或者是一个能间接定位到指标的句柄。符号援用和间接援用有一个重要的区别:应用符号援用时被援用的指标不肯定曾经加载到内存中;而应用间接援用时,援用的指标必然曾经存在虚拟机的内存中了。 3.初始化阶段初始化阶段,Java 虚拟机真正开始执行类中编写的 Java 程序代码,将主导权移交给应用程序。到这一步骤之后,类的加载过程就算正式实现了,此时会给动态变量设置初始值,并执行动态代码块的内容。 总结类加载流程总共分为 3 大类,5 个次要流程: 加载阶段(Loading):将类文件加载到内存。连贯阶段(Linking) 验证阶段(Verification):类文件安全性效验。筹备阶段(Preparation):给动态变量设置默认值。解析阶段(Resolution):将符号援用转换为间接援用。初始化阶段(Initialization):执行动态代码块和给动态变量设置初始值。本文已收录到 Gitee 开源仓库《Java 面试指南》,其中蕴含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、音讯队列等模块。Java 面试有它就够了,点击查看详情:interview: 400+ 道 Java 常见面试题和解析,继续更新中......

January 28, 2023 · 1 min · jiezi

关于java:别再写狗屎代码了推荐这-5-款-IDEA-插件让你的代码质量直接起飞

随着业务的倒退,零碎会越来越宏大,本来简略稳固的性能,可能在一直迭代后复杂度回升,潜在的危险也随之裸露,导致最终服务不稳固,造成业务价值的损失。而为了缩小这种状况,其中一种比拟好的形式就是进步代码品质,比方通过代码审查,从而升高谬误危险,然而,代码审查难度大,代码缺点、破绽不易发现,且审查工作随着代码量减少而减少,审查效率低。 工欲善其事,必先利其器,因而,这篇文章给大家介绍几种查看代码品质的利器,Alibaba Java Coding Guidelines、CheckStyle、PMD、FindBugs、SonarLint,让你在关注代码品质的同时,缩小 code review 的工作量,进步 code review 的效率,并通过代码品质剖析去反向晋升咱们的代码编写能力 一、Alibaba Java Coding Guidelines1、整体介绍:Alibaba Java Coding Guidelines 专一于Java代码标准,目标是让开发者更加不便、疾速标准代码格局。该插件在扫描代码后,将不合乎规约的代码按 Blocker、Critical、Major 三个等级显示进去,并且大部分能够主动修复,它还基于 Inspection 机制提供了实时检测性能,编写代码的同时也能疾速发现问题所在。 阿里巴巴规约扫描包含: OOP规约并发解决管制语句命名规约常量定义正文标准2、装置步骤:File > Settings > Plugins > Marketplace 搜寻 “Alibaba Java Coding Guidelines”,依照提醒进行装置,而后重启即可。 3、应用阐明:3.1、运行形式: (1)能够Tools > 阿里编码规约 > 编码规约扫描 (2)在编辑界面或者我的项目区域点击右键,在右键菜单中选择“编码规约扫描”即可: 3.2、菜单性能: 编码规约扫描:开始扫描代码关上/敞开实时检测性能:实时检测代码,个别机器性能比拟好的话能够开启这项性能切换语言至英文:中英文切换3.3、运行后果: 扫描实现后显示后果如下,咱们能够看到扫描后果次要分为 Blocker(阻挡者)、Critical(重大问题)、Major(次要的)三个大类,它们示意的是问题的重大水平,重大水平由高到低为:Blocker > Critical > Major,至于每一类中都会蕴含什么样的问题,图中的内容曾经阐明了所有。 选中其中的一个问题我的项目,会呈现如下内容(如果以后鼠标点击的是最终项,左边区域显示的是其它的内容,前面会再讲到): (1)指定区域搜寻同一类问题: 当点击③处的按钮时,会弹出如下按钮: 这里抉择扫描区域,来扫描鼠标选中的同类问题。如果依照默认抉择,那么运行后的后果就如下图所示: 这里咱们能够看到,显示了整个Project中的所有该类的问题。 (2)预览具体的不标准代码: 如果点击的是最终的问题点或者问题所在的类文件,那显示的就是如下界面,预览该处不标准的代码。 3.4、工具栏性能介绍: Rerun Inspection:从新运行一次扫描Close:敞开真个AJCG面板Expand All:开展后果的树状构造,整个后果是树状构造的。Collapse All:收起后果的树状构造Go Pre Problem:抉择上一个问题Go Next Problem:抉择下一个问题Help:帮忙Group by Serverity:(不晓得如何形容)Group by derectory:按目录分组/按类名分组间切换Filter resoled items:过滤掉曾经解决的项Autoscroll to Source:主动滚动到源码Export:导出,能够导出为XML和HTML两种格局Edit Settings:编辑设置二、CheckStyle:1、整体介绍:CheckStyle 偏重查看编码格局和代码格调标准,如命名标准、Javadoc正文标准、空格标准、size度量(如过长的办法)、反复代码、多余Imports等,从而无效束缚开发人员更好地遵循代码编写标准。Checkstyle次要是文法层面的代码编写标准的剖析,对bug简直没什么发现能力。 ...

January 28, 2023 · 2 min · jiezi

关于java:Java-缺失的特性扩展方法

什么是扩大办法扩大办法,就是可能向现有类型间接“增加”办法,而无需创立新的派生类型、从新编译或以其余形式批改现有类型。调用扩大办法的时候,与调用在类型中理论定义的办法相比没有显著的差别。 为什么须要扩大办法思考要实现这样的性能:从 Redis 取出蕴含多个商品ID的字符串后(每个商品ID应用英文逗号分隔),先对商品ID进行去重(并可能维持元素的程序),最初再应用英文逗号将各个商品ID进行连贯。 // "123,456,123,789"String str = redisService.get(someKey)传统写法: String itemIdStrs = String.join(",", new LinkedHashSet<>(Arrays.asList(str.split(","))));应用 Stream 写法: String itemIdStrs = Arrays.stream(str.split(",")).distinct().collect(Collectors.joining(","));假如在 Java 中能实现扩大办法,并且咱们为数组增加了扩大办法 toList(将数组变为 List),为 List 增加了扩大办法 toSet(将 List 变为 LinkedHashSet),为 Collection 增加了扩大办法 join(将汇合中元素的字符串模式应用给定的连接符进行连贯),那咱们将能够这样写代码: String itemIdStrs = str.split(",").toList().toSet().join(",");置信此刻你曾经有了为什么须要扩大办法的答案: 能够对现有的类库,进行间接加强,而不是应用工具类相比应用工具类,应用类型自身的办法写代码更晦涩更舒服代码更容易浏览,因为是链式调用,而不是用静态方法套娃在 Java 中怎么实现扩大办法咱们先来问问最近大火的 ChatGPT: 好吧,ChatGPT 认为 Java 外面的扩大办法就是通过工具类提供的静态方法 :)。 所以接下来我将介绍一种全新的黑科技:Manifold 筹备条件Manifold 的原理和 Lombok 是一样的,也是在编译期间通过注解处理器进行解决。所以要在 IDEA 中正确应用 Manifold,须要装置 Manifold IDEA 的插件: 而后再在我的项目 pom 的 maven-compiler-plugin 中退出 annotationProcessorPaths: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <properties> <manifold.version>2022.1.35</manifold.version> </properties> <dependencies> <dependency> <groupId>systems.manifold</groupId> <artifactId>manifold-ext</artifactId> <version>${manifold.version}</version> </dependency> ... </dependencies> <!--Add the -Xplugin:Manifold argument for the javac compiler--> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>8</source> <target>8</target> <encoding>UTF-8</encoding> <compilerArgs> <arg>-Xplugin:Manifold no-bootstrap</arg> </compilerArgs> <annotationProcessorPaths> <path> <groupId>systems.manifold</groupId> <artifactId>manifold-ext</artifactId> <version>${manifold.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build></project>如果你的我的项目中应用了 Lombok,须要把 Lombok 也退出 annotationProcessorPaths: ...

January 26, 2023 · 3 min · jiezi

关于java:含文档源码等S2SH基于JAVA的宠物动物管理系统实现

项目名称 [[含文档+源码等]S2SH基于JAVA的宠物动物管理系统实现](http://ym.maptoface.com/archi...) 视频演示 视频去哪了呢?_哔哩哔哩_bilibili 零碎介绍 《S2SH基于JAVA的宠物管理系统实现》该我的项目采纳技术jsp、strust2、Spring、hibernate、tomcat服务器、mysql数据库 开发工具eclipse,我的项目含有源码、论文、配套开发软件、软件装置教程、我的项目公布教程 性能介绍: 零碎次要分为前台和后盾两大模块 前台次要由用户体验应用: 用户登录、注册、查找商品、退出商品到购物车、下单、集体核心批改个人信息,查看集体订单,留言等性能导航; 后盾次要由系统管理员操作应用保护零碎: 订单治理、商品治理、布告治理、新闻治理、用户治理、留言治理、个人信息保护等次要性能 前台页面:http://localhost:8080/Ebuy    用户表t_user  账号:xiamo   明码:123456后盾登录页面:http://localhost:8080/Ebuy/ad...    用户表t_user  后盾管理员账号:admin    明码:123456  技术栈 后端:Spring+SpringMVC+Mybatis前端:JSP+CSS+JavaScript+jQuery应用阐明 应用Navicat或者其它工具,在mysql中创立对应名称的数据库,并导入我的项目的sql文件;应用IDEA/Eclipse/MyEclipse导入我的项目,Eclipse/MyEclipse导入时,若为maven我的项目请抉择maven;若为maven我的项目,导入胜利后请执行maven clean;maven install命令,而后运行;将我的项目中springmvc-servlet.xml配置文件中的数据库配置改为本人的配置;运行我的项目,在浏览器中输出http://localhost:8080/ 登录运行截图 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑  用户管理控制层: package com.houserss.controller; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody; import com.houserss.common.Const;import com.houserss.common.Const.Role;import com.houserss.common.ServerResponse;import com.houserss.pojo.User;import com.houserss.service.IUserService;import com.houserss.service.impl.UserServiceImpl;import com.houserss.util.MD5Util;import com.houserss.util.TimeUtils;import com.houserss.vo.DeleteHouseVo;import com.houserss.vo.PageInfoVo; ...

January 23, 2023 · 5 min · jiezi

关于java:SSM社区居民户籍扶贫管理系统论文包远程安装配置和代码讲解

项目名称 SSM社区居民户籍扶贫管理系统 视频演示 视频去哪了呢?_哔哩哔哩_bilibili 零碎介绍 我的项目介绍管理员角色蕴含以下性能:管理员登录,居民信息管理,居民数据统计,居民政策治理,居民措施匹配,居民数据管理,管理员治理等性能。 居民角色蕴含以下性能:居民登录,根本信息查看等性能。 环境须要1.运行环境:最好是java jdk 1.8,咱们在这个平台上运行的。其余版本实践上也能够。2.IDE环境:IDEA,Eclipse,Myeclipse都能够。举荐IDEA;3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可4.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS;5.数据库:MySql 5.7版本; 技术栈 后端:Spring+SpringMVC+Mybatis前端:HTML+CSS+JavaScript+jsp应用阐明 应用Navicat或者其它工具,在mysql中创立对应名称的数据库,并导入我的项目的sql文件;应用IDEA/Eclipse/MyEclipse导入我的项目,Eclipse/MyEclipse导入时,若为maven我的项目请抉择maven;若为maven我的项目,导入胜利后请执行maven clean;maven install命令,而后运行; 将我的项目中application.yml配置文件中的数据库配置改为本人的配置;运行我的项目,输出localhost:8080/ 登录环境须要 1.运行环境:最好是java jdk 1.8,咱们在这个平台上运行的。其余版本实践上也能够。2.IDE环境:IDEA,Eclipse,Myeclipse都能够。举荐IDEA;3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可4.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS; 5.数据库:MySql 5.7版本;6.是否Maven我的项目:否; 技术栈 后端:Spring+SpringMVC+Mybatis前端:JSP+CSS+JavaScript+jQuery应用阐明 应用Navicat或者其它工具,在mysql中创立对应名称的数据库,并导入我的项目的sql文件;应用IDEA/Eclipse/MyEclipse导入我的项目,Eclipse/MyEclipse导入时,若为maven我的项目请抉择maven;若为maven我的项目,导入胜利后请执行maven clean;maven install命令,而后运行;将我的项目中springmvc-servlet.xml配置文件中的数据库配置改为本人的配置;运行我的项目,在浏览器中输出http://localhost:8080/ 登录运行截图 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑  用户管理控制层: package com.houserss.controller; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody; import com.houserss.common.Const;import com.houserss.common.Const.Role;import com.houserss.common.ServerResponse;import com.houserss.pojo.User;import com.houserss.service.IUserService;import com.houserss.service.impl.UserServiceImpl;import com.houserss.util.MD5Util;import com.houserss.util.TimeUtils;import com.houserss.vo.DeleteHouseVo;import com.houserss.vo.PageInfoVo; ...

January 23, 2023 · 5 min · jiezi

关于java:打包iOS-App并上架到TestFlight测试

开发者账号首先须要注册一个开发者账号,不然什么都免谈。在手机Apple Developer上注册给钱就行了,集体开发者一年688元。 打包AppApp开发好后,就能够通过XCode打包。打包前选好版本号,不要跟以前提交的一样,反复的Version和Build是无奈提交的。当然第一次打包就不可能会反复了。 在菜单栏抉择Product,而后选Archive进行打包: 打包实现,会弹出以下对话框,就能够把利用上传到App Store Connect了。 下面这个对话框能够按上面的形式关上: 上传打包完后,点击Distribute App进行上传: 大略两三分钟,就上传实现了: 遇到的一些问题上传后,App Store Connect还会有测验,比方我第一次上传就遇到以下问题: 因为我援用了一些库,它带有一些权限相干的接口,即便我理论没用上,但还是须要在Info.plist上增加相干阐明。 <key>NSPhotoLibraryUsageDescription</key><string>This App no need</string><key>NSHealthShareUsageDescription</key><string>This App no need</string><key>NSHealthUpdateUsageDescription</key><string>This App no need</string>参考: NSPhotoLibraryUsageDescription key must be present in Info.plist to use camera roll 同时关上告诉推送,但理论不必。 解决以上问题并从新打包即可。 App Store Connect查看上传胜利后,能够登陆Connect查看:https://appstoreconnect.apple... 期待一段时间后,可能会呈现上面的问题,这个小问题,只有在页面上填一下信息就好: 点击治理: 接着就是增加内测和外测群组。而后提交审核。内测不须要审核,外测须要: 实现审核,就能够让外测人员测试了。

January 18, 2023 · 1 min · jiezi

关于java:Java低代码diboot-新手训练营踩坑

筹备代码下载java8 || springboot@2.7.6 || maven 一、环境构建diboot 老手训练营 参考《Maven装置与配置教程》 scoop install openjdk8-redhatjava -versionscoop install mavenmvn -version# C:\Users\Administrator\scoop\apps\maven\3.8.7\conf\settings.xml-- <localRepository>C:/Users/Administrator/scoop/apps/maven/repo</localRepository>-- <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror>--mvn help:systemscoop install springboot@2.7.6spring --version

January 18, 2023 · 1 min · jiezi

关于java:Quartz-SimpleThreadPool

明天开始学习企业级作业调度框架Quartz。 先简略阐明一下,Quartz的应用阐明文档能够从官网获取:Quartz tutorials,而且中文文档也比拟全面、也不难找到。如果想要练习或者学习如何应用Quartz,参考这类文档很容易上手。 咱们会从另外一个角度学习并记录Quartz的学习过程:尽可能从源码的角度,理解Quartz的底层原理。 作为企业级作业调度框架,复杂程度当然和JDK Timer不在一个数量级,对Quartz的学习也不太容易欲速不达,所以,做好筹备,一步一步来。 一个Quartz的例子只管Quartz的底层原理比较复杂,然而应用起来也不算简单。 第一步:创立Job对象,实现execute办法。第二步:创立JobDetail。第三步:创立Trigger。第四步:创立Scheduler,将JobDetail对象和Trigger对象绑定到Scheduler中,启动Schedule @Slf4jpublic class HelloJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { log.info("I dont know want should i do ..."+Thread.currentThread().getId()); } public static void main(String[] args) { JobDetail jobDetail = newJob(HelloJob.class) .withDescription("This is my first quartz job") .withIdentity("MyJob") .build(); Trigger trigger = newTrigger() .withIdentity("myTriggger","MyGroup") .startNow() .withSchedule(simpleSchedule() .withIntervalInSeconds(1) .repeatForever()) .build(); try { Scheduler sche = new StdSchedulerFactory().getScheduler(); sche.scheduleJob(jobDetail,trigger); sche.start(); }catch(Exception e){ e.printStackTrace(); } }运行后果:工作立刻开始执行,每秒钟运行一次,合乎预期。 ...

January 17, 2023 · 1 min · jiezi

关于java:记一次jvm堆外内存OOM的解决过程

本文记录一次堆外内存OOM的排查过程。周末的时候共事对线上服务进行了一次扩容,本认为只是简略减少几个实例而已,后果新实例接入流量后疯狂报警,只能马上切换下线,查看日志后发现如下谬误:jstat命令查看GC信息发现fullgc十分多因为线上服务部署在k8s集群中,实例是运行在docker环境的,镜像没有任何批改,而这个镜像曾经上线将近一个月了,为什么曾经上线的服务没有问题而新退出的实例疯狂报警,带着一头雾水回顾了下之前排查线上性能问题的各种伎俩,貌似都对堆外内存问题排查大刀阔斧,周末始终思考这个问题也进行了一些尝试,无果。转瞬周一到了,到公司后第一工夫查看了相干的一些参数,看了曾经在线上的服务,吓了一跳,线上服务堆外内存也靠近爆满(6G下限),惟恐线上服务全副挂掉。静下心来想了下咱们服务中哪些模块应用了堆外内存,第一个想到的是咱们的RPC框架,因为底层应用了netty会应用堆外内存,为了验证这个问题我也查看了另外一组十分相近的上游服务,后果发现这个服务的堆外内存使用量十分小,只有20M左右,排除掉RPC组件的问题。为了看一下堆外内存的增长曲线,我将线上服务又扩了一个正本,后果发现一个重要的线索,实例启动胜利后堆外内存根本就曾经靠近下限了。那么就省去流量模仿了,于是我在本地启动了一个服务,查看内存应用状况,后果发现启动阶段堆外内存暴涨,到肯定水平后开始稳固,于是应用排除法,将狐疑有问题的组件正文掉,很快定位到了公司的一个存储服务jar包上,又本地进行了一次内存dump,因为这个jar包没有应用netty那么它必定应用了DirectByteBuffer,于是在VisualVM中对dump进行了剖析,发现DirectByteBuffer的持有者集中在了存储服务客户端的连贯对象NioChannel上,下一步对这个链接对象进行了反编译,搜寻了一下ByteBuffer#allocateDirect办法很快发现了一个问题,这个对象初始化的时候申请了4M的堆外内存,也就是说每个链接初始化的时候要申请4M的堆外内存,于是对咱们线上的服务执行了jmap -histo查看对象数统计,发现线上服务NioChannel对象多达1451个,如下图大略算了下,每个对象持有4M堆外内存,这1451个对象要5804M将近6G的堆外内存,问题一下子清朗了起来,能够判定线上的堆外内存就是这里的问题,顺着代码找过来原来这个链接的buffer是能够设置的,分割了存储的同学,对方示意这个buffer能够设置小一点,影响不大。为什么只有咱们遇到了这个问题呢,原来是因为咱们的连接数比拟多的缘故,而这个链接数过多的问题其实是咱们的业务起因造成的,并没有改良空间,于是这个问题目前的解决办法也只有调小buffer。 至此堆外内存使用量过高的问题解决了,那么fullgc过多的问题是怎么回事呢,线上的gc日志是关上的,拉下来一份看了下,如下图所示:能够看到一个比拟显著的问题,fgc之前其实老年代远远没有达到fgc的阈值,触发fgc的起因是有代码调用了System.gc(),而咱们并没有刻意设置-XX:+DisableExplicitGC,也不想设置这个参数。那么接下来须要排查哪里进行了System.gc()调用。在网上查阅材料时偶尔发现了一个线索这里:初始化DirectByteBuffer对象时,在肯定条件下会被动调用System.gc()。 查看了jdk的源码发现ByteBuffer#allocateDirect的过程中的确有一个System.gc()的调用,比照上边图1的调用栈能够确定是这里触发的fgc,也就是说fgc的问题其实是堆外内存OOM的副产品,堆外内存OOM的问题解决这个问题也会迎刃而解,至此问题起因排查分明了。 那么为什么老实例和新实例会体现不一样呢,线上的实例并没有呈现OOM的谬误日志呢,问题的关键在于存储服务的client初始化后便不再变动,新实例初始化时比旧实例的连接数多,恰好达到了6G堆外内存下限左近,而netty的堆外内存是动静申请的,初始化机会比前者晚,申请进来时再申请堆外内存时没有可用的堆外内存了,触发了fgc,最终抛出了OOM。

January 17, 2023 · 1 min · jiezi

关于java:通过Docker启动Solace并在Spring-Boot通过JMS整合Solace

1 简介Solace是一个弱小的实时性的事件驱动音讯队列。本文将介绍如何在Spring中应用,尽管代码应用的是Spring Boot,但并没有应用相干starter,跟Spring的整合一样,可通用。JMS是通过的音讯解决框架,能够深刻学习一下,不同的MQ在JMS的整合上都是相似的。 2 通过Docker启动Solace有两种形式试用Solace,一种是通过Docker来启动,另一种是应用Cloud版本,但Cloud版本有试用期限,咱们应用Docker来启动吧。 先下载镜像: $ docker pull solace/solace-pubsub-standard:9.13.0.16而后通过以下命令启动: $ docker run -d -p 8080:8080 -p 55554:55555 -p 8008:8008 -p 1883:1883 -p 8000:8000 -p 5672:5672 -p 9000:9000 -p 2222:2222 --shm-size=2g --env username_admin_globalaccesslevel=admin --env username_admin_password=admin --name=solace solace/solace-pubsub-standard:9.13.0.16这里端口改为55554,是因为Mac的起因。 而后便能够拜访来登陆治理界面:http://localhost:8080/ 用户名明码为:admin/admin 登陆后能够看到如下界面,Solace按VPN来治理队列,VPN有点像分组,比方某个业务线应用某个VPN。 咱们在default的VPN上创立一个Queue,名为pkslow-queue: 其它设置如下: 接着在该Queue上创立Topic: 创立实现后,咱们能够间接测试一下: 能够Publish到Topic或Queue,也能够从其中一个Subscribe。 实现以上设置后,咱们就能够在Spring Boot中整合了。 3 Spring Boot JMS整合Solace3.1 发送音讯咱们是通过JmsTemplate来发送音讯的,而JmsTemplate须要连贯到MQ,就须要一个ConnectionFactory,这个Factory是带着MQ的一些连贯信息。配置代码如下: @Configurationpublic class SolacePubConfig { private final SolaceProperties solaceProperties; public SolacePubConfig(SolaceProperties solaceProperties) { this.solaceProperties = solaceProperties; } @Bean("connectionFactory") public ConnectionFactory connectionFactory() throws Exception { Properties env = new Properties(); env.put(InitialContext.INITIAL_CONTEXT_FACTORY, "com.solacesystems.jndi.SolJNDIInitialContextFactory"); env.put(InitialContext.PROVIDER_URL, solaceProperties.getBrokerUrl()); env.put(SupportedProperty.SOLACE_JMS_VPN, solaceProperties.getVpn()); env.put(InitialContext.SECURITY_PRINCIPAL, solaceProperties.getUsername()); env.put(InitialContext.SECURITY_CREDENTIALS, solaceProperties.getPassword()); return SolJmsUtility.createConnectionFactory(env); } @Bean public CachingConnectionFactory cachingConnectionFactory(ConnectionFactory connectionFactory) { CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(connectionFactory); cachingConnectionFactory.setSessionCacheSize(10); return cachingConnectionFactory; } @Bean public JmsTemplate pubJmsTemplate(CachingConnectionFactory cachingConnectionFactory) { JmsTemplate jmsTemplate = new JmsTemplate(cachingConnectionFactory); jmsTemplate.setPubSubDomain(true); jmsTemplate.setExplicitQosEnabled(true); jmsTemplate.setDeliveryPersistent(true); jmsTemplate.setDefaultDestinationName(solaceProperties.getDefaultPubDestinationName()); return jmsTemplate; }}生成JmsTemplate后,就能够援用并发送音讯了: ...

January 17, 2023 · 2 min · jiezi

关于java:Spring-Boot-项目打包-exe-可执行程序实战来了

近期做了一个前后端合并的spring boot我的项目,然而要求达成exe文件,提供给不懂电脑的小白装置应用,就去钻研了半天,踩了很多坑,写这篇文章,是想看到这篇文章的人,依照我的步骤走,能少踩坑。 筹备 筹备工作: 一个jar包,没有bug能失常启动的jar包exe4j,一个将jar转换成exe的工具inno setup,一个将依赖和exe一起打成一个安装程序的工具举荐一个 Spring Boot 基础教程及实战示例:https://github.com/javastacks... 开始 以我为例子,我将jar包放在了桌面 关上装置好的exe4j 间接下一步进入界面,抉择JAVA转EXE 而后点下一步,输出名称和输入门路 持续点击下一步,抉择启动模式 下方有个选项,须要设置打包后的程序兼容32和64位零碎 进来后勾选上 而后始终下一步,始终呈现如下界面,开始抉择jar包以及配置 在VM参数配置的中央加上:-Dfile.encoding=utf-8 点击下一步,配置JRE 下拉框点击后进入如下界面 照着这个样子写的目标是,最终会把本地jre目录和exe一起打包,让exe文件本人去依据门路去查找一起打包的jre,可不必再装置jdk 接着下一步,抉择Client VM 而后始终下一步,最终呈现如下界面 这个时候你会发现桌面多了一个demo.exe文件,这个时候先别着急点开,接下来就是将jre和exe文件再打个包合并,达到在没有jdk电脑环境下也能运行 关上inno setup,左上角File - New 间接点下一步,填写配置,利用名称,版本等,随便 而后点击下一步,这个中央默认就行,间接下一步 接着抉择生成好的exe文件 而后下一步,进入这个界面放弃默认,间接下一步 仍旧下一步,不必管 持续下一步,这里是抉择语言 而后就是抉择输入门路和填写安装程序的名字了 而后下一步,间接点Next,而后完结 配置到最初一步了,脚本文件,到这里会弹出问你是否马上编译,抉择否,先把脚本写好再本人编译 而后到了最初一步了,把本地的JRE写进脚本 ...

January 16, 2023 · 1 min · jiezi

关于java:使用-Elasticsearch-搭建自己的搜索系统这个厉害了

作者:Hai Xiang \起源:https://www.cnblogs.com/haixi... 什么是elasticsearchElasticsearch 是一个开源的高度可扩大的全文搜寻和剖析引擎,领有查问近实时的超强性能。 赫赫有名的Lucene 搜索引擎被宽泛用于搜寻畛域,然而操作简单繁琐,总是让开发者敬而远之。而 Elasticsearch将 Lucene 作为其外围来实现所有索引和搜寻的性能,通过简略的 RESTful 语法来暗藏掉 Lucene 的复杂性,从而让全文搜寻变得简略 ES在Lucene根底上,提供了一些分布式的实现:集群,分片,复制等。 搜寻为什么不必MySQL而用es咱们本文案例是一个迷你商品搜寻零碎,为什么不思考应用MySQL来实现搜寻性能呢?起因如下: MySQL默认应用innodb引擎,底层采纳b+树的形式来实现,而Es底层应用倒排索引的形式实现,应用倒排索引反对各种维度的分词,能够掌控不同粒度的搜寻需要。(MYSQL8版本也反对了全文检索,应用倒排索引实现,有趣味能够去看看两者的差异)如果应用MySQL的%key%的含糊匹配来与es的搜寻进行比拟,在8万数据量时他们的耗时曾经达到40:1左右,毫无疑问在速度方面es完胜。es在大厂中的利用状况es使用最宽泛的是elk组合来对日志进行搜寻剖析58安全部门、京东订单核心简直全采纳es来实现相干信息的存储与检索es在tob的我的项目中也用于各种检索与剖析在c端产品中,企业通常本人基于Lucene封装本人的搜寻零碎,为了适配公司营销策略、举荐零碎等会有更多定制化的搜寻需要es客户端选型spring-boot-starter-data-elasticsearch我置信你看到的网上各类公开课视频或者小我的项目均举荐应用这款springboot整合过的es客户端,然而咱们要say no! 另外,ES 系列面试题和答案全副整顿好了,微信搜寻Java技术栈,在后盾发送:面试,能够在线浏览。 此图是引入的最新版本的依赖,咱们能够看到它所应用的es-high-client也为6.8.7,而es7.x版本都曾经更新很久了,这里许多新个性都无奈应用,所以版本滞后是他最大的问题。而且它的底层也是highclient,咱们操作highclient能够更灵便。我呆过的两个公司均未采纳此客户端。 elasticsearch-rest-high-level-client这是官网举荐的客户端,反对最新的es,其实应用起来也很便当,因为是官网举荐所以在个性的操作上必定优于前者。而且该客户端与TransportClient不同,不存在并发瓶颈的问题,官网首推,必为精品! 搭建本人的迷你搜寻零碎引入es相干依赖,除此之外需引入springboot-web依赖、jackson依赖以及lombok依赖等。 Spring Boot 根底就不介绍了,举荐下这个实战教程:https://www.javastack.cn/cate... <properties> <es.version>7.3.2</es.version></properties><!-- high client--><dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>${es.version}</version> <exclusions> <exclusion> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-client</artifactId> </exclusion> <exclusion> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> </exclusion> </exclusions></dependency><dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>${es.version}</version></dependency><!--rest low client high client以来低版本client所以须要引入--><dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-client</artifactId> <version>${es.version}</version></dependency>es配置文件es-config.properties es.host=localhostes.port=9200es.token=es-tokenes.charset=UTF-8es.scheme=httpes.client.connectTimeOut=5000es.client.socketTimeout=15000封装RestHighLevelClient @Configuration@PropertySource("classpath:es-config.properties")public class RestHighLevelClientConfig { @Value("${es.host}") private String host; @Value("${es.port}") private int port; @Value("${es.scheme}") private String scheme; @Value("${es.token}") private String token; @Value("${es.charset}") private String charSet; @Value("${es.client.connectTimeOut}") private int connectTimeOut; @Value("${es.client.socketTimeout}") private int socketTimeout; @Bean public RestClientBuilder restClientBuilder() { RestClientBuilder restClientBuilder = RestClient.builder( new HttpHost(host, port, scheme) ); Header[] defaultHeaders = new Header[]{ new BasicHeader("Accept", "*/*"), new BasicHeader("Charset", charSet), //设置token 是为了平安 网关能够验证token来决定是否发动申请 咱们这里只做象征性配置 new BasicHeader("E_TOKEN", token) }; restClientBuilder.setDefaultHeaders(defaultHeaders); restClientBuilder.setFailureListener(new RestClient.FailureListener(){ @Override public void onFailure(Node node) { System.out.println("监听某个es节点失败"); } }); restClientBuilder.setRequestConfigCallback(builder -> builder.setConnectTimeout(connectTimeOut).setSocketTimeout(socketTimeout)); return restClientBuilder; } @Bean public RestHighLevelClient restHighLevelClient(RestClientBuilder restClientBuilder) { return new RestHighLevelClient(restClientBuilder); }}封装es罕用操作es搜寻零碎封装源码 ...

January 16, 2023 · 4 min · jiezi

关于java:含文档辩论PPT源码等微信小程序ssm社区心理健康服务平台后台管理系统

项目名称 [含文档+答辩PPT+源码等]微信小程序ssm社区心理健康服务平台+后盾管理系统](https://ym.maptoface.com/arch...) 视频演示 视频去哪了呢?_哔哩哔哩_bilibili 零碎介绍 《微信小程序心理健康服务平台+后盾管理系统|前后拆散VUE》该我的项目含有源码、论文等材料、配套开发软件、软件装置教程、我的项目公布教程等 本零碎蕴含微信小程序前台和Java做的后盾管理系统,该后盾采纳前后台前后拆散的模式应用Java+VUE 微信小程序——前台波及技术:WXML 和 WXSS、JavaScript、uniapp Java——后盾波及技术: 前端应用技术:JSP,HTML5,CSS3、JavaScript、VUE等 后端应用技术:Spring、SpringMvc、Mybatis(SSM)等 数据库:Mysql数据库 小程序框架:uniapp 小程序开发软件:HBuilder X 小程序运行软件:微信开发者 零碎次要分为管理员和用户、咨询师三局部, 管理员服务端:首页、集体核心、用户治理、咨询师治理、心理书籍治理、相干资源管理、试卷治理、试题治理、系统管理、订单治理, 咨询师客户端:首页、咨询师、心理书籍、相干资源、我的, 用户客户端;首页、咨询师、心理书籍、相干资源、我的等性能, 基本上实现了整个社区心理健康服务平台小程序信息管理的过程。 零碎性能残缺,适宜作为毕业设计、课程设计、数据库大作业。 环境须要 1.运行环境:最好是java jdk 1.8,咱们在这个平台上运行的。其余版本实践上也能够。2.IDE环境:IDEA,Eclipse,Myeclipse都能够。举荐IDEA;3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可4.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS; 5.数据库:MySql 5.7版本;6.是否Maven我的项目:否; 技术栈 后端:Spring+SpringMVC+Mybatis前端:JSP+CSS+JavaScript+jQuery应用阐明 应用Navicat或者其它工具,在mysql中创立对应名称的数据库,并导入我的项目的sql文件;应用IDEA/Eclipse/MyEclipse导入我的项目,Eclipse/MyEclipse导入时,若为maven我的项目请抉择maven;若为maven我的项目,导入胜利后请执行maven clean;maven install命令,而后运行;将我的项目中springmvc-servlet.xml配置文件中的数据库配置改为本人的配置;运行我的项目,在浏览器中输出http://localhost:8080/ 登录运行截图 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑  用户管理控制层: package com.houserss.controller; ...

January 15, 2023 · 5 min · jiezi

关于java:含文档PPT源码等基于JavaWeb实现的超市管理系统包运行成功

项目名称 [基于JavaWeb实现的超市管理系统[包运行胜利]](https://ym.maptoface.com/arch...) 视频演示 [含文档+PPT+源码等]基于JavaWeb实现的超市管理系统[包运行胜利]_哔哩哔哩_bilibili 零碎介绍 《JavaWeb实现的超市管理系统》该我的项目采纳的技术后盾框架:Servlet、JSP、JDBC、UI界面:BootStrap、jQuery、数据库:MySQL 零碎性能 该零碎共蕴含两种角色:员工和管理员。零碎的次要功能模块如下: 系统管理零碎登陆、零碎退出、批改明码 员工信息管理员工用户治理、减少员工用户、员工用户查问 商品信息管理商品信息管理、减少商品信息、商品信息查问 货架信息管理货架信息管理、减少货架信息、货架信息查问 商品类型治理商品类型治理、减少商品类型 进货信息管理进货信息管理、减少进货信息、进货信息查问 销售信息管理销售信息管理、减少销售信息、销售信息查问 库存信息管理库存信息盘点、库存信息查问、缺货信息揭示 盈利信息管理盈利信息查问、盈利信息统计、盈利信息剖析 该零碎功能完善、界面好看、操作简略、功能齐全、治理便捷,具备很高的理论利用价值。 环境须要 1.运行环境:最好是java jdk 1.8,咱们在这个平台上运行的。其余版本实践上也能够。2.IDE环境:IDEA,Eclipse,Myeclipse都能够。举荐IDEA;3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可4.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS; 5.数据库:MySql 5.7版本;6.是否Maven我的项目:否; 技术栈 后端:Spring+SpringMVC+Mybatis前端:JSP+CSS+JavaScript+jQuery应用阐明 应用Navicat或者其它工具,在mysql中创立对应名称的数据库,并导入我的项目的sql文件;应用IDEA/Eclipse/MyEclipse导入我的项目,Eclipse/MyEclipse导入时,若为maven我的项目请抉择maven;若为maven我的项目,导入胜利后请执行maven clean;maven install命令,而后运行;将我的项目中springmvc-servlet.xml配置文件中的数据库配置改为本人的配置;运行我的项目,在浏览器中输出http://localhost:8080/ 登录运行截图 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑  用户管理控制层: package com.houserss.controller; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody; import com.houserss.common.Const;import com.houserss.common.Const.Role;import com.houserss.common.ServerResponse;import com.houserss.pojo.User;import com.houserss.service.IUserService;import com.houserss.service.impl.UserServiceImpl;import com.houserss.util.MD5Util;import com.houserss.util.TimeUtils;import com.houserss.vo.DeleteHouseVo;import com.houserss.vo.PageInfoVo; ...

January 15, 2023 · 5 min · jiezi

关于java:基于幂等表思想的幂等实践

一、为什么须要幂等分布式场景下,多个业务零碎间实现强统一的协定是极其艰难的。一个最简略和可实现的假如就是保障最终一致性,这要求服务端在解决一个反复的申请时须要给出雷同的回应,同时不会对长久化数据产生副作用(即屡次操作与单次操作的后果须要是业务角度统一的)。一个API领有幂等能力的话,调用发起方就能够很平安的进行重试。这合乎咱们广泛的假如。提供幂等能力是服务提供方必须须要做的事。领有幂等能力的话能够保障咱们的接口不会被各种异样重试或歹意申请锁冲击。二、幂等形式不同的场景下(常见的是【界面和后端接口交互场景】和【接口于接口交互场景】),幂等形式有很多并且各不相同,都各有一些局限性和毛病!!! 能够基于【业务key + 业务状态机 + 乐观锁】去做幂等实现(个别实用于比较简单的update场景) 比方:更新订单状态为 finished 的场景中,先依据订单号查问订单,判断订单状态是否为finished,若不是则更新为finished能够基于【业务key + 分布式锁 + 业务状态机】去做幂等实现 比方:新增用户信息场景中,执行办法前先加分布式锁(防并发),以用户身份证号为查问条件,查问用户,如果用户不存在则进行新增。如果用户存在则幂等解决这种计划个别有个固定的流程:【一锁、二判、三执行】能够基于【业务key + 惟一索引】去做幂等实现(个别实用于新增数据场景) 比方:新增用户信息场景中,以用户身份证号为惟一键,建设惟一索引,新增用户时通过捕捉惟一键抵触异样(DuplicateKeyException)进行幂等管制能够基于【Redis + token模式】去做幂等实现(多用于界面和接口交互,接口于接口交互不太实用,该计划也是比拟常见的计划,但不在本次探讨范畴中) 比方:用户提交填写好的表单信息,多次重复提交时保障仅仅真正执行一次,其余的都幂等返回雷同后果能够基于【幂等表】去做幂等实现(比拟通用的一种计划,具体效率取决于存储幂等记录的存储介质) 比方:生产MQ音讯时,为了防止音讯反复生产,生产音讯前能够先插入一条幂等记录,而后再执行生产逻辑,生产实现后批改幂等记录的幂等状态为生产胜利!接口互调的状况相似三、幂等设计准则一个具备幂等性的服务,要求无论反复申请在如许极其的状况下产生,都要表里如一,此时必须满足: 对外:返回完全相同的后果对内:本身状态不再产生任何扭转对于服务提供方来说:严格来说须要申请中的字段齐全一样,服务提供刚才认为是反复申请。然而在理论环境中咱们可能没有这么严格的要求,咱们个别认为只有要害的业务参数雷同,那么他就属于反复申请,应该被幂等解决。对于服务调用方来说:须要做好幂等后果解决,屡次申请返回雷同后果须要正确被解决幂等设计要尽量从简略、牢靠、高效(过多的幂等逻辑会对可用性和性能造成影响)角度登程 简略:幂等流程和逻辑要尽量简略牢靠:不仅仅在失常运行的状况下要保障幂等的可靠性,在某些异样场景下也要尽量保障幂等的可靠性,否则该幂等设计的意义将大打折扣高效:幂等逻辑执行不能高耗时,针对于一些高并发的接口须要做到尽量减少幂等逻辑执行耗时通用幂等组件设计易用性和可扩展性也同样重要四、常见幂等场景例子【MQ音讯生产场景中】,因为MQ为了保障音讯投递胜利,可能会发动多次重试,那么消费者不便须要保障反复的音讯可能被幂等解决(比方:监听用户领取胜利音讯进行生成领取单)【界面和接口交互场景中】,前端反复提交数据,后盾接口须要保障只执行一次,其余反复申请均幂等返回(比方:用户反复提交订单、反复提交录入的用户信息)【接口互调的场景中】,调用方可能因为多种起因没能收到响应后果而发动重试(比方:数据同步、库存扣减等),此时被调用方须要保障反复调用幂等解决五、幂等实际为了将幂等这个常见的通用需要尽量设计得通用化,咱们这里采纳【幂等表 + 幂等状态机】来实现,该计划能够实用于绝大部分的【界面 + 接口交互】和【接口 与 接口交互】模式如果我的项目仅仅是界面和接口交互模式,那么采纳【Redis + token】计划也是一个不错的抉择当然,软件工程中简直没有银弹,很难有一种完满实用与所有场景的计划1、设计流程 调用放发动申请,申请达到服务提供方获取指定的业务key作为惟一的幂等键,构建幂等记录(此时幂等记录status为解决中(processing)),而后尝试将幂等记录写入存储介质(能够是Redis也能够是MySQL或其余存储介质)如果幂等记录写入胜利,则执行业务逻辑业务逻辑执行结束,通过惟一键批改幂等记录的status为胜利(success)如果幂等记录写入失败,则阐明幂等记录已存在(该业务key对应的数据,之前有被执行过),须要进行如下解决:通过幂等惟一键查问幂等记录,并且断定幂等记录的status 如果status为胜利(success),则阐明上次曾经执行过该业务了,本次无需再反复执行,获取上次执行的后果(如果有需要的话)幂等返回即可如果status为解决中(processing),则阐明曾经有其余线程正在解决业务数据 或者是 极其状况下利用宕机导致的异常情况。此时须要断定【申请处于解决中(processing)状态的时长】,并且联合利用配置的【容许的最大业务执行时长】进行判断 处于processing状态的工夫曾经超过配置的【容许的最大业务执行时长】,则尝试以乐观锁的形式从新批改幂等记录,如果批改胜利则执行业务逻辑,反之则抛出并发异样。处于processing状态的工夫没有超过配置的【容许的最大业务执行时长】,那么间接抛出并发申请异样2、问题思考对于上述的幂等实现流程中,极其状况下,有如下几点须要思考和留神的问题点 极其状况下,如果插入幂等记录胜利,并且失常执行了业务流程,此时更新幂等状态为success时出现异常(比方存储幂等记录的存储介质宕机了),此时是否须要解决该异样,还是说抛出异常中断流程???如果抛出异样会有什么影响?如果catch异样会有什么影响? 计划一、抛出异样:如果抛出异常中断流程,那么调用方应该感知到调用失败了,然而实际上业务流程曾经执行结束,这种状况如果调用方发动重试,那么幂等便会生效(同一个业务code被执行了两次)计划二、不抛出异样:如果不抛出异样,接口会继续执行,而后返回数据给调用方,如果调用方收到了返回数据,那么便不会发动重试了,不会有幂等问题。然而此时幂等记录的状态依然是解决中(processing),再指定了业务最大执行工夫的状况下,如果调用方【超过指定的最大执行】工夫再次发动重试,那么幂等依然生效(当然咱们能够不指定业务最大执行工夫)通过上述两种状况的比拟,咱们个别偏向第二种计划,本人解决掉异样,并且做一层 【兜底策略】 (比方告警或记录该条幂等数据信息等,后续能够转人工核查该数据),这种计划更加稳固和实用如果业务逻辑执行失败,那么是否应该删除之前创立的幂等记录? 依照严格的幂等含意来说,咱们应该保留这条幂等记录,并且将幂等记录的状态批改为Exception或failed,后续有重试申请进来时执行返回failed给调用方即可(保障屡次调用失去的后果雷同)。 然而在实在环境中业务执行异样有可能是数据校验失败、接口里调用内部零碎失败(比方内部零碎正在发版(没有做优雅公布)等)针对于这些状况可能调用方批改数据后进行重试或过肯定工夫后进行重试,那么此时最好有肯定的自愈能力,而不是每次这种数据都转人工解决(一些场景中会加大人力老本,比方我之前波及到的某个零碎,常常有些调用方传递的业务参数有问题或接口里调用内部零碎失败的状况)当然这两种策略须要依据具体的状况来抉择,没有谁好谁坏之分。是否须要设定【最大的解决工夫】,比方咱们冀望接口最大解决工夫为1小时(也就是说幂等记录解决processing状态的工夫最大为1h),如果超过这个工夫,那么认为这不是一种失常的case,下次重试申请时应该尝试复原业务执行。 这也是个具备两面性的抉择问题,须要依据理论我的项目状况衡量抉择

January 15, 2023 · 1 min · jiezi

关于java:功能比较丰富ssmmysql医药进销存系统源码包远程安装配置及代码讲解

    博主介绍:✌退职Java研发工程师、专一于程序设计、源码分享、技术交换、专一于Java技术畛域和毕业设计✌ 项目名称 (性能比拟丰盛)ssm+mysql医药进销存零碎源码(包近程装置配置及代码解说) 视频演示 视频去哪了呢?_哔哩哔哩_bilibili 零碎介绍 004ssm+mysql医药进销存零碎我的项目介绍医药进销存零碎,次要性能包含:其余治理:供货商治理,新增、搜寻、编辑、删除;布告治理:发布公告、布告列表;生产治理:订单列表、减少生产、订单日志;分店洽购:分店审核、洽购;总店仓库:出库治理、仓库列表、入库治理;分店治理:分店库存、分店列表、分店财务;商品治理:原材料、药效、商品列表、药品类型;总店洽购:洽购列表、洽购审核;合同治理:合同类型治理、合同列表;会员治理:会员列表;质检:质检;权限治理:人员治理、模块治理、部门治理、角色治理;审核治理:财务审核、生产审核、洽购审核;分店销售:销售统计图、订单零售审核、订单列表、分店销售; 该我的项目共有49张表,性能比较复杂; 环境须要1.运行环境:最好是java jdk 1.8,咱们在这个平台上运行的。其余版本实践上也能够。2.IDE环境:IDEA,Eclipse,Myeclipse都能够。举荐IDEA;3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可4.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS;5.是否Maven我的项目: 是;查看源码目录中是否蕴含pom.xml;若蕴含,则为maven我的项目,否则为非maven我的项目6.数据库:MySql 5.7版本; 技术栈后端:Spring SpringMVC MyBatis前端:JSP+Layui+jQuery应用阐明应用Navicat或者其它工具,在mysql中创立对应名称的数据库,并导入我的项目的sql文件;将我的项目中db.properties和spring.xml配置文件中的数据库配置改为本人的配置;应用IDEA/Eclipse/MyEclipse导入我的项目,Eclipse/MyEclipse导入时,若为maven我的项目请抉择maven;若为maven我的项目,导入胜利后请执行maven clean;maven install命令,配置tomcat,而后运行;注:tomcat中须要配置的门路必须为/medicine,否则会呈现问题运行我的项目,输出http://localhost:8080/medicin... 登录管理员用户名:admin 明码:123注意事项对于图片门路的配置(肯定要配置,否则图片无法访问)1)首先批改src/main/com.yidu/action/ErpStaff/ErpStaffAction.java中的第205行与第308行的门路,把它设置成本人本地的门路,如:String path = "E:\upload";2)首先批改src/main/com.yidu/action/ErpImg/ErpImgAction.java中的第44行与第82行的门路,把它设置成与下面雷同的门路,如:String path = "E:\upload";3)在idea中 tomcat->deployment中配置方才设置的本地门路的虚构门路为/upload,如截图所示;若编译器为eclipse,请在eclipse中配置方才设置的本地门路的虚构门路为/upload,如截图所示; 当遇到mysql查问语句中,ONLY_FULL_GROUP_BY的问题时,在navicat中执行下列语句:select @@sql_mode; 查看是否蕴含ONLY_FULL_GROUP_BY;若蕴含,则为其引起的问题; set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';select @@sql_mode; 环境须要 1.运行环境:最好是java jdk 1.8,咱们在这个平台上运行的。其余版本实践上也能够。2.IDE环境:IDEA,Eclipse,Myeclipse都能够。举荐IDEA;3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可4.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS; 5.数据库:MySql 5.7版本;6.是否Maven我的项目:否; 技术栈 后端:Spring+SpringMVC+Mybatis前端:JSP+CSS+JavaScript+jQuery应用阐明 应用Navicat或者其它工具,在mysql中创立对应名称的数据库,并导入我的项目的sql文件;应用IDEA/Eclipse/MyEclipse导入我的项目,Eclipse/MyEclipse导入时,若为maven我的项目请抉择maven;若为maven我的项目,导入胜利后请执行maven clean;maven install命令,而后运行;将我的项目中springmvc-servlet.xml配置文件中的数据库配置改为本人的配置;运行我的项目,在浏览器中输出http://localhost:8080/ 登录运行截图 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑  用户管理控制层: ...

January 14, 2023 · 5 min · jiezi

关于java:JAVA定时任务-JDK-Timer

一个JDK Timer的例子。JDK Timer蕴含的次要对象。Timer对象剖析。TimerTask对象剖析。任务调度:一次性定时工作。任务调度:屡次执行的定时工作(固定工夫点或固定工夫距离)。JDK Timer是单线程的吗?Thread和Runable的区别。优缺点。一个JDK Timer的例子我的项目中其实是常常须要定时工作的,JDK就提供了一个定时工作的实现Timer,然而因为JDK Timer不是很灵便(比方不能反对cron表达式的执行打算),所以我的项目中理论用的应该比拟少。 不过JDK Timer的应用非常简单。 第一步:创立Timer对象。第二步:扩大TimerTask实现其run办法。第三步:调用Timer对象的schedule办法创立执行打算。 @Slf4jpublic class TimerTaskDemo { public void runTimerA(){ Timer timer1=new Timer("Timer"); long delay=10000L; timer1.schedule(new TimerTask(){ @Override public void run(){ log.info("This is timerTaskA:" + Thread.currentThread().getId()); timer1.cancel(); }},delay); } public static void main(String[] args) { TimerTaskDemo timerTaskDemo=new TimerTaskDemo(); log.info("There we come:" + Thread.currentThread().getId()); timerTaskDemo.runTimerA(); }运行后果:主线程输入,10秒后定时工作执行。 21:27:17.313 [main] INFO com.example.demo.task.TimerTaskDemo - There we come:121:27:27.340 [Timer] INFO com.example.demo.task.TimerTaskDemo - This is timerTaskA:11JDK Timer蕴含的次要对象JDK提供了定时控制器Timer,次要包含: Timer:定时控制器。TimerTask:定时控制器被触发当前要执行的工作,是一个实现了Runable的抽象类,利用须要扩大实现TimerTask从而执行咱们的定时工作。Schedule:执行打算,理论是Timer的一个办法,依照肯定的规定绑定TimerTask到Timer。TaskQueue:工作队列,每一个Timer都蕴含一个工作队列保留工作,以便Timer一个个取出并执行工作。Timer对象剖析JDK 定时工作的次要对象就是这个定时器,负责定时工作的创立及调度执行。 ...

January 14, 2023 · 3 min · jiezi

关于java:详解ThreadLocal

ThreadLocal 是什么ThreadLocal类提供了一种线程本地变量的实现形式。不同于各线程都能够拜访的全局变量,ThreadLocal中的变量属于线程公有,只有以后线程能力拜访到。 ThreadLocal能做什么案例:为每个线程生成惟一的标识符;第一次调用ThreadId.get()时会返线程Id会被赋值。当第一次调用get办法时会触发initialValue生成初始值。 import java.util.concurrent.atomic.AtomicInteger; public class ThreadId { private static final AtomicInteger nextId = new AtomicInteger(0); //生成每个线程的ID private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>() { @Override protected Integer initialValue() { return nextId.getAndIncrement(); } }; // 返回线程的惟一id; public static int get() { return threadId.get(); } }下面的案例能够衍生出其余实用场景,比方登录token信息的传递等等。 ThreadLocal是怎么实现线程本地变量的想必大家看到这,内心中还是存在疑难,为什么ThreadLocal可能实现线程的本地变量?数据是怎么存储的?那么先上图阐明其存储构造和实现本地变量的原理,而后再通过要害办法的源码解析去撑持和印证咱们的说法。从图中咱们能够看到 每个线程持有一个ThreadLocalMap的对象。ThreadLocalMap外部有个数组,数组对象是Entry。Entry的key是ThreadLocal对象,value是咱们设置的具体值。通过每个线程本人持有一个独自的ThreadLocalMap对象,并向这个对象中设置对应的value值,实现了线程公有的本地变量设置和获取。接下来咱们通过源码来看下本地变量的设置、获取、删除办法。set(T value) public void set(T value) { //获取以后线程 Thread t = Thread.currentThread(); //获取以后线程的ThreadLocalMap对象 ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }set办法通过获取以后线程的ThreadLocalMap对象并以ThreadLocal为key,设置的值为value向其设值。ThreadLocalMap大家能够简略的了解成为一个map,因为不是本文重点解释内容,ThreadlocalMap具体的细节,感兴趣的小伙伴能够自行查阅源码。get() ...

January 14, 2023 · 1 min · jiezi

关于java:架构设计你真的理解软件设计中的SOLID原则吗

前言在软件架构设计畛域,有一个赫赫有名的设计准则——SOLID准则,它是由由Robert C. Martin(也称为 Uncle Bob)提出的,领导咱们写出可保护、能够测试、高扩大、高内聚、低耦合的代码。是不是很牛,然而你们都了解这个设计准则吗,如果了解不深刻的话,更这我通过JAVA示例深入浅出的明确这个重要的准则吧。SOLID实际上是由5条准则组成, 咱们逐个介绍。 S:繁多职责准则(SRP)O : 开闭准则 (OSP)L : 里氏替换准则 (LSP)I:接口隔离准则(ISP)D:依赖倒置准则(DIP) 繁多职责准则(SRP)这个准则指出“一个类应该只有一个扭转的理由”,这意味着每个类都应该有繁多的责任或繁多的目标。举个例子来了解其中的核心思想,假如有一个BankService的类须要执行以下操作: 1.存钱2.取钱3.打印通票簿4.获取贷款信息5.发送一次性明码 package com.alvin.solid.srp;public class BankService { // 存钱 public long deposit(long amount, String accountNo) { //deposit amount return 0; } // 取钱 public long withDraw(long amount, String accountNo) { //withdraw amount return 0; } // 打印通票簿 public void printPassbook() { //update transaction info in passbook } // 获取贷款信息 public void getLoanInterestInfo(String loanType) { if (loanType.equals("homeLoan")) { //do some job } if (loanType.equals("personalLoan")) { //do some job } if (loanType.equals("car")) { //do some job } } // 发送一次性明码 public void sendOTP(String medium) { if (medium.equals("email")) { //write email related logic //use JavaMailSenderAPI } }}当初咱们来看看这么写会带来什么问题? ...

January 14, 2023 · 4 min · jiezi

关于java:Java-UDF-的设计与使用介绍兼容-Hive-UDF-实现数据快速迁移

作者介绍: 李仕杨,SelectDB 生态研发工程师,Apache Doris Contributor。 咱们在应用各个 SQL 引擎时,会遇到纷繁复杂的查问需要。一部分能够通过引擎自带的内置函数去解决,但内置函数往往具备肯定通用性,在局部非凡场景下内置函数可能无奈满足需要,所以个别 SQL 引擎会提供 UDF 性能,不便用户通过本人写逻辑来满足特定的需要,Apache Doris 也不例外。 在 Java UDF 之前,Apache Doris 提供了原生 UDF 。因为是应用 C++ 来编写的,执行效率高、速度更快,然而在理论应用中也会存在一些问题: 跟 Doris 代码耦合度高,须要本人打包编译 Doris 源码只反对 C++ 语言并且 UDF 代码出错会影响 Doris 集群稳定性对于只相熟 Hive、Spark 等大数据组件的用户有肯定应用门槛由上可知,原生的 UDF 实现起来门槛较高且存在肯定的不稳定性因素。那么是否有一种实现绝对简略、应用门槛较低且与 Doris 代码耦合度低的 UDF 呢? 答案是有的。在 2022 年 12 月正式公布的 Apache Doris 1.2.0 版本(https://github.com/apache/dor...)中,咱们推出了全新的 Java UDF 和 Remote UDF 性能,其中 Java UDF 不仅能满足以上要求,并且在不便和平安角度为用户带来了全新体验: 不相熟 C++?Java 代码一样能够实现本人的 UDF应用条件刻薄?只有有 Jar 包就能应用放心稳定性?Java UDF 出错只影响本身,对 Doris 的稳定性简直无影响迁徙旧大数据平台的数据和 UDF 费时费力?Java UDF 齐全兼容 Hive UDF,轻松实现疾速迁徙.......设计思路大体步骤Apache Doris 的 BE 是由 C++ 代码编写,如果想在 Doris 中实现 Java UDF,不可避免须要调用 JNI,而不正确的 JNI 调用将导致重大的性能问题。那么该如何设计 Java UDF 以解决这个问题呢? ...

January 13, 2023 · 3 min · jiezi