关于java:18-个一线工作的常用-Shell-脚本建议收藏

起源:进击云原生 1、检测两台服务器指定目录下的文件一致性#!/bin/bash ###################################### 检测两台服务器指定目录下的文件一致性 ##################################### #通过比照两台服务器上文件的md5值,达到检测一致性的目标 dir=/data/web b_ip=192.168.88.10 #将指定目录下的文件全副遍历进去并作为md5sum命令的参数,进而失去所有文件的md5值,并写入到指定文件中 find $dir -type f|xargs md5sum > /tmp/md5_a.txt ssh $b_ip "find $dir -type f|xargs md5sum > /tmp/md5_b.txt" scp $b_ip:/tmp/md5_b.txt /tmp #将文件名作为遍历对象进行一一比对 for f in `awk '{print 2} /tmp/md5_a.txt'`do #以a机器为规范,当b机器不存在遍历对象中的文件时间接输入不存在的后果 if grep -qw "$f" /tmp/md5_b.txt then md5_a=`grep -w "$f" /tmp/md5_a.txt|awk '{print 1}'` md5_b=`grep -w "$f" /tmp/md5_b.txt|awk '{print 1}'` #当文件存在时,如果md5值不统一则输入文件扭转的后果 if [ $md5_a != $md5_b ]then echo "$f changed." fi else echo "$f deleted." fi done 2、定时清空文件内容,定时记录文件大小#!/bin/bash ################################################################# 每小时执行一次脚本(工作打算),当工夫为0点或12点时,将目标目录下的所有文件内#容清空,但不删除文件,其余工夫则只统计各个文件的大小,一个文件一行,输入到以时#间和日期命名的文件中,须要思考目标目录下二级、三级等子目录的文件 ################################################################ logfile=/tmp/`date +%H-%F`.log n=`date +%H` if [ $n -eq 00 ] || [ $n -eq 12 ] then #通过for循环,以find命令作为遍历条件,将目标目录下的所有文件进行遍历并做相应操作 for i in `find /data/log/ -type f` do true > $i done else for i in `find /data/log/ -type f` do du -sh $i >> $logfile done fi 3、检测网卡流量,并按规定格局记录在日志中#!/bin/bash ####################################################### #检测网卡流量,并按规定格局记录在日志中#规定一分钟记录一次 #日志格局如下所示: #2019-08-12 20:40 #ens33 input: 1234bps #ens33 output: 1235bps ######################################################3 while : do #设置语言为英文,保障输入后果是英文,否则会呈现bug LANG=en logfile=/tmp/`date +%d`.log #将上面执行的命令后果输入重定向到logfile日志中 exec >> $logfile date +"%F %H:%M" #sar命令统计的流量单位为kb/s,日志格局为bps,因而要*1000*8 sar -n DEV 1 59|grep Average|grep ens33|awk '{print $2,"\t","input:","\t",$5*1000*8,"bps","\n",$2,"\t","output:","\t",$6*1000*8,"bps"}' echo "####################" #因为执行sar命令须要59秒,因而不须要sleep done 4、计算文档每行呈现的数字个数,并计算整个文档的数字总数#!/bin/bash ######################################################### #计算文档每行呈现的数字个数,并计算整个文档的数字总数 ######################################################## #应用awk只输入文档行数(截取第一段) n=`wc -l a.txt|awk '{print $1}'` sum=0 #文档中每一行可能存在空格,因而不能间接用文档内容进行遍历 for i in `seq 1 $n`do #输入的行用变量示意时,须要用双引号 line=`sed -n "$i"p a.txt`#wc -L选项,统计最长行的长度 n_n=`echo $line|sed s'/[^0-9]//'g|wc -L` echo $n_nsum=$[$sum+$n_n] done echo "sum:$sum" 杀死所有脚本 ...

August 31, 2023 · 8 min · jiezi

关于java:JVM整理三

JVM介绍执行引擎执行引擎蕴含解释器、jit编译器、垃圾回收器,所以java又称为是半编译半解释的语言.执行引擎的工作就是将字节码指令解释/编译为利用平台上的本地机器指令,能力让Java程序运行起来. 解释器JVM启动时,会依据预约义的标准对字节码采纳逐行解释的形式执行,将每条字节码文件中的内容编译为对应平台的本地机器指令执行.(重点:不须要期待编译,立刻执行,但执行须要逐行解释) JIT编译器JVM将字节码间接编译成和本地机器平台相干的机器语言,加载热点代码.(重点:有个编译的过程须要期待,但执行速度快) 为什么要有编译器还要有解释器?因为解释器须要每一行指令都去翻译,这样效率十分低下。只能是那些一开始曾经确定好的程序,当程序启动的时候,解释器能够马上应用,省去编译的工夫,立刻执行。而编译器,编译的工夫远远大于解释器,尽管能够很好防止函数被解释执行,而是将整个函数体编译成为机器码,每次函数执行时,只执行编译后的机器码即可,这种形式能够使执行效率大幅度晋升。所以各有利弊,在不同的场景能够应用。 设置程序执行办法默认状况下JVM采纳解释器和即时编译器并存的架构,当然也能够依据具体的利用场景,通过配置命令的形式指定JVM齐全采纳解释器执行,还是齐全采纳即时编译器执行.-Xint: 齐全采纳解释器模式-Xcomp: 齐全采纳即时编译器模式执行程序-Xmixed: 默认模式如图: 热点探测JVM会依据代码被调用的频率来判断这块代码或这行代码是否是热点代码,如果达到肯定阈值则会被JIT编译器探测到,而后将其间接编译为对应平台的本地机器指令,以此晋升java程序的执行性能.能够通过配置指令形式 -XX:CompileThreshold=10000 设置对应阈值,默认值为10000,如图: 热度衰减办法调用计数器统计并不是办法被调用的相对次数,而是一个绝对的执行频率,即一段时间之内办法被调用的次数.当超过肯定的工夫限度,如果办法的调用次数依然不足以让它提交给即时编译器编译,那这个办法的调用计数器就会被缩小一半,这个过程称为办法调用计数器热度衰减,而这段时间就称为该办法统计的半衰周期.能够通过 -XX:-UseCounterDecay 来敞开热度衰减,默认是开启的.半衰周期(CounterHalfLifeTime)没有提供指令形式进行设置.查问jdk源码(https://github.com/openjdk/jdk/blob/jdk8-b120/hotspot/src/share/vm/runtime/globals.hpp),该参数为开发参数,默认值为30,单位为秒.如图: 垃圾收集器jdk8有Serial收集器、Parallel收集器、CMS收集器、G1收集器.掂量垃圾收集器的三项重要指标:内存占用、吞吐量和提早.三者独特形成了一个不可能三角.一般来说低提早的垃圾收集器的吞吐量比拟低,高吞吐的垃圾收集器的延迟时间比拟高. 按年老代与老年代应用的垃圾回收器辨别:年老代: serial,parnew,parallel scavenge.老年代: serial old,cms,parallel old. 按提早和吞吐量辨别:低提早优先:cms,g1吞吐量优先:parallel old 按单线程和多线程辨别:单线程:serial,serial old多线程:parnew,cms,parallel scavenge,parallel old,g1 按年老代和老年代组合应用如图:红色虚线局部为jdk8已废除,jdk9已去除,绿色虚线局部jdk14为已废除,CMS在jdk14中已删除. Serial回收器Serial收集器运行示意图: 介绍(1)Serial收集器是最根底、历史最悠久的收集器,已经(在JDK 1.3.1之前)是HotSpot虚拟机新生代收集器的惟一抉择.(2)大家只看名字就可能猜到,这个收集器是一个单线程工作的收集器,它在进行垃圾收集时,必须暂停其余所有工作线程,直到它收集完结. 实用场景小型物理机,运行在客户端模式下的虚拟机,Serial收集器是个不错的抉择,因为没有线程交互的开销,分心做垃圾收集天然能够取得最高的单线程收集效率.能够通过 -XX:+UseSerialGC 开启应用Serial收集器,如图: Parallel回收器Parallel收集器运行示意图: 介绍(1) Parallel与Serial相比,它是一款多线程工作的垃圾收集器,能够充沛的利用cpu资源. (2) 与Parnew相比,它的关注指标是达到一个可管制的吞吐量(吞吐量 = 用户利用程序运行的工夫 / (利用程序运行的工夫 + 垃圾回收的工夫)). (3) Parallel Scavenge和Parallel Old是jdk8默认的垃圾收集器. 实用场景如果对于收集器运作不太理解,手工优化存在艰难的话,应用Parallel Scavenge收集器配合自适应调节策略,把内存治理的调优工作交给虚拟机去实现兴许是一个很不错的抉择。只须要把根本的内存数据设置好(如-Xmx设置最大堆),而后应用-XX:MaxGCPauseMillis参数(更关注最大进展工夫)或-XX:GCTimeRatio(更关注吞吐量)参数给虚拟机设立一个优化指标,那具体细节参数的调节工作就由虚拟机实现了。能够通过 -XX:+UseParallelGC或-XX:+UseParallelOldGC应用Parallel收集器. CMS回收器CMS(Concurrent Mark Sweep)收集器运行示意图: 介绍(1) CMS收集器是以获取最短进展工夫为指标的收集器.(2) CMS收集器是基于标记-革除算法实现的,整个过程能够分为四个步骤:1)初始标记(CMS initial mark)有STW;初始标记仅仅只是标记一下GCRoots能间接关联到的对象,速度很快.2)并发标记(CMS concurrent mark)并发标记阶段就是从GC Roots的间接关联对象开始遍历整个对象图的过程,这个过程耗时较长然而不须要进展用户线程,能够与GC线程一起并发运行.3)从新标记(CMS remark)有STW;从新标记阶段是为了修改并发标记期间,因用户程序持续运作而导致标记产生变动的那一部分对象的标记记录.4)并发革除(CMS concurrent sweep)清理删除掉标记阶段判断的曾经死亡的对象,因为不须要挪动存活对象,所以这个阶段也是能够与用户线程同时并发执行的.STW(stop the world)介绍:示意在垃圾收集器在此工作期间,其余业务线程都会暂停工作,应用程序会有卡顿. 实用场景应用程序比拟重视用户的应用体验,CMS是以获取最短回收进展工夫为指标.能够通过 -XX:+UseConcMarkSweepGC 应用CMS收集器,它是和Parnew收集器组合应用的,如图: ...

August 30, 2023 · 1 min · jiezi

关于java:spring使用Async注解导致循环依赖问题异常的排查

因为布控预警我用到了@async来实现异步操作,在本地跑的时候始终没有报错,可是当我打包到服务器启动的时候却报了一个BeanCurrentlyInCreationException Bean with name 'xxx' has been injected into other beans [xxx2] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.呈现循环依赖报错了,于是我看了一下代码,确实有循环依赖的状况(这个是不好的习惯不要学,这里我之前没留神到,前面能够改一下),然而我记得明明spring是可能解决应用@Autowired注解造成的循环的,并不会导致报错,而且我本地也始终复现不了,十分的奇怪。于是我写了一个spring循环依赖应用@Async的demo并调试,异样代码的产生点在spring的doCreateBean办法 if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else { //如果代理后的对象不等于原始对象就会抛异样了 }@Componentpublic class CircularTest { @Autowired CircularTest2 circularTest2;}@Componentpublic class CircularTest2 { @Autowired CircularTest CircularTest; @Async public void async() { }}开始我的代码是下面这样,spring初始化bean的程序是先CircularTest再CircularTest2,每到初始化CircularTest2执行异样处代码的时候,间接earlySingletonReference返回的是null,所以始终复现不了,这时候我忽然想到是不是spring初始化程序的起因,因为之前也遇到过spring程序不确定的问题,于是我改了一下代码 ...

August 30, 2023 · 1 min · jiezi

关于java:javanethttpHttpClient

一、在应用java自带的HttpClient时, 发现一个景象,即有些以前罕用http的header, 是不可能set到申请里进行传递的,在jdk.internal.net.http.common.Utils类中,能够看到 private static Set<String> getDisallowedHeaders() { Set<String> headers = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); headers.addAll(Set.of("connection", "content-length", "expect", "host", "upgrade")); String v = getNetProperty("jdk.httpclient.allowRestrictedHeaders"); if (v != null) { // any headers found are removed from set. String[] tokens = v.trim().split(","); for (String token : tokens) { headers.remove(token); } return Collections.unmodifiableSet(headers); } else { return Collections.unmodifiableSet(headers); } }connection, content-length, expect, host, upgrade这几个, 属于禁止设置的。因为在jdk.internal.net.http.HttpRequestBuilderImpl中, 会进行严格的校验 private void checkNameAndValue(String name, String value) { requireNonNull(name, "name"); requireNonNull(value, "value"); if (!isValidName(name)) { throw newIAE("invalid header name: \"%s\"", name); } if (!Utils.ALLOWED_HEADERS.test(name, null)) { throw newIAE("restricted header name: \"%s\"", name); } if (!isValidValue(value)) { throw newIAE("invalid header value: \"%s\"", value); } }二、它本人管制连贯的复用,所以设置不了connection这个header.从jdk.internal.net.http.ConnectionPool中能够看出一些参数 ...

August 30, 2023 · 3 min · jiezi

关于java:SM2算法的优势原理和应用场景

在数字化时代,信息安全成为关注的焦点。明码算法是信息安全的外围,而国密算法SM2是一种国产明码算法,曾经广泛应用于电子认证、电子签名、数据加密等畛域。本文将深刻介绍SM2算法的劣势、原理和利用场景,并探讨如何利用FuncGPT(慧函数)生成的SM2库构建平安的应用程序。 一、国密算法SM2概述 国密算法SM2是由国家明码管理局制订的一种非对称明码算法,包含SM2密钥替换、数字签名和公钥加密等三局部。它基于椭圆曲线(ECC)明码实践,具备较高的安全性和效率。 相比于国内支流的RSA算法,SM2算法具备以下劣势:安全性更高:等同平安程度下,SM2的密钥长度和签名长度远远小于RSA,提供更高的安全性和更小的计算开销。效率更高:SM2的加密和解密速度比RSA快,适宜于高并发场景。国产自主:SM2是我国自主设计的明码算法,符合国家明码治理政策,有利于保障国家信息安全。 二、SM2算法原理及利用1、SM2密钥替换SM2密钥替换是基于椭圆曲线(ECC)的一种密钥替换协定。通过替换单方的公钥和私钥,实现密钥的协商和传输。SM2密钥替换具备较高的安全性,能够无效避免中间人攻打。 2、SM2数字签名SM2数字签名是利用私钥对音讯进行签名,而后利用公钥验证签名的过程。SM2数字签名能够确保音讯的完整性和不可否认性,实用于身份认证、数据完整性校验等场景。 3、SM2公钥加密SM2公钥加密是利用公钥对音讯进行加密,而后利用私钥解密的过程。SM2公钥加密能够爱护敏感信息的传输平安,实用于数据加密、电子邮件加密等场景。 三、利用FuncGPT(慧函数)生成SM2 专一AI生成Java函数的FuncGPT(慧函数)是飞算SoFlu软件机器人推出的函数AI 生成器,反对所有类型函数创立,通过自然语言形容Java函数需要,实时生成高质量、高可读性的Java函数代码。生成代码可间接复制到IDEA,或一键导入Java全自动开发工具函数库,从而进步开发者的编码效率。 利用FuncGPT(慧函数)生成SM2的步骤如下: 1、飞算云智官网装置注册飞算SoFlu软件机器人,并配置相应的环境变量。2、签到点击支付FuncGPT慧函数次数,并立刻体验FuncGPT慧函数。3、左侧输入框内输出“对输出的字符串进行国密SM2算法加密”。 // 类名:SM2Encryptor// 函数名:encryptWithSM2// 函数性能:对输出的字符串进行国密SM2算法加密// POM依赖包:// <dependency>// <groupId>org.bouncycastle</groupId>// <artifactId>bcpkix-jdk15on</artifactId>// <version>1.68</version>// </dependency>import org.bouncycastle.crypto.AsymmetricCipherKeyPair;import org.bouncycastle.crypto.InvalidCipherTextException;import org.bouncycastle.crypto.engines.SM2Engine;import org.bouncycastle.crypto.generators.ECKeyPairGenerator;import org.bouncycastle.crypto.params.*;import org.bouncycastle.crypto.signers.SM2Signer;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.bouncycastle.jce.spec.ECParameterSpec;import org.bouncycastle.util.encoders.Hex;import java.security.*;import java.security.spec.ECGenParameterSpec;public class SM2Encryptor { /** * 对输出的字符串进行国密SM2算法加密 * @param inputString 输出的字符串 * @return 加密后的字符串 */ public static String encryptWithSM2(String inputString) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, InvalidCipherTextException { Security.addProvider(new BouncyCastleProvider()); // 生成密钥对 ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("sm2p256v1"); keyPairGenerator.init(new ECKeyGenerationParameters(new ECGenParameterSpec("sm2p256v1"), new SecureRandom())); AsymmetricCipherKeyPair keyPair = keyPairGenerator.generateKeyPair(); // 获取公钥和私钥 ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.getPrivate(); ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic(); // 加密 SM2Engine engine = new SM2Engine(); ParametersWithRandom parameters = new ParametersWithRandom(publicKey, new SecureRandom()); engine.init(true, parameters); byte[] inputBytes = inputString.getBytes(); byte[] cipherBytes = engine.processBlock(inputBytes, 0, inputBytes.length); // 将加密后果转换为十六进制字符串 String cipherString = Hex.toHexString(cipherBytes); return cipherString; }}// 函数示例// 对输出的字符串进行国密SM2算法加密示例// 入参:inputString,输出的字符串// 出参:encryptedString,加密后的字符串// 调用示例:// String inputString = "Hello, World!";// String encryptedString = SM2Encryptor.encryptWithSM2(inputString);// System.out.println(encryptedString);// 输入后果:例如,对输出字符串"Hello, World!"进行国密SM2算法加密,失去的加密后果为:"c8a8a5f6b6b9e8f3d7d4f2d8c3f8a6f7e4b5b6f4e9b4e4c8f2e5b9e9f4c8e5d7e7"// 则输入后果为:"c8a8a5f6b6b9e8f3d7d4f2d8c3f8a6f7e4b5b6f4e9b4e4c8f2e5b9e9f4c8e5d7e7"将FuncGPT(慧函数)生成的这段代码从代码可读性、强壮度等多维度进行剖析,不难发现: ...

August 30, 2023 · 1 min · jiezi

关于java:如何写出一份百发百中的简历

马上就到一年一度的校招季了,近几年程序员行业的招聘堪称是越来越内卷,作为面试的敲门砖,简历的重要性显而易见,明天就认真谈谈简历的方方面面,心愿对大家写简历有所帮忙,愿每个人都能顺利拿到称心的Offer。 简历蕴含哪些内容?一份好的简历总体能够分为以下几个板块, 根本信息教育背景技能列表工作经验我的项目教训其余这个程序能让 HR 从浅到深疾速理解求职者的劣势与技 1. 集体根本信息次要就是姓名/电话/邮箱 ,这几项是必填内容。清晰列举出信息即可,这样HR就不必在接下来的电话沟通或面试中再去诘问这些内容,建设咱们接下来电话沟通对你的相熟度。也能够加上微信作为备选分割计划,免得电话打不通的状况。其次是求职意向,比方Java开发工程师、前端开发工程师、公司首席技术官等等。如果参加了一些开源我的项目或者常常总结分享,能够放上 Github 或者博客链接,因为这能从另一方面突显求职者的编程能力。如果 Github 既没奉献过开源我的项目,一年就 commit 了几次的话就不要放进去了。如果没写过技术博客,或者很久没更新的话,能够在筹备面试的这段时间,每周依据温习的主题写一篇总结性的博客。这样一方面可能通过写文字强化了解温习的内容,为技术面试做好筹备,另一方面也能作为简历的加分项。2. 教育背景这块不用说,就是写你的本科、研究生、博士等阶段的学校和业余。 如果有 高绩点 / 奖学金 / 较量获奖 等能够选重要的加上,比方一些较量的国家级一二等奖、国家奖学金等等。如果你业余排名很靠前,也能够把业余排名写上去。对于校招而言,如果有些专业课问题特地好,比方数据结构、计算机系统等,也能够加上去,体现出你集体的根底很扎实。3. 技能列表技能列表就是向企业展现你会什么,然而这个咱们不能自觉的将所有的技能重叠下来,要依据所求职的岗位来针对性的组织本人的专业技能,将岗位须要的技能联合本人的相熟水平,放在后面;其余不太相干的技能,能够稍往后放或者间接不写进去。 上面我举个例子简略阐明,比方上面是一则招聘布告,外面形容了岗位的需要。从中咱们能够看到, 企业对Spring、数据库、架构、高并发等方面有要求,因而联合咱们本身的工作经验,能够依照如下相似的格局总结: 熟练掌握Java根底、汇合、并发,有JVM排查问题和调优的教训精通Spring MVC、Spring Boot,能够手写实现Spring MVC。纯熟应用JPA、Spring Security等框架。熟练掌握MySQL原理和常见优化伎俩(索引、SQL优化、读写拆散等)相熟常见分布式框架原理,如Dubbo、Kafka、Zookeeper、ES、Redis等相熟云原生部署,把握K8S、Docker等底层原理。 慎用精通,一般来讲,依据对常识的相熟水平,咱们能够应用不同的水平,精通 > 相熟(举荐应用)> 把握(举荐应用)> 理解(举荐应用)。如果对某一个常识或者框架不是了解的十分透彻,肯定不要应用精通,否则可能面试官会针对这个框架进行深刻考查,如果有些知识点答复的不好,就会影响到面试官对你的认识。4. 工作经验工作经验倡议采纳倒序的形式,来介绍本人过来一段时间的工作状况,如果是校招的话,能够换成实习经验。大略的示例如下: 某出名公司 (202X 年 X 月 ~ 202X 年 X 月 ) 职位:Java 后端开发工程师工作内容:次要负责基础架构的设计和实现5. 我的项目教训我的项目教训介绍你的具体我的项目经验,大略交代下我的项目的背景、业务内容即可,多写点技术形容,写分明你在这个我的项目中利用何种技术解决了或者达到了或者实现了什么成果,或者给公司或团队带来了什么收益,或者写你在该我的项目中遇到技术难题的攻关过程,千万不要写相似“通过该我的项目,我学习到了XXX”,企业招你来是干活的不是专门给你学习的。 具体来讲, 能够依据岗位需要和本人的理论工作状况,抉择3-4个相干的我的项目即可,比方这里我以一个分布式爬虫零碎为例来进行介绍。 分布式网络爬虫零碎的设计与实现2022.09 - 2023.06 XX公司Python开发工程师我的项目内容: 作为组长负责设计和开发分布式网络爬虫零碎,优化爬虫策略和防屏蔽规定,晋升网页抓取的效率和品质。应用 Scrapy 框架对爬虫模块进行重构,进步 200% 爬虫速度并缩小服务器 20% CPU负载。优化爬虫策略,升高 80% 被屏蔽的申请数。基于ZK、Redis和MySQL实现了分布式爬虫零碎的外围调度, 实现了URL的排序、散发、调度、任务分配等模块。基于K8s和Docker对整套零碎进行架构拆分和部署,能够依据负载进行实时扩大,同时也实现继续集成与一键自动化部署。注意事项1. 依据工作教训和岗位偏重来写我的项目教训 形容技术栈时针对本人求职的公司职位或者求职意向来写,例如求职开发职位,就弱化一些本人已经做过的一些测试、运维或者项目经理的工作形容;求职后端开发,就要弱化前端相干的技术术语了;求职 Java 开发,就不要在简历中大写特写 C、PHP 等其余语种的我的项目或模块经验。尤其不要写与职位无关的经验,如果存在的话能够一笔带过。 如果工作经验不长,你在我的项目中的角色可能是负责单个服务或者单个服务中的局部模块,此时写我的项目经验时能够多写点技术细节,如网络通信的协定细节、队列数据交换的设计细节、程序对数据加工的细节等等;然而如果你曾经工作三年及以上的高级开发者,刻画我的项目经验时,要偏重写一点对我的项目整体的框架或者架构的认知,如音讯在各个服务中的流转过程、每个服务的作用、外围服务的构造、技术重难点等等。 到这里也揭示大家,不要一份简历到处投递,要依据岗位需要来调整本人的我的项目教训和侧重点,对症下药。2. 学会总结我的项目难点疏导面试 简直在我经验过的所有面试中,在介绍完我的项目的大抵内容之后,面试官都会问我同样一个问题,"我的项目的难点在哪里?", 针对这个问题,咱们在总结我的项目的时候,要提前认真思考一下我的项目中有哪些性能比较复杂?哪些性能花了很长时间才解决?有时候难点不肯定是十分大的性能或者改变,你只有找到我的项目中的一点,深挖上来就会遇到难点,解决它,这种经验就能够拿来在面试中来说了。 另外咱们在实现一个我的项目之后,能够及时的总结以后我的项目中遇到的艰难和问题,以及本人是如何解决的,省得等到真要找工作的时候,才发现很多货色都忘了,得从新剖析整顿我的项目。 ...

August 29, 2023 · 1 min · jiezi

关于java:我想的反射

何谓反射?如果说大家钻研过框架的底层原理或者咱们本人写过框架的话,肯定对反射这个概念不生疏。反射之所以被称为框架的灵魂,次要是因为它赋予了咱们在运行时剖析类以及执行类中办法的能力。通过反射你能够获取任意一个类的所有属性和办法,你还能够调用这些办法和属性。 反射的优缺点?反射能够让咱们的代码更加灵便、为各种框架提供开箱即用的性能提供了便当。不过,反射让咱们在运行时有了剖析操作类的能力的同时,也减少了平安问题,比方能够忽视泛型参数的安全检查(泛型参数的安全检查产生在编译时)。另外,反射的性能也要稍差点,不过,对于框架来说理论是影响不大的。 反射的利用场景?像咱们平时大部分时候都是在写业务代码,很少会接触到间接应用反射机制的场景。然而!这并不代表反射没有用。相同,正是因为反射,你能力这么轻松地应用各种框架。像 Spring/Spring Boot、MyBatis 等等框架中都大量应用了反射机制。这些框架中也大量应用了动静代理,而动静代理的实现也依赖反射。比方上面是通过 JDK 实现动静代理的示例代码,其中就应用了反射类 Method 来调用指定的办法。

August 29, 2023 · 1 min · jiezi

关于java:SpringCache

Spring Cache 教程什么是缓存?缓存是一种长期存储数据的机制,用于在须要时提供快速访问。当数据被频繁读取时,将其存储在缓存中能够防止每次都拜访数据库或其余耗时的资源。 为什么应用缓存?应用缓存能够显著晋升应用程序的性能,缩小响应工夫,升高资源耗费。通过将罕用数据存储在缓存中,能够防止不必要的数据库查问或计算,从而减速数据拜访过程。 Spring Cache 概述Spring Cache是Spring框架提供的一个模块,用于在应用程序中轻松地实现缓存。它形象了底层缓存库,使你能够应用对立的API来进行缓存操作,而不须要关怀具体的缓存实现细节。 反对的缓存库Spring Cache反对多种缓存库,包含: CaffeineEhcacheGuavaRedis...你能够依据我的项目需要抉择适宜的缓存库。 应用 Spring Cache基本概念Spring Cache应用一些外围概念: @Cacheable:用于标记办法的后果应该被缓存。@CacheEvict:用于标记办法的后果应该被从缓存中移除。@CachePut:用于标记办法的后果应该被缓存,但办法会始终执行。@Caching:容许同时利用多个缓存相干的注解。注解@Servicepublic class ProductService { @Cacheable("products") public Product getProductById(Long id) { // ... } @CachePut(value = "products", key = "#product.id") public Product updateProduct(Product product) { // ... } @CacheEvict(value = "products", key = "#id") public void deleteProduct(Long id) { // ... }}缓存配置你能够通过配置类或XML文件来配置缓存。 @Configuration@EnableCachingpublic class CacheConfig { @Bean public CacheManager cacheManager() { return new CaffeineCacheManager("products"); }}缓存的一些注意事项缓存应该仅用于那些被频繁拜访且不常常扭转的数据。在应用缓存时,须要思考缓存过期策略,以确保缓存中的数据不会过期。审慎应用缓存,防止缓存过多数据导致内存耗费问题。

August 29, 2023 · 1 min · jiezi

关于java:829学习总结

1、xml中须要转移的字符在xml写sql有些字符须要本义,如果用上面的形式,能够不必本义也能示意原来的意思 在idea中间接打大写的CD会有补全提醒2、对查问后果排序 降序排序,默认升序order by number desc3、内连贯和笛卡尔积的区别笛卡尔积:selct* from tb1,tb2隐式内连贯:selct* from tb1,tb2 where 判断条件4、一段简略的sql,limit是取前十个查问后果 <select id="getSalesTop10" resultType="com.sky.dto.GoodsSalesDTO"> SELECT od.name,SUM(od.number) number FROM orders o,order_detail od WHERE o.id = od.order_id AND o.status = 5 <if test="beginTime != null"> <![CDATA[ AND o.order_time >= #{beginTime} ]]> </if> <if test="endTime != null"> <![CDATA[ AND o.order_time <= #{endTime} ]]> </if> group by od.name order by number desc limit 10</select>5、应用的apiLocalDateTime.of(LocalDate类型,LocalTime.MIN)获取当天最小的时刻LocalDateTime.of(LocalDate类型,LocalTime.MAX)获取当天最大的时刻 工夫对象目前我晓得的包含LocalDate和LocalDateTime,除了能够加减天数,还能够加减分钟之类的用法一样工夫对象.plusDays(Integer) 给LocalDate对象的工夫加几天工夫对象.minusDays(Integer) 给LocalDate对象的工夫减几天 6、面试题中final、finally、finalize的区别 final 关键字能够用于润饰类、办法和变量。当用于类时,示意该类不可被继承;当用于办法时,示意该办法不可被子类重写;当用于变量时,示意该变量不能被批改(即为常量)。在个别状况下,应用 final 能够进步代码的安全性和稳定性,避免意外被批改。 finally 关键字用于定义一个代码块,在 try-catch-finally 构造中,无论是否产生异样都会执行该代码块中的内容。通常在 finally 中开释资源,如敞开文件或数据库连贯等。 ...

August 29, 2023 · 1 min · jiezi

关于java:深入解析CMS垃圾回收器

本文已收录至GitHub,举荐浏览 Java随想录 微信公众号:Java随想录 原创不易,重视版权。转载请注明原作者和原文链接后面几篇文章都在介绍GC的工作原理,上面开始大家期待的垃圾回收器章节。一共有三篇:CMS、G1和ZGC。 本篇文章先来介绍CMS。 纵观全书《深刻了解JVM虚拟机》第三版,在垃圾回收器这一篇章,对于CMS的笔墨是十分多的。 CMS也是JVM面试的一个重点,只有说起垃圾回收器,CMS能够说不得不问,聊好了,会让面试官感觉你有两把刷子。 话不多说,间接进入正题。 CMS简介CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收进展工夫为指标的收集器。 CMS启用参数:-XX:+UseConMarkSweepGC,CMS是老年代垃圾收集器,应用的是标记-革除算法。 在CMS之前的垃圾回收器,要么就是串行垃圾回收形式,要么就是关注零碎吞吐量,而 CMS 垃圾回收器的呈现,则突破了这个难堪的场面。 CMS收集器是HotSpot虚拟机谋求低进展的第一次胜利尝试,其开启了 GC 回收器关注 GC 进展工夫的历史。 CMS 垃圾回收器之所以可能实现对 GC 进展工夫的管制,其要害是「三色标记算法」(不理解的同学去翻我之前写的文章)。 通过三色标记算法,实现了垃圾回收线程与用户线程并发执行,从而极大地升高了零碎响应工夫。 如果在JDK9之后应用CMS垃圾收集器后,默认年老代就为ParNew收集器,并且不可更改,同时JDK9之后被标记为不举荐应用,JDK14就被删除了。 能够说CMS是垃圾回收器的一个里程碑。 运作过程CMS整个运作过程分为四个大阶段,包含: 初始标记(CMS initial mark)并发标记(CMS concurrent mark)从新标记(CMS remark)并发革除(CMS concurrent sweep)留神:这里说的是四个大阶段,两头还会有其余的过渡小阶段,然而最次要的工夫损耗在这四个阶段上。 其中「初始标记」、「从新标记」这两个步骤依然须要Stop The World,这点是须要留神的。 CMS在各个阶段都做了哪些事呢,别着急,听我缓缓道来。 初始标记这一步依然须要暂停所有的其余线程,但这个阶段会很快实现。它的目标是「标记所有的根对象,以及被根对象间接援用的对象,以及年老代指向老年代的对象」。 也就是说初始标记阶段,只会标记第一层,不会向下追溯去深度遍历。 并发标记在此阶段中,垃圾回收器将遍历对象图,从GC Roots「向下追溯」,标记所有可达的对象。这个过程是四个阶段中耗时最长的,然而不须要进展用户线程,能够与垃圾收集线程一起并发运行。 在此阶段,利用线程与垃圾回收线程是并发运行的。如果利用线程产生了新的对象,并且批改了老年代中的对象援用,那么这些变动可能被并发进行的垃圾回收线程疏忽掉,这就可能造成「漏标」问题,即有些本该被标记的对象没有被标记。 为了解决这个问题,CMS采纳了卡表。 当利用线程试图批改老年代的某个对象援用时,把这些发生变化的对象所在的Card标识为Dirty,这样后续就只须要扫描这些Dirty Card的对象,从而防止扫描整个老年代。 对于卡表,之前在讲跨代援用的时候介绍过,遗记的同学去翻翻我之前写的文章。 并发预处理并发预处理能够通过参数:-XX:-CMSPrecleaningEnabled管制,默认开启。 并发预处理阶段用户线程能够与垃圾回收线程一起执行。 并发预处理目标在于心愿能尽可能减少下一个阶段「从新标记」所耗费的工夫,因为下一个阶段从新标记是须要Stop The World的。 在前个并发阶段中,老年代的对象援用关系可能会发生变化,所以并发预处理这个阶段会扫描可能因为并发标记时导致老年代发生变化的对象,会再扫描一遍标记为Dirty的卡页,并标记被Dirty对象间接或间接援用的对象,而后革除Card标识。 可勾销的并发预处理此阶段也不进行应用程序,本阶段尝试在STW的最终标记阶段之前尽可能多做一些工作。本阶段的具体工夫取决于多种因素,因为它循环做同样的事件,直到满足某个退出条件。 在该阶段,次要循环去做两件事: 解决 From 和 To 区的对象,标记可达的老年代对象。和上一个阶段一样,扫描解决Dirty Card中的对象。在预处理步骤后,如果满足上面这个条件,就会开启可中断的预处理: Eden的应用空间大于-XX:CMSScheduleRemarkEdenSizeThreshold,这个参数的默认值是2M,如果新生代的对象太少,就没有必要执行该阶段,间接执行从新标记阶段。如果满足上面的条件,就会退出循环: ...

August 29, 2023 · 1 min · jiezi

关于java:面试官synchronized-能不能禁止指令重排序大部分人都会答错

指令重排序1、问题形容首先肯定要明确:指令重排序和有序性是不一样的。这一点十分重要。 咱们常常都会这么说: volatile能保障内存可见性、禁止指令重排序然而不能保障原子性。synchronized能保障原子性、可见性和有序性。留神:这里的有序性并不是代表能禁止指令重排序。举个例子: 在双重查看的单例模式中,既然曾经加了synchronized为什么还须要volatile去润饰变量呢?如果synchronized能禁止指令重排,那么齐全能够不必要volatile。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice2、DCL代码字节码剖析指令重排序问题首先须要晓得的知识点:Object obj = new Object();这句代码并不是一个原子操作,他分为三步: 在内存申请一片空间,new 出一个对象调用new出的这个对象的构造方法将这个对象的援用赋值给obja)、DCL双重查看代码public class MySingleton { private static MySingleton INSTANCE; private MySingleton() { } public static MySingleton getInstance() { if (INSTANCE == null) { synchronized (MySingleton.class) { if (INSTANCE == null) { INSTANCE = new MySingleton(); } } } return INSTANCE; }}b)、字节码如下 从字节码中能够看到,new MySingleton();这句代码对应了17、20、21、24这四行字节码(20行是一个援用的拷贝,能够疏忽)。 首先在17行在内存中开拓一块空间创立一个MySingleton对象。而后在21行调用该对象的构造方法。而后在24即将该对象的援用赋值给动态变量INSTANCE。以上是咱们冀望的执行程序,咱们心愿每个线程都依照该程序去执行指令(这就是禁止指令重排序)。然而因为计算机为了进步运行效率,会将咱们的指令程序进行优化重排(比方下面的程序可能会优化重排为:17、24、21) 指令重排序带来的问题 咱们的计算机为了晋升效率,会将咱们的代码程序做一些优化,比方在t1线程中的执行程序是 17、24、21,在t2线程中执行的程序是17、21、24 (在单个线程中不论是那种执行程序都不会有问题)。当t1线程获取到锁执行对象创立的时候,先执行了24行,将该对象的援用赋值给了动态变量INSTANCE(此时对象还没调用构造方法,该对象还不是一个残缺的对象)。此时t2线程开始运行了,当t2线程执行到if (INSTANCE == null)(第16行代码)语句的时候,t2线程发现INSTANCE不为空,此时t2线程间接返回INSTANCE对象。然而此时该对象还是一个不残缺的对象,在t2线程应用该对象的时候就会呈现问题。所以说指令重排序在单线程中是不会有任何问题的,然而一旦波及到多线程的状况,那么指令重排序可能会带来意想不到的后果。 有序性那么既然synchronized不能禁止指令重排序,那么他保障的有序性是什么有序呢? 它的实质是让多个线程在调用synchronized润饰的办法时,由并行(并发)变成串行调用,谁取得锁谁执行。 1、代码示例t1、t2两个线程都须要去获取单例对象,而后调用test办法,并且test办法是加了同步锁的办法。 public class MySingleton { private static MySingleton INSTANCE; private MySingleton() { } public static MySingleton getInstance() { if (INSTANCE == null) { synchronized (MySingleton.class) { if (INSTANCE == null) { INSTANCE = new MySingleton(); } } } return INSTANCE; } public static void test(final MySingleton singleton) { synchronized (MySingleton.class) { System.out.println(singleton); } }}测试代码 ...

August 29, 2023 · 1 min · jiezi

关于java:Spring-Boot-别再用-Date-作为入参了LocalDateTimeLocalDate-真香

作者:TinyThing链接:https://www.jianshu.com/p/b52db905f020 0x0 背景我的项目中应用LocalDateTime系列作为dto中工夫的类型,然而spring收到参数后总报错,为了全局配置工夫类型转换,尝试了如下3中办法。 注:本文基于Springboot2.0测试,如果无奈失效可能是spring版本较低导致的。PS:如果你的Controller中的LocalDate类型的参数啥注解(RequestParam、PathVariable等)都没加,也是会出错的,因为默认状况下,解析这种参数应用ModelAttributeMethodProcessor进行解决,而这个处理器要通过反射实例化一个对象进去,而后再对对象中的各个参数进行convert,然而LocalDate类没有构造函数,无奈反射实例化因而会报错!!! 0x1 当LocalDateTime作为RequestParam或者PathVariable时这种状况要和工夫作为Json字符串时区别对待,因为前端json转后端pojo底层应用的是Json序列化Jackson工具(HttpMessgeConverter);而工夫字符串作为一般申请参数传入时,转换用的是Converter,两者有区别哦。 在这种状况下,有如下几种计划:举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice1. 应用Converterimport org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.convert.converter.Converter;import org.springframework.http.converter.HttpMessageConverter;import java.time.LocalDate;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;@Configurationpublic class DateConfig { @Bean public Converter<String, LocalDate> localDateConverter() { return new Converter<>() { @Override public LocalDate convert(String source) { return LocalDate.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd")); } }; } @Bean public Converter<String, LocalDateTime> localDateTimeConverter() { return new Converter<>() { @Override public LocalDateTime convert(String source) { return LocalDateTime.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); } }; }}以上两个bean会注入到spring mvc的参数解析器(如同叫做ParameterConversionService),当传入的字符串要转为LocalDateTime类时,spring会调用该Converter对这个入参进行转换。2. 应用ControllerAdvice配合initBinder@ControllerAdvicepublic class GlobalExceptionHandler { @InitBinder protected void initBinder(WebDataBinder binder) { binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() { @Override public void setAsText(String text) throws IllegalArgumentException { setValue(LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd"))); } }); binder.registerCustomEditor(LocalDateTime.class, new PropertyEditorSupport() { @Override public void setAsText(String text) throws IllegalArgumentException { setValue(LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); } }); binder.registerCustomEditor(LocalTime.class, new PropertyEditorSupport() { @Override public void setAsText(String text) throws IllegalArgumentException { setValue(LocalTime.parse(text, DateTimeFormatter.ofPattern("HH:mm:ss"))); } }); }}从名字就可以看进去,这是在controller做环切(这外面还能够全局异样捕捉),在参数进入handler之前进行转换;转换为咱们相应的对象。0x2 当LocalDateTime作为Json模式传入这种状况下,如同上文形容,要利用Jackson的json序列化和反序列化来做:@Configurationpublic class JacksonConfig { /** 默认日期工夫格局 */ public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; /** 默认日期格局 */ public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; /** 默认工夫格局 */ public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss"; @Bean public ObjectMapper objectMapper(){ ObjectMapper objectMapper = new ObjectMapper();// objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);// objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE); JavaTimeModule javaTimeModule = new JavaTimeModule(); javaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))); javaTimeModule.addSerializer(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))); javaTimeModule.addSerializer(LocalTime.class,new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))); javaTimeModule.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))); javaTimeModule.addDeserializer(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))); javaTimeModule.addDeserializer(LocalTime.class,new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))); objectMapper.registerModule(javaTimeModule).registerModule(new ParameterNamesModule()); return objectMapper; }}0x3 来个残缺的配置吧Spring Boot 根底就不介绍了,举荐看这个实战我的项目: ...

August 29, 2023 · 5 min · jiezi

关于java:JavaGarbage-Collection-Logging-to-a-File-in-Java

原文https://www.baeldung.com/java-gc-logging-to-file 1. OverviewGarbage collection is a marvel of the Java programming language providing us with automatic memory management. 垃圾回收是 Java 编程语言的一个奇观,它为咱们提供了主动内存治理性能。 Garbage collection hides the details of having to manually allocate and deallocate memory. 垃圾回收暗藏了手动调配和删除内存的细节。 While this mechanism is fantastic, sometimes it doesn't work the way we want. 尽管这种机制十分好,但有时并不能如咱们所愿。 In this tutorial, we'll explore Java's logging options for garbage collection statistics and discover how to redirect these statistics to a file. 在本教程中,咱们将摸索 Java 的垃圾收集统计日志选项,并理解如何将这些统计信息重定向到文件。 ...

August 29, 2023 · 3 min · jiezi

关于java:Spring是如何解决循环依赖的

三级缓存思维Spring 解决循环依赖的外围就是提前裸露对象,而提前裸露的对象就是搁置于第二级缓存中。下表是三级缓存的阐明: 所有被 Spring 治理的 Bean,最终都会寄存在 singletonObjects 中,这外面寄存的 Bean 是经验了所有生命周期的(除了销毁的生命周期),残缺的,能够给用户应用的。 earlySingletonObjects 寄存的是曾经被实例化,然而还没有注入属性和执行 init 办法的 Bean。 singletonFactories 寄存的是生产 Bean 的工厂。 解决循环依赖Spring 是如何通过下面介绍的三级缓存来解决循环依赖的呢?这里只用 A,B 造成的循环依赖来举例: 实例化 A,此时 A 还未实现属性填充和初始化办法(@PostConstruct)的执行,A 只是一个半成品。为 A 创立一个 Bean 工厂,并放入到 singletonFactories 中。发现 A 须要注入 B 对象,然而一级、二级、三级缓存均为发现对象 B。实例化 B,此时 B 还未实现属性填充和初始化办法(@PostConstruct)的执行,B 只是一个半成品。为 B 创立一个 Bean 工厂,并放入到 singletonFactories 中。发现 B 须要注入 A 对象,此时在一级、二级未发现对象 A,然而在三级缓存中发现了对象 A,从三级缓存中失去对象 A,并将对象 A 放入二级缓存中,同时删除三级缓存中的对象 A。(留神,此时的 A 还是一个半成品,并没有实现属性填充和执行初始化办法)将对象 A 注入到对象 B 中。对象 B 实现属性填充,执行初始化办法,并放入到一级缓存中,同时删除二级缓存中的对象 B。(此时对象 B 曾经是一个成品)对象 A 失去对象 B,将对象 B 注入到对象 A 中。(对象 A 失去的是一个残缺的对象 B)对象 A 实现属性填充,执行初始化办法,并放入到一级缓存中,同时删除二级缓存中的对象 A。咱们从源码中来剖析整个过程: ...

August 28, 2023 · 3 min · jiezi

关于java:Spring-MVC-四Context层级

这一节咱们来答复上篇文章中避而不谈的无关什么是RootApplicationContext的问题。 这就须要引入Spring MVC的无关Context Hierarchy的问题。Context Hierarchy意思就是Context层级,既然说到Context层级,阐明在Spring MVC我的项目中,可能存在不止一个Context。 Context是上下文的意思,咱们能够间接了解为容器,上一篇文章咱们提到了ServletApplicationContext的概念,能够了解为Servlet容器。 除此之外,Spring我的项目中必定还有有IoC容器,咱们明天就来聊一下这两个容器之间的关系。 为什么须要容器咱们能够这样了解:但凡具备生命周期的对象,也就是说对象并不是在以后现成创立、应用实现之后就销毁的,而是在以后现成应用实现之后不销毁、其余线程还须要持续应用的。这中对象就须要一个容器来保留。 比方Spring的单例Bean,在Spring初始化的过程中就会创立并存入Ioc容器,之后利用应用过程中从Ioc容器中获取。 Servlet对象(比方DispatchServlet)也是这样,在Web利用初始化的过程中创立,Controller、ViewResolver、ExceptionHandler等对象随之也实现创立,这些对象在整个利用的生命周期中会重复应用,因而,Servlet也必须要有一个容器来存储。 Spring把容器称之为上下文,Context。 咱们能够把Servlet容器叫做WebApplicationContext,因为Servlet的呈现就是为了解决Web利用的,所以自然而然的,咱们能够把Servlet容器称为WebApplicationContext。 绝对应的,Spring Ioc容器,咱们能够称之为RootApplicationContext:根容器。 Servlet和根容器的关系下图高深莫测的阐明了两者之间的关系: Servlet容器寄存Controller、VIewResolver、HanderMapping等DispatcherServlet的相干对象,根容器能够寄存其余Service、Repositories等对象。 一个DispatcherServlet能够对应的有一个Servlet容器,一个Web利用能够有多个DispatcherServlet(这种利用其实比拟少见),所以一个利用能够有多个Servlet容器。然而个别状况下,即便有多个Servlet容器,一个利用也心愿只有一个根容器,以便在不同的Servlet容器之间共享根容器的对象。 举例咱们上面用几个例子来阐明两者之间的关系。 还是延用上一篇文章的例子,并做如下简略的革新。 首先,减少一个单例bean,以便启用Spring IoC容器。咱们只是简略引入IoC容器,单例bean不须要太简单, package org.example.service;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationContext;import org.springframework.stereotype.Component;@Componentpublic class UserService { @Autowired ApplicationContext app; public String getUserInfo(){ System.out.println(" application in UserService:"+ app); return "This is userinfo...from UserService..."; }}只有一个办法,返回String。不过为了能阐明以后单例Bean所处的容器,咱们通过@Autowired引入ApplicationContext对象(心愿大家还记得这一点,咱们后面讲过通过什么样的形式,可能在利用中拿到Bean所处的Application对象),这样的话咱们就可能晓得以后Spring利用的Ioc容器具体是哪个对象。 其次,咱们须要新增一个Spring Ioc容器的配置类,咱们称之为RootConfiguration,配置类仅指定扫描门路即可: import org.springframework.context.annotation.Configuration;@Configuration@ComponentScan("org.example.service")public class RootConfiguration {}最初,Controller革新一下,与UserService一样,引入ApplicationContext(Controller中的ApplicationContext,咱们能够人为他就是Servlet容器),log打印一下具体的Context,同时咱们打印一下以后Servlet容器的父容器: package org.example.controller;import org.example.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationContext;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.servlet.DispatcherServlet;import org.springframework.web.servlet.ModelAndView;@Controllerpublic class HelloWorldController { @Autowired UserService userService; @Autowired ApplicationContext app; @GetMapping("/hello") @ResponseBody public String hello(ModelAndView model){ DispatcherServlet d; String userInfo = userService.getUserInfo(); System.out.println("app in controller:"+app); System.out.println("servletContext's parent Context"+app.getParent()); return "<h1>"+userInfo+"</h1>"; }}OK,筹备工作实现,开始验证。 ...

August 28, 2023 · 2 min · jiezi

关于java:Spring-Task是什么

1.Spring Task是什么?Spring Task是Spring框架中用于解决定时工作的模块。它容许代码在特定的工夫距离或者指定的工夫点执行工作。咱们能够通过配置注解或者应用XML文件来定义和治理定时工作。 定位:定时工作框架作用:定时主动执行某段Java代码 Spring Task提供了@Scheduled、和@EnableScheduling以及其余注解。咱们能够应用@Scheduled注解来标记一个办法,指定它的执行工夫。@EnableScheduling注解用于启用定时工作的反对。 上面是一个应用@Scheduled注解的例子: /** * 解决超时工作 */@Scheduled(cron = "0 * * * * ?")public void delete(){ log.info("解决超时工作:{}", new Date());}通过Spring Task,咱们能够不便地在Spring应用程序中执行定时工作,能够依据本人的需要来配置定时工作的执行工夫和频率。

August 28, 2023 · 1 min · jiezi

关于java:SpringCatch

SpringCatch起步依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId> <version>2.7.3</version></dependency>在SpringCache中提供了很多缓存操作的注解,常见的是以下的几个:@EnableCaching:开启缓存注解性能,通常加在启动类上@CachePut:将办法的返回值放到缓存中@CacheEvict:将一条或多条数据从缓存中删除@Cacheable:在办法执行前先查问缓存中是否有数据,如果有数据,则间接返回缓存数据;如果没有缓存数据,调用办法并将办法返回值放到缓存中 @CachePut 阐明: 作用: 将办法返回值,放入缓存 value: 缓存的名称, 每个缓存名称上面能够有很多key key: 缓存的key ----------> 反对Spring的表达式语言SPEL语法 @Cacheable 阐明: 作用: 在办法执行前,spring先查看缓存中是否有数据,如果有数据,则间接返回缓存数据;若没有数据,调用办法并将办法返回值放到缓存中 value: 缓存的名称,每个缓存名称上面能够有多个key key: 缓存的key ----------> 反对Spring的表达式语言SPEL语法 @CacheEvict 阐明: 作用: 清理指定缓存 value: 缓存的名称,每个缓存名称上面能够有多个key key: 缓存的key ----------> 反对Spring的表达式语言SPEL语法在 delete 办法上加注解@CacheEvict

August 28, 2023 · 1 min · jiezi

关于java:如何用-Nginx-代理-MySQL-连接并限制可访问-IP

起源:toutiao.com/article/7234104886726705716 1.前言咱们的生产环境基本上都部署在云服务器上,例如应用服务器、MySQL服务器等。如果MySQL服务器间接裸露在公网,就会存在很大的危险,为了保障数据安全,MySQL服务器的端口是不对外开放的。 好巧不巧,线上业务遇到bug了,开发的小伙伴须要近程连贯MySQL来查看数据,那应该怎么办呢? 咱们能够通过Nginx代理(“跳板机”)来进行连贯。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice2.Nginx代理连贯要实现对连贯的代理转发,咱们须要一台服务器并装置Nginx,且与MySQL服务器处于一个内网之中,内网之间能够拜访。 其次,咱们须要用到ngx_stream_core_module模块,该模块不是默认构建的,咱们须要在configure时增加--with-stream来进行构建。 增加过程能够参照【Nginx根本命令&不停机版本升级】一文进行,咱们这里不再赘述。 既然要用到ngx_stream_core_module模块,首当其冲,是看看其提供的指令,咱们才晓得怎么来进行配置。 1)stream该指令定义了stream服务器。与http块平级,定义在main块中。 作用域:main语法:stream {...}示例: stream { server { ...... } }2)server该指令定义一个虚拟主机,与http块中的server相似。咱们能够在stream块中定义多个server块。 作用域:stream语法:server {...}stream { server { ...... } server { ...... } }3)listen该指令定义虚拟主机server要监听的socket的地址和端口。 作用域:server语法:listen address:port;示例: listen 127.0.0.1:3306; listen *:3306; # 成果与listen *:3306一样 listen 3306; listen localhost:3306;4)配置示例MySQL服务器,端口3306(单机环境) stream { server { listen 3306; proxy_pass 192.168.110.101:3306; } }MySQL服务器,端口3306(集群环境) stream { upstream mysql_socket { server 192.168.110.101:3306; } server { listen 3306; proxy_pass mysql_socket; } }此时,咱们就能够通过例如Navicat等客户端进行连贯。 ...

August 28, 2023 · 1 min · jiezi

关于java:从原理聊JVM五JVM的编译过程和优化手段-京东云技术团队

一、前端编译前端编译就是将Java源码文件编译成Class文件的过程,编译过程分为4步: 1 筹备初始化插入式注解处理器(Annotation Processing Tool)。 2 解析与填充符号表将源代码的字符流转变为标记(Token)汇合,结构出形象语法树(AST)。 形象语法树每个节点都代表着程序代码中的一个语法结构,蕴含包、类型、修饰符、运算符、接口、返回值、代码正文等内容。 编译器的后续行为都是基于形象语法树来进行。 符号表能够了解为一个K-V构造的汇合,存储了以下信息: 变量名和常量过程和函数名称文字常量和字符串编译器生成的临时文件源语言中的标签编译器在运行过程中会通过符号表来不便查找所有标识。 3 注解处理器注解处理器能够看做是一组编译器的插件,用来读写形象语法树中任意元素。 简略来说,注解处理器的作用就是让编译器对特定注解执行特定逻辑,个别用来生成代码,比方罕用的lombok和mapstruct都是基于此。 如果在这期间语法树被批改了,编译器将回到“解析与填充符号表”的过程重新处理,这个循环被称作“轮次(Round)”。 这是开发人员惟一能管制编译器行为的形式。 4 剖析与字节码生成前置步骤能够胜利生成一个构造正确的语法树,语义剖析则是校验语法树是否合乎逻辑。 语义剖析又分为四步: 4.1 标注查看标注查看次要用来检查表量是否被申明、变量与赋值是否匹配等等。 在这个阶段,还会进行被称作“常量折叠”的优化,比方Java代码int a = 1 + 2;,理论编译后会被折叠为int a = 3; 4.2 数据及控制流剖析数据流剖析和控制流剖析是对程序上下文逻辑更进一步的验证,它能够查看出诸如程序局部变量在应用前是否有赋值、办法的每条门路是否都有返回值、是否所有的受查异样都被正确处理了等问题。 4.3 解语法糖Java中存在十分多的语法糖用来简化代码实现,比方主动的装箱拆箱、泛型、变长参数等等。这些语法糖会在编译器被还原为根底语法结构,这个过程被称为解语法糖。 4.4 字节码生成这是javac编译过程的最终阶段,编译器会在这个阶段把后面生成的形象语法树、符号表生成为class文件,还进行了大量的代码增加和转换。 二、运行时编译运行时编译的次要目标是为了将代码编译成本地代码,从而节俭解释执行的工夫。 然而JVM并不是启动后立即开始执行编译,而是为了执行效率先进行解释执行。等到程序运行过程中,依据热点探测,找出热点代码后,对其进行针对性的编译来逐步代替解释执行。所以HotSpot JVM采纳的是解释器和即时编译器并存的架构。 1 应用编译执行的机会Sun JDK次要依据办法上的一个计数器来计算是否超过阈值,如果超过则采纳编译执行的形式。 调用计数器记录办法调用次数,在client模式下默认为1500次,在server模式下默认为10000次,可通过-XX:CompileThreshold=10000来设置 回边计数器循环执行局部代码的执行次数,默认在client模式时为933,在server模式下为140,可通过-XX:OnStackReplacePercentage=140来设置 2 编译模式在编译上,Sun JDK提供两种模式:client compiler(-client)和server compiler(-server) 2.1 Client compiler又称C1,较为轻量级,次要包含以下几方面: 2.1.1 办法内联编译器所做最重要的优化是办法内联遵循面向对象设计,属性拜访通常通过setter/getter办法而非间接调用,而此类办法调用的开销很大,特地是绝对办法的代码量而言。 当初的JVM通常都会用内联代码的形式执行这些办法,举个例子: Order o = new Order();o.setTotalAmount(o.getOrderAmount() * o.getCount());而编译后的代码实质上执行的是: Order o = new Order();o.orderAmount = o.orderAmount * o.count;内联默认是开启的,可通过-XX:-Inline敞开,然而因为它对性能影响微小,并不倡议敞开。 ...

August 28, 2023 · 1 min · jiezi

关于java:面试官如何遍历-Redis-中的海量数据

起源:https://www.toutiao.com/article/6697540366528152077/ 前言有时候咱们须要晓得线上的redis的应用状况,尤其须要晓得一些前缀的key值,让咱们怎么去查看呢?明天给大家分享一个小知识点! 事变产生因为咱们的用户token缓存是采纳了【user_token:userid】格局的key,保留用户的token的值。咱们运维为了帮忙开发小伙伴们查一下线上当初有多少登录用户。 间接用了keys user_token*方式进行查问,事变就此产生了。导致redis不可用,假死。 剖析起因咱们线上的登录用户有几百万,数据量比拟多;keys算法是遍历算法,复杂度是O(n),也就是数据越多,工夫复杂度越高。 数据量达到几百万,keys这个指令就会导致 Redis 服务卡顿,因为 Redis 是单线程程序,程序执行所有指令,其它指令必须等到以后的 keys 指令执行完了才能够持续。 解决方案那咱们如何去遍历大数据量呢?这个也是面试常常问的。咱们能够采纳redis的另一个命令scan。咱们看一下scan的特点 1、复杂度尽管也是 O(n),然而它是通过游标分步进行的,不会阻塞线程 2、提供 count 参数,不是后果数量,是redis单次遍历字典槽位数量(约等于) 3、同 keys 一样,它也提供模式匹配性能; 4、服务器不须要为游标保留状态,游标的惟一状态就是 scan 返回给客户端的游标整数; 5、返回的后果可能会有反复,须要客户端去反复,这点十分重要; 6、单次返回的后果是空的并不意味着遍历完结,而要看返回的游标值是否为零 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice一、scan命令格局 SCAN cursor [MATCH pattern] [COUNT count]二、命令解释:scan 游标 MATCH <返回和给定模式相匹配的元素> count 每次迭代所返回的元素数量 SCAN命令是增量的循环,每次调用只会返回一小部分的元素。所以不会让redis假死 SCAN命令返回的是一个游标,从0开始遍历,到0完结遍历 三、举例 redis > scan 0 match user_token* count 5 1) "6" 2) 1) "user_token:1000" 2) "user_token:1001" 3) "user_token:1010" 4) "user_token:2300" 5) "user_token:1389"从0开始遍历,返回了游标6,又返回了数据,持续scan遍历,就要从6开始 redis > scan 6 match user_token* count 5 1) "10" 2) 1) "user_token:3100" 2) "user_token:1201" 3) "user_token:1410" 4) "user_token:5300" 5) "user_token:3389"总结这个是面试常常会问到的,也是咱们小伙伴在工作的过程常常用的,个别小公司,不会有什么问题,但数据量多的时候,你的操作形式不对,你的绩效就会被扣哦,哈哈。谢谢!!! ...

August 28, 2023 · 1 min · jiezi

关于java:Configuration-注解的-Full-模式和-Lite-模式

@Configuration 注解置信各位小伙伴常常会用到,然而大家晓得吗,这个注解有两种不同的模式,一种叫做 Full 模式,另外一种则叫做 Lite 模式。 精确来说,Full 模式和 Lite 模式其实 Spring 容器在解决 Bean 时的两种不同行为。 这两种不同的模式在应用时候的体现齐全不同,明天松哥就来和各位小伙伴捋一捋这两种模式。 1. 概念梳理首先咱们先来看一下 Spring 官网文档中对 Full 模式和 Lite 模式的一个介绍: 截图来自:https://docs.spring.io/spring-framework/reference/core/beans/... 这个文档次要讲了这样几件事件: 咱们能够通过在一个办法上增加 @Bean 注解,进而将该办法的返回值裸露给 Spring 容器,在这种场景下,@Bean 注解实际上就是一种通用的工厂办法机制。当一个增加了 @Bean 注解的办法位于一个没有增加 @Configuration 注解的类里边时,那么这个增加了 @Bean 注解的办法在解决时就会依照 Lite 模式来解决。当一个 Bean 被申明在增加了 @Component 注解的类中,那么会依照 Lite 模式来解决。当一个 Bean 被申明在一个一般的类中时(plain old class),依照 Lite 模式来解决(这一点感觉和第二点差不多)。在 Lite 模式下,@Bean 注解标记的办法最终不会被 CGLIB 进行代理,就是一个一般的工厂办法,因而,在 @Bean 标记的办法中,不能调用其余 @Bean 注解标记的办法,如果有须要,能够通过办法参数注入本人所须要的 Bean。因为 Lite 模式下并不会应用 CGLIB,因而 @Bean 标记的办法能够是 final 类型的。在大多数场景下,咱们在一个 @Configuration 注解标记的类中,应用 @Bean 注解向 Spring 容器注册一个 Bean,都是 Full 模式。官网文档的介绍还是有些形象,接下来松哥通过具体的案例来和大家演示 Full 模式和 Lite 模式的差异。 ...

August 28, 2023 · 3 min · jiezi

关于java:Spring-Boot-3-大版本齐发Java-8-版本马上要退出历史舞台了

Spring Boot 太狠了,明天一次性公布了三个次要版本,三条版本线同时更新: Spring Boot 3.1.3Spring Boot 3.0.10Spring Boot 2.7.15 三条线次要都是 bug 修复、性能加强、文档改良和依赖降级。 这三个版本次要有什么区别呢? Spring Boot 3.1.x 和 3.0.x 区别不大,但 2.7.x 和 3.x 对环境的影响还是挺大的,特地是 Spring Boot 3.0 对 JDK 17、Servlet 5.0、Spring 6.0 的反对。 栈长理一下 Spring Boot 的依赖关系: Spring Boot3.1.33.0.102.7.15JDK17 - 2017 - 208 - 20Servlet5.0+5.0+3.1, 4.0Spring6.0.11+6.0.11+5.3.29+Maven3.6.3+3.5+3.5+Gradle7.5+, 8.x7.5+, 8.x6.8.x, 6.9.x, 7.x, 8.x高深莫测了吧,同时,栈长留神到 Spring Boot 2.6.x 版本线曾经进行保护了: 栈长整顿了 Spring Boot 的最新版本反对状况: 版本公布工夫进行保护工夫进行商业反对3.2.x2023-11-232024-11-232026-02-233.1.x2023-05-182024-05-182025-08-183.0.x2022-11-242023-11-242025-02-242.7.x2022-05-192023-11-182025-02-182.6.x2021-12-17已进行2024-02-242.5.x2021-05-20已进行2023-08-242.4.x2020-11-12已进行2023-02-232.3.x2020-05-15已进行已进行2.2.x2019-10-16已进行已进行2.1.x2018-10-10已进行已进行2.0.x2018-03-01已进行已进行1.5.x2017-01-30已进行已进行话说你们用的哪个 Spring Boot 版本?能够来一波投票! 另外,Spring Boot 3.2.x 也在路上了,还有 3 个月也要公布了,到时 2.7.x 也进行保护了,收费保护能用的也就 Spring Boot 3.0 及以上的版本了。 ...

August 28, 2023 · 1 min · jiezi

关于java:SpringSpring-MVCSpring-Boot-有什么用

首先,Spring、Spring MVC和Spring Boot都是Java开发中十分罕用的框架。 Spring是什么?Spring是一个轻量级的Java开发框架,它提供了很多不便的性能和个性,比方依赖注入(DI)、面向切面编程(AOP)、事务管理等。通过Spring,咱们能够更加高效地开发和治理Java应用程序。 Spring MVC是什么?Spring MVC是基于Spring框架的一个模块,用于构建Web应用程序。它采纳MVC(Model-View-Controller)的软件设计模式,将应用程序分为模型(Model)、视图(View)和控制器(Controller),通过申请-响应模型来解决Web申请和生成响应。通过三层架构,咱们能够更不便的进行业务的剖析与解决. Spring Boot是什么?Spring Boot是一个疾速开发和部署Spring应用程序的工具。它简化了Spring应用程序的配置和部署过程,并提供了一套开箱即用的默认配置,使得开发者能够专一于业务逻辑的实现,而不须要过多关注繁琐的配置。Spring Boot还集成了嵌入式容器,能够不便地将应用程序打包为可执行的JAR文件,并疾速运行。

August 27, 2023 · 1 min · jiezi

关于java:线程池简要解释

如果咱们正当的应用线程池,则能够防止把零碎搞崩的困境。总得来说,应用线程池能够带来以下几个益处: 1、升高资源耗费。通过反复利用已创立的线程,升高线程创立和销毁造成的耗费。 2、进步响应速度。当工作达到时,工作能够不须要等到线程创立就能立刻执行。 3、减少线程的可管理型。线程是稀缺资源,应用线程池能够进行统一分配,调优和监控。 线程池的外围属性有哪些?threadFactory(线程工厂):用于创立工作线程的工厂。 corePoolSize(外围线程数):当线程池运行的线程少于 corePoolSize 时,将创立一个新线程来解决申请,即便其余工作线程处于闲暇状态。 workQueue(队列):用于保留工作并移交给工作线程的阻塞队列。 maximumPoolSize(最大线程数):线程池容许开启的最大线程数。 handler(回绝策略):往线程池增加工作时,将在上面两种状况触发回绝策略:1)线程池运行状态不是 RUNNING;2)线程池曾经达到最大线程数,并且阻塞队列已满时。 keepAliveTime(放弃存活工夫):如果线程池以后线程数超过 corePoolSize,则多余的线程闲暇工夫超过 keepAliveTime 时会被终止。 常见的阻塞队列有以下几种: ArrayBlockingQueue:基于数组构造的有界阻塞队列,按先进先出对元素进行排序。 LinkedBlockingQueue:基于链表构造的有界/无界阻塞队列,按先进先出对元素进行排序,吞吐量通常高于 ArrayBlockingQueue。Executors.newFixedThreadPool 应用了该队列。 常见回绝策略有以下几种: AbortPolicy:停止策略。默认的回绝策略,间接抛出 RejectedExecutionException。调用者能够捕捉这个异样,而后依据需要编写本人的解决代码。 DiscardPolicy:摈弃策略。什么都不做,间接摈弃被回绝的工作。 DiscardOldestPolicy:摈弃最老策略。摈弃阻塞队列中最老的工作,相当于就是队列中下一个将要被执行的工作,而后从新提交被回绝的工作。如果阻塞队列是一个优先队列,那么“摈弃最旧的”策略将导致摈弃优先级最高的工作,因而最好不要将该策略和优先级队列放在一起应用。 CallerRunsPolicy:调用者运行策略。在调用者线程中执行该工作。该策略实现了一种调节机制,该策略既不会摈弃工作,也不会抛出异样,而是将工作回退到调用者(调用线程池执行工作的主线程),因为执行工作须要肯定工夫,因而主线程至多在一段时间内不能提交工作,从而使得线程池有工夫来解决完正在执行的工作。 终止线程池次要有两种形式: shutdown:“温顺”的敞开线程池。不承受新工作,然而在敞开前会将之前提交的工作处理完毕。 shutdownNow:“粗犷”的敞开线程池,也就是间接敞开线程池,通过 Thread#interrupt() 办法终止所有线程,不会期待之前提交的工作执行结束。然而会返回队列中未解决的工作。 要想正当的配置线程池大小,首先咱们须要辨别工作是计算密集型还是I/O密集型。 对于计算密集型,设置 线程数 = CPU数 + 1,通常能实现最优的利用率。 对于I/O密集型,网上常见的说法是设置 线程数 = CPU数 * 2 ,这个做法是能够的,但集体感觉不是最优的。 在咱们日常的开发中,咱们的工作简直是离不开I/O的,常见的网络I/O(RPC调用)、磁盘I/O(数据库操作),并且I/O的等待时间通常会占整个工作解决工夫的很大一部分,在这种状况下,开启更多的线程能够让 CPU 失去更充沛的应用,一个较正当的计算公式如下: 线程数 = CPU数 CPU利用率 (工作等待时间 / 工作计算工夫 + 1) 例如咱们有个定时工作,部署在4核的服务器上,该工作有100ms在计算,900ms在I/O期待,则线程数约为:4 1 (1 + 900 / 100) = 40个。 当然,具体咱们还要结合实际的应用场景来思考。如果要求比拟准确,能够通过压测来获取一个正当的值。

August 27, 2023 · 1 min · jiezi

关于java:Spring-MVC-三-基于注解配置

Servlet3.0Servlet3.0是基于注解配置的实践根底。 Servlet3.0引入了基于注解配置Servlet的标准,提出了可拔插的ServletContext初始化形式,引入了一个叫ServletContainerInitializer的接口。 An instance of the ServletContainerInitializer is looked up via the jar services API by the container at container / application startup time. The framework providing an implementation of the ServletContainerInitializer MUST bundle in the META-INF/services directory of the jar file a file called javax.servlet.ServletContainerInitializer, as per the jar services API, that points to the implementation class of the ServletContainerInitializer.Servlet3.0标准约定:WEB容器(比方tomcat)要通过SPI的形式查看利用jar包的META-INF/services目录下的Servlet容器的初始化类(ServletContainerInitializer接口的实现类),通过调用该实现类的onStartup办法实现Servlet容器的初始化。 此外,Servlet3.0还引入了@HandlesTypes注解,用来指定Servlet容器初始化过程中,WEB容器会认为利用中的哪些类(由@HandlesTypes指定)会参加到Servlet容器的初始化过程中来。 SpringMVC正是通过以上形式实现Servlet容器的初始化的!!! SpringMVC Servlet容器初始化过程依照上述实践的指引,探索注解形式配置Spring MVC的原理就没那么艰难了。 先看下图:很容易的,咱们发现SpringMVC指定的Servlet容器初始化的实现类为org.springframework.web.SpringServletContainerInitializer。 所以咱们找到他看看: @HandlesTypes(WebApplicationInitializer.class)public class SpringServletContainerInitializer implements ServletContainerInitializer {}的确是ServletContainerInitializer接口的实现类,@HandlesTypes指定的是WebApplicationInitializer,这个WebApplicationInitializer到底是个啥东东,咱们先放放,咱们先来钻研一下 SpringServletContainerInitializer类的onStartup办法。 ...

August 27, 2023 · 2 min · jiezi

关于java:Kafka为什么这么快

Kafka 是一个基于公布-订阅模式的音讯零碎,它能够在多个生产者和消费者之间传递大量的数据。Kafka 的一个显著特点是它的高吞吐率,即每秒能够解决百万级别的音讯。那么 Kafka 是如何实现这样高得性能呢?本文将从七个方面来剖析 Kafka 的速度劣势。 零拷贝技术仅可追加日志构造音讯批处理音讯批量压缩消费者优化未刷新的缓冲写入GC 优化以下是对本文中应用得一些英文单词得解释: Broker:Kafka 集群中的一台或多台服务器统称 broker Producer:音讯生产者 Consumer:音讯消费者 zero copy:零拷贝 1. 零拷贝技术零拷贝技术是指在读写数据时,防止将数据在内核空间和用户空间之间进行拷贝,而是间接在内核空间进行数据传输。对于 Kafka 来说,它应用了零拷贝技术来减速磁盘文件的网络传输,以进步读取速度和升高 CPU 耗费。下图阐明了数据如何在生产者和消费者之间传输,以及零拷贝原理。 步骤 1.1~1.3:生产者将数据写入磁盘 步骤 2:消费者不应用零拷贝形式读取数据2.1:数据从磁盘加载到 OS 缓存 2.2:将数据从 OS 缓存复制到 Kafka 应用程序 2.3:Kafka 应用程序将数据复制到 socket 缓冲区 2.4:将数据从 socket 缓冲区复制到网卡 2.5:网卡将数据发送给消费者 步骤 3:消费者以零拷贝形式读取数据3.1:数据从磁盘加载到 OS 缓存 3.2:OS 缓存通过 sendfile() 命令间接将数据复制到网卡 3.3:网卡将数据发送到消费者 能够看到,零拷贝技术防止了多余得两步操作,数据间接从OS 缓存复制到网卡再到消费者。这样做的益处是极大地提高了I/O效率,升高了CPU和内存的耗费。 举荐博主开源的 H5 商城我的项目waynboot-mall,这是一套全副开源的微商城我的项目,蕴含三个我的项目:经营后盾、H5 商城前台和服务端接口。实现了商城所需的首页展现、商品分类、商品详情、商品 sku、分词搜寻、购物车、结算下单、支付宝/微信领取、收单评论以及欠缺的后盾治理等一系列性能。 技术上基于最新得 Springboot3.0、jdk17,整合了 MySql、Redis、RabbitMQ、ElasticSearch 等罕用中间件。分模块设计、简洁易保护,欢送大家点个 star、关注博主。 github 地址:https://github.com/wayn111/waynboot-mall 2. 仅可追加日志构造Kafka 中存在大量的网络数据长久化到磁盘(生产者到代理)和磁盘文件通过网络发送(代理到消费者)的过程。这一过程的性能会间接影响 Kafka 的整体吞吐量。为了优化 Kafka 的数据存储和传输,Kafka 采纳了一种仅可追加日志构造形式来长久化数据。仅可追加日志构造是指将数据以程序追加(append-only)的形式写入到文件中,而不是进行随机写入或更新。这样做的益处是能够缩小磁盘 I/O 的开销,进步写入速度。 ...

August 27, 2023 · 2 min · jiezi

关于java:Spring-MVC-二-基于xml配置

创立一个基于xml配置的Spring MVC我的项目。 Idea创立新我的项目,pom文件引入依赖: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.12.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.2.12.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.12.RELEASE</version> </dependency>在我的项目的webapp/WEB-INF目录下创立web.xml文件,配置DispatcherServlet: <?xml version="1.0" encoding="UTF-8"?><web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <description>dispatcherServlet</description> <display-name>DispatcherServlet</display-name> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping></web-app>留神其中定义了contextConfigLocation:上下文配置文件地位,配置为:classpath:springmvc.xml,指定Spring MVC启动过程中会到指定地位读取该配置文件,所以咱们须要配置好springmvc.xml文件。 在我的项目resource门路下配置springmvc.xml文件: <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 扫描包 --> <context:component-scan base-package="org.example.controller"/> <!-- 视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 视图前缀 --> <property name="prefix" value="/" /> <!-- 视图后缀 --> <property name="suffix" value=".jsp" /> </bean></beans>次要是指定Spring MVC的controller的包扫描门路,并指定视图解析器、以及视图后缀为jsp。 ...

August 26, 2023 · 1 min · jiezi

关于java:小知识CommunicationsException异常

问题线上在查比较复杂的SQL是,呈现以下报错: Error querying database. Cause: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure\n\nThe last packet successfully received from the server was 10,181 milliseconds ago. The last packet sent successfully to the server was 10,239 milliseconds ago.从报错意思上看,是数据库连贯曾经被敞开了。通过屡次试验确认,只有SQL执行超过10s,就会呈现以上谬误。 起因我的项目是springboot,数据库连接池用的是阿里的druid-spring-boot-starter-1.2.15。如上图所示:JDBC通过socket对字节流进行解决,因而也会有一些根本网络操作,相似于HttpClient这种用于网络操作的代码库;同样的也会受到ConnectTimeout/SocketTime的影响。DruidDataSource有设置以上超时的办法: DruidDataSource dataSource = new DruidDataSource();dataSource.setConnectTimeout(100_000);dataSource.setSocketTimeout(100_000);然而以后零碎并没有设置以上参数,那为什么申请超时10s就会报错?并且以后druid-spring-boot-starter-1.2.15版本并没有socketTime&connetctTimeout配置参数(无奈通过spring.datasource.druid前缀来配置)。通过源码(DruidDatasource类)能够看到以下内容: public class DruidDataSource extends DruidAbstractDataSource implements DruidDataSourceMBean, ManagedDataSource, Referenceable, Closeable, Cloneable, ConnectionPoolDataSource, MBeanRegistration { public void init() throws SQLException { …… // 省略 try { …… // 省略 if (this.jdbcUrl != null) { this.jdbcUrl = this.jdbcUrl.trim(); …… // 省略 initFromUrlOrProperties(); // 从url里解析参数 } if (connectTimeout == 0) { socketTimeout = DEFAULT_TIME_CONNECT_TIMEOUT_MILLIS; // 10_000 } if (socketTimeout == 0) { socketTimeout = DEFAULT_TIME_SOCKET_TIMEOUT_MILLIS; // 10_000 } …… // 省略 } catch (SQLException e) { …… // 省略 } finally { …… // 省略 } }}通过以上源码能够看到,如果没有设置参数值,则会默认设置为10s。持续看initFromUrlOrProperties办法: ...

August 26, 2023 · 2 min · jiezi

关于java:StringStringBufferStringBuilder-的区别

可变性:String 是不可变的。StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是应用字符数组保留字符串,不过没有应用 final 和 private 关键字润饰,最要害的是这个 AbstractStringBuilder 类还提供了很多批改字符串的办法比方 append 办法. 线程安全性String 中的对象是不可变的,也就能够了解为常量,线程平安。AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共办法。StringBuffer 对办法加了同步锁或者对调用的办法加了同步锁,所以是线程平安的。StringBuilder 并没有对办法进行加同步锁,所以是非线程平安的。性能每次对 String 类型进行扭转的时候,都会生成一个新的 String 对象,而后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象自身进行操作,而不是生成新的对象并扭转对象援用。雷同状况下应用 StringBuilder 相比应用 StringBuffer 仅能取得 10%~15% 左右的性能晋升,但却要冒多线程不平安的危险。对于三者应用的总结:操作大量的数据: 实用 String单线程操作字符串缓冲区下操作大量数据: 实用 StringBuilder多线程操作字符串缓冲区下操作大量数据: 实用 StringBuffer

August 26, 2023 · 1 min · jiezi

关于java:SpringIOC

Spring IOC 教程什么是IOC?IOC是Inversion of Control(管制反转)的缩写,它是一种软件设计准则,用于实现组件之间的解耦。在传统的程序设计中,组件通常由程序员手动创立和治理,而在IOC中,控制权被反转,容器负责创立和治理组件,并在须要时将它们注入到其余组件中。 Spring IOC的劣势解耦性:组件之间的依赖关系被Spring容器治理,升高了代码的耦合度。可维护性:组件的创立和治理由容器负责,使得代码更易于保护和扩大。可测试性:组件的依赖关系通过接口注入,不便进行单元测试。灵活性:能够在不批改代码的状况下更改组件的配置。可重用性:组件的复用性进步,能够在不同的我的项目中应用。应用XML配置实现IOC在Spring中,最常见的实现IOC的形式是应用XML配置文件。以下是一个简略的示例: <!-- 创立一个名为"userService"的Bean --><bean id="userService" class="com.example.UserService"> <property name="userRepository" ref="userRepository" /></bean><!-- 创立一个名为"userRepository"的Bean --><bean id="userRepository" class="com.example.UserRepository" />在下面的示例中,userService依赖于userRepository,Spring容器会负责创立并注入这些组件。 应用注解实现IOC除了XML配置,Spring还反对应用注解来实现IOC。以下是应用注解的示例: @Componentpublic class UserService { @Autowired private UserRepository userRepository; // ...}@Repositorypublic class UserRepository { // ...}在这个示例中,通过@Autowired注解,Spring会主动将userRepository注入到userService中。 应用Java配置实现IOC除了XML和注解,还能够应用Java配置类来实现IOC: @Configurationpublic class AppConfig { @Bean public UserService userService() { return new UserService(userRepository()); } @Bean public UserRepository userRepository() { return new UserRepository(); }}依赖注入(DI)的类型Spring反对三种类型的依赖注入:构造函数注入、setter办法注入和接口注入。具体应用哪种取决于你的我的项目需要和代码格调。 AOP(面向切面编程)与IOC的关系AOP是Spring框架的另一个重要概念,它容许你在不批改源代码的状况下,将横切关注点(如日志、事务管理)利用到应用程序中。AOP和IOC密切相关,因为它们都利用了Spring容器来实现。 Spring容器Spring容器负责创立、配置和管理应用程序中的组件。常见的Spring容器有两种:BeanFactory和ApplicationContext。ApplicationContext是BeanFactory的扩大,提供了更多的性能,如国际化、事件流传等。

August 25, 2023 · 1 min · jiezi

关于java:锁的四种状态

synchronized底层synchronized理论没有设想中的那么"轻便"优化JDK 6中为了缩小取得锁和开释锁带来的性能耗费,引入了“偏差锁”和“轻量级锁”。 锁的四种状态锁一共有4种状态,级别从低到高顺次是:无锁、偏差锁、轻量级锁和重量级锁。锁状态只能降级不能降级。 无锁 无锁没有对资源进行锁定,所有的线程都能拜访并批改同一个资源,但同时只有一个线程能批改胜利。 CAS原理及利用即是无锁的实现。无锁无奈全面代替有锁,但无锁在某些场合下的性能是十分高的。 偏差锁 偏差锁是指一段同步代码始终被一个线程所拜访,那么该线程会主动获取锁,升高获取锁的代价。 在大多数状况下,锁总是由同一线程屡次取得,不存在多线程竞争,所以呈现了偏差锁。其指标就是在只有一个线程执行同步代码块时可能进步性能。 轻量级锁 是指当锁是偏差锁的时候,被另外的线程所拜访,偏差锁就会降级为轻量级锁,其余线程会通过自旋的模式尝试获取锁,不会阻塞,从而进步性能。 若以后只有一个期待线程,则该线程通过自旋进行期待。然而当自旋超过肯定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁降级为重量级锁。 重量级锁 降级为重量级锁时,此时期待锁的线程都会进入阻塞状态。也就是咱们了解的synchronized锁住资源,其余线程组阻塞期待

August 25, 2023 · 1 min · jiezi

关于java:6种限流实现附代码通俗易懂

限流是一种管制拜访速率的策略,用于限度零碎、服务或API接口的申请频率或数量。它的目标是为了爱护零碎免受过多申请的影响,避免零碎因过载而解体或变得不可用。限流是一种重要的性能优化和资源爱护机制。 限流的益处有以下几个: 爱护零碎稳定性:如果零碎承受太多申请,超出了其解决能力,可能导致系统解体或响应工夫急剧减少,从而影响用户体验。限流能够帮忙管制申请速率,确保零碎稳固运行。爱护零碎可用性:有些资源可能是无限的,如数据库连贯、网络带宽、内存等。通过限度对这些资源的拜访,能够避免它们被耗尽,从而爱护零碎的可用性。避免歹意攻打:限流能够缩小歹意攻打和滥用系统资源的危险。例如,避免 DDoS(分布式拒绝服务)攻打或歹意爬虫拜访网站。偏心分配资源:对于多个客户或用户,限流能够确保资源偏心调配。每个客户都有限度的拜访机会,而不会被某个客户垄断。防止雪崩效应:当零碎中的一个组件或服务产生故障时,可能会导致大量申请涌入其余失常的组件或服务,进一步加剧零碎负载,限流能够避免这种雪崩效应。 限流分类限流的实现计划有很多种,磊哥这里略微理了一下,限流的分类如下所示: 合法性验证限流:比方验证码、IP 黑名单等,这些伎俩能够无效的避免歹意攻打和爬虫采集。容器限流:比方 Tomcat、Nginx 等限流伎俩,其中 Tomcat 能够设置最大线程数(maxThreads),当并发超过最大线程数会排队期待执行;而 Nginx 提供了两种限流伎俩:一是管制速率,二是管制并发连接数。服务端限流:比方咱们在服务器端通过限流算法实现限流,此项也是咱们本文介绍的重点。合法性验证限流为最惯例的业务代码,就是一般的验证码和 IP 黑名单零碎,本文就不做过多的叙述了,咱们重点来看下后两种限流的实现计划:容器限流和服务端限流。 一、容器限流1.1 Tomcat 限流Tomcat 8.5 版本的最大线程数在 conf/server.xml 配置中,如下所示: <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" maxThreads="150" redirectPort="8443" />其中 maxThreads 就是 Tomcat 的最大线程数,当申请的并发大于此值(maxThreads)时,申请就会排队执行,这样就实现了限流的目标。 小贴士:maxThreads 的值能够适当的调大一些,此值默认为 150(Tomcat 版本 8.5.42),但这个值也不是越大越好,要看具体的硬件配置,须要留神的是每开启一个线程须要耗用 1MB 的 JVM 内存空间用于作为线程栈之用,并且线程越多 GC 的累赘也越重。最初须要留神一下,操作系统对于过程中的线程数有肯定的限度,Windows 每个过程中的线程数不容许超过 2000,Linux 每个过程中的线程数不容许超过 1000。1.2 Nginx 限流Nginx 提供了两种限流伎俩:一是管制速率,二是管制并发连接数。 管制速率咱们须要应用 limit_req_zone 用来限度单位工夫内的申请数,即速率限度,示例配置如下: limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;server { location / { limit_req zone=mylimit; }}以上配置示意,限度每个 IP 拜访的速度为 2r/s,因为 Nginx 的限流统计是基于毫秒的,咱们设置的速度是 2r/s,转换一下就是 500ms 内单个 IP 只容许通过 1 个申请,从 501ms 开始才容许通过第 2 个申请。 ...

August 25, 2023 · 3 min · jiezi

关于java:20000-字彻底搞懂-Kafka

1、为什么有音讯零碎1、解耦合2、异步解决例如电商平台,秒杀流动。 个别流程会分为: 危险管制库存锁定生成订单短信告诉更新数据通过音讯零碎将秒杀流动业务拆离开,将不急需处理的业务放在前面缓缓解决; 流程改为: 危险管制库存锁定音讯零碎生成订单短信告诉更新数据3、流量的管制3.1 网关在承受到申请后,就把申请放入到音讯队列外面 3.2 后端的服务从音讯队列外面获取到申请,实现后续的秒杀解决流程。而后再给用户返回后果。 长处:管制了流量毛病:会让流程变慢举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice2、Kafka外围概念生产者:Producer 往Kafka集群生成数据消费者:Consumer 往Kafka外面去获取数据,解决数据、生产数据Kafka的数据是由消费者本人去拉去Kafka外面的数据 主题:topic分区:partition默认一个topic有一个分区(partition),本人可设置多个分区(分区扩散存储在服务器不同节点上) 解决了一个海量数据如何存储的问题 例如:有2T的数据,一台服务器有1T,一个topic能够分多个区,别离存储在多台服务器上,解决海量数据存储问题 3、Kafka的集群架构Kafka集群中,一个kafka服务器就是一个broker,Topic只是逻辑上的概念,partition在磁盘上就体现为一个目录。 Consumer Group:生产组,生产数据的时候,都必须指定一个group id,指定一个组的id 假设程序A和程序B指定的group id号一样,那么两个程序就属于同一个生产组 非凡: 比方,有一个主题topicA, 程序A去生产了这个topicA,那么程序B就不能再去生产topicA(程序A和程序B属于一个生产组)再比方程序A曾经生产了topicA外面的数据,当初还是从新再次生产topicA的数据,是不能够的,然而从新指定一个group id号当前,能够生产。不同生产组之间没有影响。生产组需自定义,消费者名称程序主动生成(举世无双)。 Controller:Kafka节点外面的一个主节点。借助zookeeper 4、Kafka磁盘程序写保障写数据性能kafka写数据: 程序写,往磁盘上写数据时,就是追加数据,没有随机写的操作。 教训: 如果一个服务器磁盘达到肯定的个数,磁盘也达到肯定转数,往磁盘外面程序写(追加写)数据的速度和写内存的速度差不多。 生产者生产音讯,通过kafka服务先写到os cache 内存中,而后通过sync程序写到磁盘上 5、Kafka零拷贝机制保障读数据高性能消费者读取数据流程: 消费者发送申请给kafka服务kafka服务去os cache缓存读取数据(缓存没有就去磁盘读取数据)从磁盘读取了数据到os cache缓存中os cache复制数据到kafka应用程序中kafka将数据(复制)发送到socket cache中socket cache通过网卡传输给消费者 kafka linux sendfile技术 — 零拷贝 消费者发送申请给kafka服务kafka服务去os cache缓存读取数据(缓存没有就去磁盘读取数据)从磁盘读取了数据到os cache缓存中os cache间接将数据发送给网卡通过网卡将数据传输给消费者 6、Kafka日志分段保留Kafka中一个主题,个别会设置分区;比方创立了一个topic_a,而后创立的时候指定了这个主题有三个分区。 其实在三台服务器上,会创立三个目录。 服务器1(kafka1): 创立目录topic_a-0:目录上面是咱们文件(存储数据),kafka数据就是message,数据存储在log文件里.log结尾的就是日志文件,在kafka中把数据文件就叫做日志文件。一个分区上面默认有n多个日志文件(分段存储),一个日志文件默认1G 服务器2(kafka2): 创立目录topic_a-1:服务器3(kafka3): 创立目录topic_a-2:7、Kafka二分查找定位数据Kafka外面每一条音讯,都有本人的offset(绝对偏移量),存在物理磁盘下面,在position Position:物理地位(磁盘下面那个中央) 也就是说一条音讯就有两个地位: offset:绝对偏移量(绝对地位)position:磁盘物理地位稠密索引: Kafka中采纳了稠密索引的形式读取索引,kafka每当写入了4k大小的日志(.log),就往index里写入一个记录索引。其中会采纳二分查找 8、高并发网络设计(先理解NIO)网络设计局部是kafka中设计最好的一个局部,这也是保障Kafka高并发、高性能的起因 对kafka进行调优,就得对kafka原理比拟理解,尤其是网络设计局部 Reactor网络设计模式1: ...

August 25, 2023 · 4 min · jiezi

关于java:公司来了个大佬把-FullGC-40-次天优化为-10-天-1-次太秀了~

起源:https://heapdump.cn/article/1859160 通过这一个多月的致力,将 FullGC 从 40 次/天优化到近 10 蠢才触发一次,而且 YoungGC 的工夫也缩小了一半以上,这么大的优化,有必要记录一下两头的调优过程。 对于 JVM 垃圾回收,之前始终都是处于实践阶段,就晓得新生代,老年代的降职关系,这些常识仅够应酬面试应用的。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice问题前一段时间,线上服务器的 FullGC 十分频繁,均匀一天 40 屡次,而且隔几天就有服务器主动重启了,这表明服务器的状态曾经十分不失常了,失去这么好的机会,当然要被动申请进行调优了。 未调优前的服务器 GC 数据,FullGC 十分频繁。 首先服务器的配置十分个别(2 核 4G),总共 4 台服务器集群。每台服务器的 FullGC 次数和工夫根本差不多。其中 JVM 几个外围的启动参数为: -Xms1000M -Xmx1800M -Xmn350M -Xss300K -XX:+DisableExplicitGC -XX:SurvivorRatio=4 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC-Xmx1800M:设置 JVM 最大可用内存为 1800M。-Xms1000m:设置 JVM 初始化内存为 1000m。此值能够设置与 -Xmx 雷同,以防止每次垃圾回收实现后 JVM 从新分配内存。-Xmn350M:设置年老代大小为 350M。整个 JVM 内存大小 = 年老代大小 + 年轻代大小。增大年老代后,将会减小年轻代大小。此值对系统性能影响较大,Sun 官网举荐配置为整个堆的 3/8。-Xss300K:设置每个线程的堆栈大小。JDK5.0 当前每个线程堆栈大小为 1M,以前每个线程堆栈大小为 256K。依据利用的线程所需内存大小进行调整。在雷同物理内存下,减小这个值能生成更多的线程。然而操作系统对一个过程内的线程数还是有限度的,不能有限生成,经验值在 3000~5000 左右。第一次优化一看参数,马上感觉新生代为什么这么小,这么小的话怎么进步吞吐量,而且会导致 YoungGC 的频繁触发,如上图的新生代收集就耗时 830s。 ...

August 25, 2023 · 2 min · jiezi

关于java:似懂非懂的-AspectJ

明天想和小伙伴们聊一下咱们在应用 Spring AOP 时,一个十分常见的概念 AspectJ。 1. 对于代理小伙伴们晓得,Java 23 种设计模式中有一种模式叫做代理模式,这种代理咱们能够将之称为动态代理,Spring AOP 咱们常说是一种动静代理,那么这两种代理的区别在哪里呢? 1.1 动态代理这种代理在咱们日常生活中其实十分常见,例如房屋中介就相当于是一个代理,当房东须要出租房子的时候,须要公布广告、寻找客户、清理房间。。。因为比拟麻烦,因而房东能够将租房子这件事件委托给两头代理去做。这就是一个动态代理。 我通过一个简略的代码来演示一下,首先咱们有一个租房的接口,如下: public interface Rent { void rent();}房东实现了该接口,示意想要出租屋宇: public class Landlord implements Rent{ @Override public void rent() { System.out.println("房屋出租"); }}中介作为两头代理,也实现了该接口,同时代理了房东,如下: public class HouseAgent implements Rent { private Landlord landlord; public HouseAgent(Landlord landlord) { this.landlord = landlord; } public HouseAgent() { } @Override public void rent() { publishAd(); landlord.rent(); agencyFee(); } public void publishAd() { System.out.println("公布招租广告"); } public void agencyFee() { System.out.println("收取中介费"); }}能够看到,中介的 rent 办法中,除了调用房东的 rent 办法之外,还调用了 publishAd 和 agencyFee 两个办法。 ...

August 25, 2023 · 4 min · jiezi

关于java:144K-Star一款外观漂亮运行快速动画细腻的开源免费UI组件库

之前给大家举荐了很多后盾模版,有读者心愿举荐一些跟通用的难看组件,毕竟出了后盾还有很多其余场景嘛。所以,明天持续给大家举荐一个广受好评的UI组件库:NextUI 次要个性NextUI的次要指标是简化开发流程,为加强的用户体验提供好看且适应性强的零碎设计。 它有以下几点外围个性: 可共性定制:NextUI提供了插件的模式来定制主题,你能够更改所有的语义标记以创立一个全新的主题性能优良:构建在TailWind CSS之上,这意味着没有运行时款式,包中也没有不必要的类,所以性能极佳日间/夜间模式:反对主动模式识别,当检测到HTML主题变动时,NextUI会主动更改主题模式疾速上手:NextUI是齐全组件化的,以最大限度地缩小学习曲线,并提供尽可能好的开发体验组件预览对于一款UI组件,是否难看是大家都特地关注的,上面就带大家一起来看看NextUI的一些罕用组件成果。 因为篇幅无限,就筛选了一些罕用的,还有很多其余的组件没有在这里展现,感兴趣的能够自行返回官网查看并体验动态效果。 最初,老规矩,奉上相干链接,感兴趣的能够间接去深刻理解: 官方网站:https://nextui.org/开源地址:https://github.com/nextui-org/nextui欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

August 25, 2023 · 1 min · jiezi

关于java:异常

异样Throwable 分为Exception和Error;Exception 和 Error 有什么区别?在 Java 中,所有的异样都有一个独特的先人 java.lang 包中的 Throwable 类。Throwable 类有两个重要的子类:Exception :程序自身能够解决的异样,能够通过 catch 来进行捕捉。。Error:Error 属于程序无奈解决的谬误 ,咱们没方法通过 catch 来进行捕捉不倡议通过catch捕捉 。例如 Java 虚拟机运行谬误(Virtual MachineError)、虚拟机内存不够谬误(OutOfMemoryError)、类定义谬误(NoClassDefFoundError)等 。这些异样产生时,Java 虚拟机(JVM)个别会抉择线程终止。# Checked Exception 和 Unchecked Exception 有什么区别?Checked Exception 即 受查看异样 ,Java 代码在编译过程中,如果受查看异样没有被 catch或者throws 关键字解决的话,就没方法通过编译。 异样解决形式:try-with 和try-catch-finally;try-catch-finally 如何应用?try块:用于捕捉异样。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。catch块:用于解决 try 捕捉到的异样。finally 块:无论是否捕捉或解决异样,finally 块里的语句都会被执行。当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在办法返回之前被执行。

August 25, 2023 · 1 min · jiezi

关于java:双亲委派乐观锁悲观锁

java类加载机制&nbsp&nbsp&nbsp&nbsp&nbspjava虚拟机把形容类的数据从 Class 文件加载到内存,并对数据进行校验,解析和初始化,最终造成能够被虚拟机间接应用的 java 类型。&nbsp&nbsp&nbsp&nbsp&nbsp什么是类加载器,有哪些?实现通过类的权限定名获取该类的二进制字节流的代码块叫做类加载器。次要有一下四品种加载器:&nbsp&nbsp&nbsp&nbsp&nbsp类加载器分类:启动类加载器(Bootstrap ClassLoader)、加载外围java代码的扩大类加载器(Extension ClassLoader)、加载扩大的java代码 (非核心代码如日志、图形化等类)启动类加载器、(Bootstrap ClassLoader)加载咱们写的类自定义类加载器 、(User ClassLoader)个别框架会自定义类加载器,如Tomcat&nbsp&nbsp&nbsp&nbsp&nbsp双亲委派模型,如果一个类加载器收到了类加载的申请,它首先不会本人去加载这个类,而是把这个申请委派给父类加载器去实现,每一层的类加载器都是如此,这样所有的加载申请都会被传送到顶层的启动类加载器中,只有当父加载无奈实现加载申请(它的搜寻范畴中没找到所需的类)时,子加载器才会尝试去加载类。 乐观锁和乐观锁:&nbsp&nbsp&nbsp&nbsp&nbsp乐观锁概念乐观锁与乐观锁是一种狭义上的概念,体现了对待线程同步的不同角度。在Java和数据库中都有此概念对应的理论利用。乐观锁/乐观锁区别乐观锁对于同一个数据的并发操作,乐观锁认为本人在应用数据的时候肯定有别的线程来批改数据,因而在获取数据的时候会先加锁,确保数据不会被别的线程批改。Java中,synchronized关键字和Lock的实现类都是乐观锁。乐观锁而乐观锁认为本人在应用数据时不会有别的线程批改数据,所以不会增加锁,只是在更新数据的时候去判断之前有没有别的线程更新了这个数据。如果这个数据没有被更新,以后线程将本人批改的数据胜利写入。如果数据曾经被其余线程更新,则依据不同的实现形式执行不同的操作(例如报错或者主动重试)。乐观锁实现乐观锁在Java中是通过应用无锁编程来实现,最常采纳的是CAS算法,Java原子类中的递增操作就通过CAS自旋实现的。概念:&nbsp&nbsp&nbsp&nbsp&nbspCAS全称 Compare And Swap(比拟与替换),是一种无锁算法。在不应用锁(没有线程被阻塞)的状况下实现多线程之间的变量同步。java.util.concurrent包中的原子类就是通过CAS来实现了乐观锁。&nbsp&nbsp&nbsp&nbsp&nbsp实现CAS算法波及到三个操作数:须要读写的内存值V。进行比拟的值A。要写入的新值B。&nbsp&nbsp&nbsp&nbsp&nbsp当且仅当 V 的值等于 A 时,CAS通过原子形式用新值B来更新V的值(“比拟+更新”整体是一个原子操作),否则不会执行任何操作。个别状况下,“更新”是一个一直重试的操作。之前提到java.util.concurrent包中的原子类(AtomicInteger等类),就是通过CAS来实现了乐观锁CAS问题 ABA问题:&nbsp&nbsp&nbsp&nbsp&nbspCASCAS须要在操作值的时候查看内存值是否发生变化,没有发生变化才会更新内存值。然而如果内存值原来是A,起初变成了B,而后又变成了A,那么CAS进行查看时会发现值没有发生变化,然而实际上是有变动的。 &nbsp&nbsp&nbsp&nbsp&nbspCAS的ABA问题的解决思路就是在变量后面增加版本号,每次变量更新的时候都把版本号加一,这样变动过程就从“A-B-A”变成了“1A-2B-3A”。循环工夫长开销大。CAS操作如果长时间不胜利,会导致其始终自旋,给CPU带来十分大的开销。

August 24, 2023 · 1 min · jiezi

关于java:Spring-MVC-一-从MVC-Servlet开始

甩开膀子,持续干活。 明天开始Spring Framework中的另外一部分重头戏:Spring Web MVC,借助Spring Web MVC,Spring Framework能够通过Servlet API轻松构建基于web的利用。 在开始Spring Web MVC之前,咱们还是要简略理解一下MVC的前世今生。 MVC vs 三层架构比拟古老了,简略说一下即可。 三层架构三层架构是为了实现应用程序的“高内聚低耦合”思维,把各功能模块划分为表示层UI、业务逻辑层BLL、数据拜访层DAL。各层之间通过接口相互拜访,并通过数据实体在各层之间传递数据。 三层之间分工明确,各负其责:UI层负责数据展现,BLL负责业务逻辑的解决,DAL负责数据的拜访和存储。 新生代程序员不太容易了解为什么还须要进行这样的定义,因为目前的java框架天生就是三层架构的各种变体:在三层架构的根底上,对各层又进行了进一步的细分。 20年前的程序员对三层架构所解决的问题应该印象粗浅,因为20年前绝大部分的java我的项目都没有清晰的层次结构,要么就是在jsp/servlet中充斥业务逻辑和数据库拜访、要么就是在后盾service代码中掺杂各种数据库拜访、业务逻辑以及页面款式的代码。横七竖八,程序员在须要进行bug修复或功能完善的时候,读代码比读经书还要难。 三层架构对于解决上述问题功不可没。 MVCMVC是Model、View、Controller的缩写,也就是模型、视图、控制器,最早是为Smalltalk语言提出的一种设计模式,最终在java web利用中失去了最为宽泛的利用。 view:视图层,负责数据展现或数据收集,能够有图形、图表、文字等等不同的展现形式。controller:管制层,负责接管从view层提交的用户申请,转发用户申请给模型层(model),接管model转发给view层进行展现。model:模型,解决管制层转发的用户申请,生成用户申请的数据并通过管制层转发给view层。 MVC vs 三层架构MVC是属于三层架构中UI层的设计模式,也就是说MVC都属于UI层,即便是model也属于UI层的一部分。 所以,MVC是设计模式,三层架构是应用程序或利用零碎的架构,两者属于不同维度的概念,不能混同。 如果MVC整个都处于三层架构的UI层的话,那么model就没有解决业务逻辑的责任,因为解决业务逻辑是BLL层的责任。因而,model能够了解为是在view和controller之间传递数据的载体。 生吞活剥的比照概念之间的异同其实意义不大,最重要的,咱们还是要学习把握Spring MVC的具体用法及底层逻辑。 下一篇文章正式开始。在此之前,咱们还须要首先简略回顾一下Servlet的概念。 Servlet以后的java利用在泛滥优良框架的加持下(尤其是Spring框架),大家对Servlet可能也不算太相熟了。 其实正是通过Servlet,Java才成为“适宜进行Web程序开发的语言”。 Servlet是Service applet的缩写,意思是服务端小程序,对应的,Java还已经推出过客户端小程序-applet,已经风行一时,只不过是因为各种起因,早已退出了历史舞台。 在MVC框架呈现之前,java web程序员必须与servlet打交道,每一个servlet须要在web.xml中进行配置: <servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>com.example.servlet.MyServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/myServlet</url-pattern> </servlet-mapping>其中<servlet>局部配置servlet的名字、以及其对应的servlet类。<servlet-mapping>局部配置serlvet与业务申请url的对应关系。 配置内容很容易了解,然而配置起来相当麻烦,因为MVC框架之前的每一个利用都会有数量泛滥的Servlet,程序员必须在web.xml中为每一个servlet进行配置。 Servlet3.0之后,容许通过注解形式进行配置,与web.xml形式相比,注解形式要简化许多,因而Servlet3.0是对java web程序员的一次解放。 MVC框架比方Spring Web MVC(或之前的struts)的呈现是对java web程序员的又一次大解放,Spring Web Mvc框架通过DispatcherServlet代替了应用层的其余Servlet(利用不须要创立Servlet)、只须要创立Controller。整个利用只有Dispatcherservlet一个Servlet即可,进一步简化了繁琐的Servlet配置工作(不过,话说回来,Controller其实相似Servlet,只不过Controller不须要实现任何接口、比Servlet的配置要简略一些)。 因而,尽管咱们在应用Spring Mvc的过程中感触不到Servlet的存在,然而咱们要晓得Spring MVC其实也是围绕Servlet在工作,因为Servlet是MVC框架中的C、起到承前启后的控制器作用、是绕不开的外围存在。 有了这些背景常识,下一篇文章咱们开始钻研Spring MVC。 上一篇 Spring FrameWork从入门到NB - Spring AOP的自我调用

August 24, 2023 · 1 min · jiezi

关于java:React-Native封装tencentx5-Sdk的Webview

参考资料:react-native-webview-tencentx5手把手教你一步步集成腾讯 X5 内核(Tencent TBS X5) 之前基于react-native-webview封装的Canvas在比拟老的android手机上没法导出图片canvas.toDataURL生效了,就想用react-native-webview-tencentx5去代替react-native-webview,然而react-native-webview-tencentx5不兼容react-native@0.70.所以只能借鉴react-native-webview-tencentx5从新去封装一个webview。 去TBS官网下载sdk腾讯浏览服务 - SDK 下载在android/app下创立libs而后把下载的sdk包放到文件夹里(把很长名字减短)用android studio关上,右键点击sdk包,Add As Library下载react-native-webview-tencentx5的代码,把android/src/main/java/indi/fan/webviewx5文件夹整个拷贝到本人写安卓原生组建的文件夹下(我的文件夹名字是webviewx)批改java文件引入的门路改成本人文件所在的门路 将RNX5WebViewPackage.kt文件改成RNX5WebViewPackage.javapackage com.xxxx.webviewx;import com.facebook.react.ReactPackage;import com.facebook.react.bridge.JavaScriptModule;import com.facebook.react.bridge.NativeModule;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.uimanager.ViewManager;import java.util.Arrays;import java.util.Collections;import java.util.List;public class RNX5WebViewPackage implements ReactPackage { @Override public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { return Arrays.<NativeModule>asList( new RNX5WebViewModule(reactContext) ); } public List<Class<? extends JavaScriptModule>> createJSModules() { return Collections.emptyList(); } @Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.asList( new RNX5WebViewManager() ); }}批改events文件里的kt文件为java(以TopHttpErrorEvent为例)package com.xxxx.webviewx.events;import com.facebook.react.bridge.WritableMap;import com.facebook.react.uimanager.events.Event;import com.facebook.react.uimanager.events.RCTEventEmitter;public class TopHttpErrorEvent extends Event<TopHttpErrorEvent> { public static final String EVENT_NAME = "topHttpError"; public int viewId; public WritableMap mEventData; public TopHttpErrorEvent(int viewId, WritableMap mEventData) { super(viewId); this.viewId = viewId; this.mEventData = mEventData; } public String getEventName() { return EVENT_NAME; } public boolean canCoalesce() { return false; } public short getCoalescingKey() { return 0; } public void dispatch(RCTEventEmitter rctEventEmitter) { rctEventEmitter.receiveEvent(this.viewId, this.EVENT_NAME, mEventData); }}引入到MainApplication.java里

August 24, 2023 · 1 min · jiezi

关于java:Java的SPI机制以及基于SPI编程

背景在面向对象的设计准则中,个别举荐模块之间基于接口编程,通常状况下调用方模块是不会感知到被调用方模块的外部具体实现。一旦代码外面波及具体实现类,就违反了开闭准则。如果须要替换一种实现,就须要批改代码。 为了实现在模块拆卸的时候不必在程序外面动静指明,这就须要一种服务发现机制。Java SPI 就是提供了这样一个机制:为某个接口寻找服务实现的机制。这有点相似 IOC 的思维,将拆卸的控制权移交到了程序之外。 SPI 英文为 Service Provider Interface, 字面意思就是:“服务提供者的接口”,能够了解为专门提供给服务调用者或者扩大框架性能的开发者去应用的一个接口。 SPI 将服务接口和具体的服务实现拆散开来,将服务调用方和服务实现者解耦,可能晋升程序的扩展性、可维护性。批改或者替换服务实现并不需要批改调用方。 应用场景很多框架都应用了 Java 的 SPI 机制,比方:数据库加载驱动,日志接口,以及 dubbo 的扩大实现等等。拿日志接口来说,Spring框架提供的日志服务 SLF4J 其实只是一个日志接口,然而 SLF4J 的具体实现能够有几种,比方:Logback、Log4j、Log4j2 等等,而且还能够切换,在切换日志具体实现的时候咱们是不须要更改我的项目代码的,只须要在 Maven 依赖外面批改一些 pom 依赖就好了。 与API的区别API:是指能够用来实现某项性能的类、接口或者办法。提供方提供实现形式,调用方只需调用即可。 SPI:是指用来继承、扩大,实现自定义性能的类、接口或者办法。调用方可抉择应用提供方提供的内置实现,也能够本人实现。 SPI原理Java SPI的具体约定为:当服务的提供者提供了服务接口后,在jar包的META-INF/services目录下同时创立一个以服务接口全类名命名的文件,该文件的内容就是实现该服务接口具体实现类的全名,当然这个服务接口实现类也必须在这个jar中。当内部程序拆卸这个模块的时候,就能通过该jar包META-INF/services下的配置文件找到具体的实现类,并装载实例化,实现模块的注入。Java就是通过扫描META-INF/services文件夹目录上面的文件,把实现类加载到servciceLoader外面。 简略来讲,META-INF/services/下的配置文件名字就是接口的全类名,实现类的全类名就是问这个文件的内容,如果有多个实现类,能够全副写在这个文件中,同时在实现类中要实现这个接口。不定义在META-INF/services上面行不行?就想定义在别的中央能够吗?答案是不行。看下图JDK源码中,因为曾经定义为配置门路,如果写在别的中央,类加载器就会找不到了。 案例实现代码构造如下: ├─main│ ├─java│ │ └─com│ │ ├─test│ │ │ └─Apple│ │ │ └─Fruit│ └─resources│ ├─META-INF│ │ └─services│ │ └─com.test.Fruit 创立接口Fruit,模仿服务提供方接口package com.test;public interface Fruit { }创立接口实现类Apple,实现Fruit接口;package com.test;public class Apple implements Fruit { static { System.out.println("hi,I am an apple!"); }}在resources构造下创立META-INF/services目录,在这个目录下,创立以这个接口名命名的文件com.test.Fruit,同时在这个文件中写入这个实现类的全类名;com.test.Apple创立Test测试类,在测试类中创立一个类加载器ServiceLoader来实现本案例。import com.test.Fruit;import java.util.ServiceLoader;public class Test { public static void main(String[] args) { ServiceLoader<Fruit> test = ServiceLoader.load(Fruit.class); for (Fruit item:test){ } }}执行后果如下,表明本案例胜利执行。hi,I am an apple!

August 24, 2023 · 1 min · jiezi

关于java:推荐一款免费好用的远程桌面Getscreen

因为平时有多台设施要用,所以远程桌面是我常常要应用的工具。 最近,正好看到一款不错的远程桌面软件,马上拿进去举荐给大家,如果有须要的能够看看。 明天要举荐的远程桌面软件就是这款叫Getscreen的软件,举荐理由挺简略,就3点: 简略易用:只须要两步就能轻松连上远程桌面第一步:在须要被近程连贯的机器上下载它的Agent程序并启动,点击Send取得一个链接 第二步:在其余机器上关上浏览器,应用第一步中的链接,就能轻松连上远程桌面了 应用办法是不是非常简单呢?不须要任何技术常识。 如果你有很多设施的话,还能够下载它的Dashboard来治理你的设施,应用起来会更加晦涩。 个人用户根本收费Getscreen的付费机制也比拟敌对,对于收费用户,能够反对2个设施,置信大部分个人用户也根本够用了。 多平台反对:反对windows、macOS、Linux以及Android 对于windows、macOS、Linux比拟惯例了,然而还有个Android,TJ在想是不是也能用来管制手机?这个TJ还没尝试,感兴趣的小伙伴能够试试看。 最初,老规矩,奉上官方网站:https://getscreen.me/ 。另外,如果您出了远程桌面需要之外,还有内网穿透需要,也能够看看之前举荐的ngrok,一条命令就搞定! 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

August 24, 2023 · 1 min · jiezi

关于java:Spring-Boot-Spring-Batch-实现批处理任务保姆级教程场景实战

起源:blog.csdn.net/qq_35387940/article/details/108193473 前言概念词就不多说了,我简略地介绍下 , spring batch 是一个 方便使用的 较健全的 批处理 框架。 为什么说是方便使用的,因为这是 基于spring的一个框架,接入简略、易了解、流程明显。 为什么说是较健全的, 因为它提供了平常咱们在对大批量数据进行解决时须要思考到的 日志跟踪、事务粒度调配、可控执行、失败机制、重试机制、数据读写等。 注释那么回到文章,咱们该篇文章将会带来给大家的是什么?(联合实例解说那是当然的) 从实现的业务场景来说,有以下两个: 从 csv文件 读取数据,进行业务解决再存储从 数据库 读取数据,进行业务解决再存储也就是平时常常遇到的数据清理或者数据过滤,又或者是数据迁徙备份等等。大批量的数据,本人实现分批解决须要思考的货色太多了,又不释怀,那么应用 Spring Batch 框架 是一个很好的抉择。 首先,在进入实例教程前,咱们看看这次的实例里,咱们应用springboot 整合spring batch 框架,要编码的货色有什么? 通过一张简略的图来理解: 可能大家看到这个图,是不是多多少少想起来定时工作框架?的确有那么点像,然而我必须在这通知大家,这是一个批处理框架,不是一个schuedling 框架。然而后面提到它提供了可执行管制,也就是说,啥时候执行是可控的,那么显然就是本人能够进行扩大联合定时工作框架,实现你心中所想。 ok,回到主题,置信大家能从图中简单明了地看到咱们这次实例,须要实现的货色有什么了。所以我就不在对各个小组件进行大批量文字的形容了。 那么咱们事不宜迟,开始咱们的实例教程。 首先筹备一个数据库,外面建一张简略的表,用于实例数据的写入存储或者说是读取等等。 bloginfo表 相干建表sql语句: CREATE TABLE `bloginfo` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `blogAuthor` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '博客作者标识', `blogUrl` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '博客链接', `blogTitle` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '博客题目', `blogItem` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '博客栏目', PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 89031 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;pom文件里的外围依赖: ...

August 24, 2023 · 7 min · jiezi

关于java:Redis的序列化

应用Redis存储一些缓存十分的不便,运行效率也很高,然而当咱们贮存的时候会发现一个景象,存储进去的键会主动的增加上一串前缀,这其实是keySerializer和valueSerializer默认的序列化计划是应用的JdkSerializationRedisSerializer.应用jdk序列化字符串当然会更具备安全性,然而绝对应的也损失了一些性能.而对于咱们大多数状况下只会应用的string类型,应用jdk进行序列化如同有点不是很适宜,那这个时候,spring也提供了一个StringRedisTemplate,而StringRedisTemplate继承自RedisTemplate,通过查找咱们发现,StringRedisTemplate继承自RedisTemplate又继承了RedisAccessor,而在RedisAccessor中的afterPropertiesSet办法会进行序列化器的设置.在RedisTemplate中会重写afterPropertiesSet办法.第一步会先进行一个判断,如果此时默认的序列化器为null则会创立一个jdk序列化器,并且会将默认的序列化器赋给key,value哈hash序列化器

August 23, 2023 · 1 min · jiezi

关于java:序列化器

什么是序列化?序列化是指将对象转换为字节流的过程,使其可能在存储或传输时放弃其状态。这个过程本质上是将对象转化为字节的序列,以便稍后可能复原为原始对象。Serializable接口Java中,序列化的根底是java.io.Serializable接口。只有实现了这个接口的类,才可能被序列化和反序列化。这个接口并不蕴含任何办法,它的作用在于标识出一个类是能够被序列化的。 序列化和反序列化的流程序列化:通过应用ObjectOutputStream,咱们能够将对象写入字节流中。这个流能够保留到文件、数据库或通过网络发送。 反序列化:通过应用ObjectInputStream,咱们能够从字节流中读取对象,将其还原成咱们须要的对象。 序列化的用处序列化在许多方面都具备重要作用: 长久化存储:将对象保留在磁盘上,使得应用程序在重启后可能复原状态。这在游戏、利用设置等方面十分有用。网络通信:通过序列化和反序列化,咱们能够在客户端和服务器之间传递对象数据。这在分布式系统和网络应用中至关重要。分布式系统:在分布式环境中,序列化实现近程办法调用(RMI),容许在不同的机器上调用对象的办法。版本控制和安全性在序列化中,版本控制和安全性是两个重要的思考因素: 版本控制:当类的构造发生变化时,已序列化的对象可能无奈正确反序列化。咱们能够应用serialVersionUID字段来显式申明版本号,并确保在类构造变动时进行适当的解决。安全性:序列化可能导致敏感数据的透露。咱们应该审慎解决蕴含敏感信息的对象,或者在序列化时进行加密解决。自定义序列化有时,咱们可能须要自定义序列化过程,以满足特定需要。通过在类中实现writeObject和readObject办法,咱们能够在序列化和反序列化过程中进行自定义操作。 性能思考只管序列化是弱小的工具,但它也可能影响性能。特地是在序列化大型对象时,会波及较大的开销。在高性能利用中,咱们可能须要思考采纳其余办法来缩小序列化的累赘。

August 23, 2023 · 1 min · jiezi

关于java:Aop实现自动填充字段值

需要:主动填充更新工夫创立工夫,创立用户和更新用户。 自定义注解:OperationType类是一个枚举 @Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface AutoFill{ OperationType value();}OperationType枚举类 /** * 数据库操作类型 */ public enum OperationType {/** * 更新操作 */ UPDATE,/** * 插入操作 */ INSERT}应用aop并且申明一个事务 package com.sky.aspect;import com.sky.annotation.AutoFill;import com.sky.constant.AutoFillConstant;import com.sky.context.BaseContext;import com.sky.enumeration.OperationType;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.stereotype.Component;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.time.LocalDateTime;import java.util.Objects;@Aspect@Component@Slf4jpublic class AutoFillAspect {@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")public void pt() {}@Before("pt()")public void autoFill(JoinPoint joinPoint) { //获取签名对象 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //获取办法上注解 AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class); OperationType value = annotation.value(); //解析注解是减少还是更新 Object[] args = joinPoint.getArgs(); if (Objects.isNull(args) || args.length == 0) { return; } Object target = args[0]; LocalDateTime now = LocalDateTime.now(); Long currentId = BaseContext.getCurrentId(); Class<?> clazz = target.getClass(); if (value == OperationType.INSERT) { try { Method setCreateTimeMethod = clazz.getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class); Method setCreateUserMethod = clazz.getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class); setCreateTimeMethod.invoke(target,now); setCreateUserMethod.invoke(target,currentId); autoFillUpdateMethod(now,currentId,clazz,target); } catch (Exception e) { e.printStackTrace(); } } else if (value == OperationType.UPDATE) { try { autoFillUpdateMethod(now,currentId,clazz,target); } catch (Exception e) { e.printStackTrace(); } }}private void autoFillUpdateMethod(LocalDateTime now, Long id, Class<?> clazz, Object target) throws Exception { Method setUpdateTimeMethod = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class); Method setUpdateUserMethod = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class); setUpdateTimeMethod.invoke(target,now); setUpdateUserMethod.invoke(target,id);}} ...

August 23, 2023 · 1 min · jiezi

关于java:Spring-Boot通过企业邮箱发邮件被Gmail退回的问题解决方法

这两天给咱们开发的Chrome插件:Youtube中文配音减少了账户注册和登录性能,其中有一步是邮箱验证,所以这边会在Spring Boot后盾给用户的邮箱发个验证信息。如果发邮件,之前的文章教程里就有,这里就不说了,着重说说这两天发现所有用Gmail注册的用户都被退件的问题。 报错景象先来看看具体报错(如果您也碰到这种状况,那么能够看看前面的内容): 退信起因:发件人(youtubedubbing@mail.spring4all.com)域名的DNS记录未设置或设置谬误导致对方拒收此邮件。host gmail-smtp-in.l.google.com[142.251.10.26] said: 550-5.7.26 This mail is unauthenticated, which poses a security risk to the sender and Gmail users, and has been blocked. The sender must authenticate with at least one of SPF or DKIM. For this message, DKIM checks did not pass and SPF check for [mail.spring4all.com] did not pass with ip: [54.204.34.130]. The sender should visit https://support.google.com/mail/answer/81126#authentication for instructions on setting up authentication. k191-20020a636fc8000000b00565bcd33890si6279798pgc.848 - gsmtp (in reply to end of DATA command)解决方案:请告诉你的邮箱管理员为邮箱域名设置正确的DNS(SPF、DKIM、DMARC)记录。具体请见 http://service.exmail.qq.com/cgi-bin/help?subtype=1&&no=10005... 。问题剖析从退信起因中Google给的链接内容十分多,大抵内容就是Google针对垃圾邮件滥用邮箱等行为做的防护机制。所以,如果您要反对Gmail的话,就必须合乎它所制订的身份配置要求,外面蕴含了:SPF配置、DKIM配置、ARC配置以及DMARC配置。 ...

August 23, 2023 · 1 min · jiezi

关于java:13-秒插入-30-万条数据我惊呆了

本文次要讲述通过MyBatis、JDBC等做大数据量数据插入的案例和后果。 30万条数据插入插入数据库验证实体类、mapper和配置文件定义User实体mapper接口mapper.xml文件jdbc.propertiessqlMapConfig.xml不分批次间接梭哈循环逐条插入MyBatis实现插入30万条数据JDBC实现插入30万条数据总结验证的数据库表构造如下: CREATE TABLE `t_user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户id', `username` varchar(64) DEFAULT NULL COMMENT '用户名称', `age` int(4) DEFAULT NULL COMMENT '年龄', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户信息表';话不多说,开整! 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice实体类、mapper和配置文件定义User实体 /** * <p>用户实体</p> * * @Author zjq */@Datapublic class User { private int id; private String username; private int age;}mapper接口 public interface UserMapper { /** * 批量插入用户 * @param userList */ void batchInsertUser(@Param("list") List<User> userList);}mapper.xml文件 ...

August 23, 2023 · 4 min · jiezi

关于java:对-JDK8-新出的Optional类的探索与思考

by emanjusaka from https://www.emanjusaka.top/archives/1692754288680 彼岸花开可奈何 本文欢送分享与聚合,全文转载请留下原文地址。引言所有的 Java 程序员根本都会遇到 NullPointerException 异样,个别解决这个问题可能不会是很难,然而有时去排查到底是哪引起的会消耗很长时间很是麻烦。最近理解到 JDK1.8 新减少了一个 Optional 类能够防止一些 NullPointerException 异样,上面让咱们一起去理解一下它吧。 基于值的类(Value-based Classes)有些类,如 java.util.Optional 和 java.time.LocalDateTime,是基于值的。基于值的类的实例: 是最终的和不可变的(只管可能蕴含对可变对象的援用);具备 equals、hashCode 和 toString 的实现,这些实现仅依据实例的状态计算,而不是依据实例的标识或任何其余对象或变量的状态计算;不应用对身份敏感的操作,例如实例之间的援用相等(==)、实例的身份哈希代码或对实例的外部锁进行同步;仅基于 equals() 而不是基于援用相等 (==) 被视为相等;没有可拜访的构造函数,而是通过工厂办法进行实例化,这些办法不提交返回实例的标识;当相等时是可自在替换的,这意味着在任何计算或办法调用中,依据 equals() 替换任何两个相等的实例 x 和 y 都不会产生显著的行为变动。如果程序试图辨别对基于值的类的相等值的两个援用,无论是间接通过援用相等,还是间接通过调用同步、身份哈希、序列化或任何其余身份敏感机制,都可能产生不可预测的后果。在基于值的类的实例上应用这种对身份敏感的操作可能会产生不可预测的影响,应该防止。 简略地说,基于值的类的实例是最终的,不可变的,并且这些实例没有适当的状态和标识,因而某些操作是特定于标识的,因而不应应用。 一、Optional中的根本办法Optional 类位于 java.util 包下,它是一个容器对象,可能蕴含也可能不蕴含非空值。 这是一个基于值的类;在Optional实例上应用身份敏感操作(包含援用相等(==)、身份哈希码或同步)可能会产生不可预测的后果,应该防止。 1、创立办法empty() 返回一个空的 Optional 实例 public class Main { public static void main(String[] args) { System.out.println(Optional); }}// 输入Optional.empty留神:不要通过与Option.empty()返回的实例进行==比拟来防止测试对象是否为空,因为不能保障它是单例的。 <!----> of(T value) 返回一个带值的 Optional,如果 value 是 null 会抛出 NullPointerException 异样 public static void main(String[] args) { Optional<String> emanjusaka = Optional.of("emanjusaka"); System.out.println(emanjusaka); }// 输入Optional[emanjusaka]ofNullable(T value) ...

August 23, 2023 · 3 min · jiezi

关于java:昨晚做梦面试官问我三色标记算法

本文已收录至GitHub,举荐浏览 Java随想录 微信公众号:Java随想录 原创不易,重视版权。转载请注明原作者和原文链接某天,爪哇星球上,一个一般的房间,正在举办一场机密的面试: 面试官:咱们先从JVM根底开始问,理解三色标记算法吗? 我:额......不理解。 面试官:进来的时候记得把门带上。 当初Java面试真的曾经是越来越卷了,间接上来问原理给你间接干懵。 上篇咱们讲了记忆集,这篇来聊聊「三色标记算法」,也是Java面试的常客。聊好了会让面试官感觉你这小伙子有点货色。 三色标记算法既然叫三色标记算法,首先咱们要搞明确是哪三色,三色是:彩色,红色,灰色。 把可达性剖析遍历对象图过程中遇到的对象,依照「是否拜访过」这个条件标记成以下三种色彩: 红色:示意对象尚未被垃圾收集器拜访过。显然在可达性剖析刚刚开始的阶段,所有的对象都是红色的,若在剖析完结的阶段,依然是红色的对象,即代表不可达。彩色:示意对象曾经被垃圾收集器拜访过,且这个对象的所有援用都曾经扫描过。彩色的对象代表曾经扫描过,它是平安存活的,如果有其余对象援用指向了彩色对象,毋庸从新扫描一遍。彩色对象不可能间接(不通过灰色对象)指向某个红色对象。灰色:示意对象曾经被垃圾收集器拜访过,但这个对象上至多存在一个援用还没有被扫描过。《深刻了解Java虚拟机》书中对于这块图画的很好,高深莫测,间接上原图: 从下面这段话中,咱们提炼一下要害要点: 初始阶段,GC Root是彩色的,所有的对象都是红色的,若在剖析完结的阶段,依然是红色的对象,即代表不可达。如果有其余对象援用指向了彩色对象,毋庸从新扫描一遍。彩色对象不可能间接指向某个红色对象。让我来给大伙略微解释一下第二点和第三点。 我下面画了一个示意图,第一幅和第二幅画的是对的,第三幅画的是错的。 先剖析第二点,如果有其余对象援用指向了彩色对象,那么这个对象只能为灰色或者彩色,天然无须再从新扫描一遍。 而后再说第三点,彩色对象不可能间接指向某个红色对象。 咱们从下面可知彩色对象的定义是:「对象的所有援用都曾经扫描过」,而红色对象是:「对象尚未被垃圾收集器拜访过」。 那么问题来了,如果彩色对象间接指向某个红色对象,那么他就跟彩色对象的定义矛盾了。 因为红色对象还没被拜访过,怎么能算所有援用都扫描过了呢,所以他就不可能是彩色。 下面这个很重要,把这个了解透彻之后,咱们看看三色标记算法存在的一些问题: 因为一些垃圾回收器存在垃圾回收线程和用户线程并发的状况(例如CMS的并发阶段),那么三色标记会有两个问题: 一种是把本来沦亡的对象谬误标记为存活,这不是坏事,但其实是能够容忍的,只不过产生了一点逃过本次收集的浮动垃圾而已,下次收集清理掉就好,问题不大。另一种是把本来存活的对象谬误标记为已沦亡,这就是十分致命的结果了,程序必定会因而产生谬误。第一点无伤大雅,所以咱们解决问题的重心放到第二点上。 1994年实践上被证实了,「当且仅当以下两个条件同时满足时」,会产生「对象隐没」的问题,即本来应该是彩色的对象被误标为红色: 赋值器插入了一条或多条从彩色对象到红色对象的新援用。赋值器删除了全副从灰色对象到该红色对象的间接或间接援用。其实一句话说白了就是:「跟灰色对象断开连接,跟彩色对象建设连贯」。 因而,咱们要解决并发扫描时的对象隐没问题,只需毁坏这两个条件中的任意一个即可。 由此别离产生了两种解决方案:「增量更新(Incremental Update)」和「原始快照(Snapshot At The Beginning,SATB)」。 这两个解决方案各毁坏一个条件。 增量更新增量更新要毁坏的是第一个条件。 当彩色对象插入新的指向红色对象的援用关系时,就将这个新插入的援用记录下来,等并发扫描完结之后,再将这些记录过的援用关系中的彩色对象为根,从新扫描一次。 这能够简化了解为,彩色对象一旦新插入了指向红色对象的援用之后,它就变回灰色对象了。 这其实有点像之前讲过相似OopMap的思维,实质也是保护了个映射关系,扫描完结的时候把这个映射关系再从新扫描一遍,不必全局扫描。 如图,将这个新插入的援用关系记录下来,扫描完结之后,将记录过的援用关系中的彩色对象1为根,从新扫描一次,就OK了。 原始快照原始快照要毁坏的是第二个条件。 当灰色对象要删除指向红色对象的援用关系时,就将这个要删除的援用记录下来,在并发扫描完结之后,再将这些记录过的援用关系中的灰色对象为根,从新扫描一次。 这也能够简化了解为,无论援用关系删除与否,都会依照刚刚开始扫描那一刻的「对象图快照」来进行搜寻,故名「原始快照」。 如图,将这个删除的援用关系记录下来,扫描完结之后,将记录过的援用关系中的灰色对象2为根,从新扫描一次,就OK了。 那么有个问题,增量更新和原始快照都须要记录援用关系,那这个记录的工夫点产生在什么时刻呢? 不晓得大家还是否记得之前说过的「写屏障」,是的没错。 无论是增量更新还是原始快照,虚拟机的记录操作都是通过写屏障实现的。 写屏障,咱们之前讲记忆集与卡表的时候介绍过的,能够了解为Spring中的AOP,目前为止卡表状态的保护,增量更新,原始快照都是基于写屏障。 另外,课外拓展一下,CMS应用的是增量更新,G1应用的是原始快照。 本篇文章就到这了,本篇篇幅可能有点短,不过能把事件说分明就行。之后开始讲垃圾回收器,大家一起期待下吧。 用心写文章,大伙要是有播种,心愿点个赞激励一下,thank you。 感激浏览,如果本篇文章有任何谬误和倡议,欢送给我留言斧正。 老铁们,关注我的微信公众号「Java 随想录」,专一分享Java技术干货,文章继续更新,能够关注公众号第一工夫浏览。一起交流学习,期待与你共同进步!

August 23, 2023 · 1 min · jiezi

关于java:36款影音娱乐音乐电台直播类APP评测体验报告

为不便开发者更好地掂量APP在同类产品中的体现和竞争力,有针对性地进行产品优化,软件绿色联盟策动了垂类APP评测体验专题,目前已公布了天气、小说、教育和视频类APP评测体验报告。本期将对影音娱乐类中的音乐、电台、直播类APP围绕绿标五大规范进行体验评测,欢送利用开发者继续关注。 1、评测体验本次测试共计36款利用,其中音乐类APP18款,电台类APP9款,直播类APP9款,整体体现如下:a) 开屏广告次要分为摇一摇、点击图标查看详情、上滑查看详情、扭转手机、前倾手机五类。经测试,暂未发现设置高灵敏度,升高交互动作断定阈值,造成强迫式跳转景象。然而测试过程中如果呈现摆臂动作/拿手机时调整一下姿态/振荡手机的状况,则跳转到第三方广告页面。 b) 插件类广告次要分为点击查看详情、弹出式查看详情、摇一摇跳转等。对于“摇一摇跳转到第三方页面”这类广告,因为音乐和电台类的特殊性,在应用过程中可能会有跑步锤炼情景,所以很容易跳转到第三方广告页面。 c) 大多数利用提供了青少年模式,青少年模式内容体现良好。直播类利用均有未成年禁止充值提醒,禁止未成年人直播及生产,禁止流传守法违规、封建迷信、暴力血腥、低俗色情、招嫖欺骗、违禁品等不良信息的显著告诉提醒。然而在测试过程中,也发现了个别直播类APP有未成年直播状况,K歌类的约唱厅、点唱厅、约玩厅是青少年汇集的重灾区。 d) 对于适老化版本,局部音乐类利用独立开发了专属大字版,也有利用内嵌了大字模式/关心模式。在切换模式上,利用内嵌大字版切换入口设置门路较荫蔽,不易发现。在内容举荐方面,专属大字版会主动举荐老年人可能比拟感兴趣的音乐,小局部内嵌式的利用开启适老模式后,仅对页面进行了适配,没有对内容进行个性化举荐。极少数的专属大字版利用存在将广告伪装成利用性能的状况,吸引老年用户点击。 2、绿标整体达标状况36款APP的绿标整体达标率如下:兼容性规范:达标率97.2%。稳定性规范:达标率97.2%。功耗规范:达标率100%。性能规范:整体达标率94.4%,有2款APP未通过性能规范检测,其中1款存在后盾亮屏内存占用超出规范要求(规范为各类利用在后盾且亮屏5分钟的内存占用应≤ 400MB)。另1款存在后盾灭屏内存占用(规范为各类利用在后盾且灭屏1分钟的内存占用应≤ 400MB),后盾亮屏CPU占用(规范为各类利用在后盾且亮屏5分钟的CPU占用应≤ 2%),后盾灭屏CPU占用(规范为各类利用在后盾且灭屏5分钟的CPU占用应≤ 2%)都超出规范要求的状况。平安规范:36款利用有7款APP未通过平安规范检测,整体达标率为80.6%,次要不通过起因集中在:1)广告问题2)不当申请权限的问题,次要有以下三个权限存在滥用问题:①android.permission.BIND_ACCESSIBILITY_SERVICE;②android.permission.CALL_PHONE;③android.permission.BIND_NOTIFICATION_LISTENER_SERVICE。3、绿标平安评测1)某音乐类APP点击开屏广告“跳过”按钮进入利用后,利用内再次自动弹出广告。另外广告敞开按钮可供点击区域过小。 整改倡议:依据绿标5.1平安规范,广告应在其自身所属的利用内展现,禁止利用弹出或显示影响用户体验的广告,如低头、强制插屏、侧边等。广告敞开按钮应提供无效、显著的敞开选项。 2)某直播类APP开启悬浮窗权限弹框一闪而过。整改倡议:悬浮窗权限弹框应清晰明示让用户抉择是否开启权限。 3)某音乐类APP点击“不感兴趣”下方弹出的广告后,在利用上方页面又弹出同一利用广告“祝贺取得暗藏处分”字样,点击后主动跳转第三方页面。 整改倡议:APP信息窗口页面,存在跳转、应用第三方的行为时,应以显著形式明示并经用户被动抉择批准。不应存在坑骗误导强制用户跳转的文字、图片或视频链接。 4)某音乐类APP内的插件广告点击“不感兴趣”按钮后,关不掉广告。整改倡议:APP在用户终端弹出广告或者其余与终端软件性能无关的信息窗口的,该当以显著的形式向用户提供敞开或者退出窗口的性能标识。不应提供虚伪、有效、标识不显著的敞开选项。 5)经测试发现有1款利用应用android.permission.CALL_PHONE权限,次要是拨打商家客服电话。 整改倡议:对于拨打电话性能,除一键报警、平安专线、网络会议等必须场景外,其余场景禁止应用该权限。开发者应应用零碎提供的接口调起拨号界面,而后由用户进行手动拨打电话。6)测试发现有3款利用应用android.permission.BIND_ACCESSIBILITY_SERVICE权限和android.permission.BIND_NOTIFICATION_LISTENER_SERVICE权限,用来防止录屏直播过程中麦克风与其余利用抵触导致直播无声音。 整改倡议:android.permission.BIND_ACCESSIBILITY_SERVICE为高危权限,仅限APP实现反对无障碍性能状况下,能够申请应用此权限,如针对视障人士的屏幕朗诵性能,其余场景一律禁用该权限!在无正当场景的状况下,应间接删除该权限,防止权限检测时出现异常。android.permission.BIND_NOTIFICATION_LISTENER_SERVICE为高危权限,可监听用户告诉栏收到的所有信息,无正当应用场景开发者不应应用此权限。 4、写在最初在整改、适配绿标的过程中,小伙伴们有任何疑难可及时与咱们分割,您能够发送邮件至邮箱:sga@china-sga.com或增加下方↓↓↓工作人员微信号。

August 23, 2023 · 1 min · jiezi

关于java:使用-IDEA-远程-Debug-调试太实用了

背景有时候咱们须要进行近程的debug,本文钻研如何进行近程debug,以及应用 IDEA 近程debug的过程中的细节。看完能够解决你的一些纳闷。 配置近程debug的服务,以springboot微服务为例(springcloud的应该差不多,我没钻研过)。首先,启动springboot须要加上特定的参数。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice1、IDEA设置高下版本的 IDEA 的设置可能界面有点不一样,我用2020.1.1的。大抵上差不多,自行摸索。 IDEA关上近程启动的springboot应用程序所对应的 1.抉择 Edit Configuration 2.如图,点击加号,抉择Remote 3.配置,具体步骤见图 留神:留神端口别被占用。后续这个端口是用来跟近程的java过程通信的。 能够留神到:切换不同的jdk版本,生成的脚本不一样 抉择 jdk1.4,则为 -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=50055这就是你为什么搜其余博客,会有这种配置的起因,其实这个配置也是可行的。但更精确应该依照上面jdk5-8的配置 抉择 jdk 5-8,则为 -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=50055抉择 jdk9以上,则为 -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:50055据说因为jdk9变得平安了,近程调试只容许本地,如果要近程,则须要在端口前配置*。 另外,关注公众号Java技术栈,在后盾回复关键字:IDEA,浏览我写的大量 IDEA 教程。2、启动脚本革新应用第一步失去的 Command line arguments for remote JVM 即可,即-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=50055 革新后的启动脚本如下 nohup java \-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=50055 \-jar remote-debug-0.0.1-SNAPSHOT.jar &留神在windows中用 ^ 来进行换行,例如 java ^-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=50055 ^-jar remote-debug-0.0.1-SNAPSHOT.jar阐明: 1、端口可随便本人定,未被占用的都行,然而要和IDEA里的remote中设置的端口统一!其余参数照抄。具体的参数解释能够参照附录或本人搜 2、remote-debug-0.0.1-SNAPSHOT.jar 改成给你本人的 jar 包名字 3、我给的脚本是后盾运行的,如不须要后盾运行,自行去掉 nohup 和 & 3、启动springboot,启动IDEA里的 IDEA 近程调试的细节1、细节1:停在本地断点,关闭程序后会继续执行吗如果近程调试在本人的断点处停下来了,此时敞开IDEA中的我的项目进行运行,则还会持续运行执行完剩下的逻辑吗?会的,这点比拟不容易记住 ...

August 23, 2023 · 1 min · jiezi

关于java:踩坑记录mysql-数据同步踩坑

一、背景prod 环境应用了 maxwell 进行数据同步,maxwell 监听主库的 binlog,而后将变动数据推送到 kafka,由程序接管解决,调用流程如下: 二、造成起因data-sync 服务中,mysql 的链接信息如下: spring.datasource.dynamic.datasource.master.url = jdbc:mysql:replication://192.168.1.130:3306,192.168.1.47:3306/ehp?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/其中,1.130 是主库,1.47 是从库 replication 协定会将局部读申请调配到从库中,如果此时从库的数据还未实现同步,会导致业务程序查不到数据 三、解决办法能够应用以下三种搭配形式: 监听主库的 binlog ,主库中查问数据监听从库的 binlog,从库中查问数据监听从库的 binlog,主库中查问数据

August 23, 2023 · 1 min · jiezi

关于java:踩坑记录服务频繁重启问题排查

一、背景在进行本地测试时,发现调用某个服务时会偶现调用失败的问题,报错信息如下:从图中可知,是从注册核心未找到服务导致。一开始认为是有人在重新部署,前面发现这个问题呈现的有些频繁,于是开始排查公布记录,发现近期并未有人重启服务,然而容器的重启次数高达 1521 次 二、问题跟进首先想到两种起因: 容器网络呈现问题,导致健康检查失败,被 k8s 从新拉起容器因为某些起因挂掉了,导致无奈响应申请(盲猜是 OOM 了)第一种通过运维排查后排除。于是开始排查第二种状况,从监控上看到了 GC 回收工夫高达 30s 因为是个老服务,且外面逻辑泛滥,又没有主动生成 dump 文件的配置,无奈齐全必定是 oom 导致。于是批改了我的项目配置,将 Xms 和 Xmx 参数从 512m 批改为了 1024m,并增加上 oom 后主动 dump 的配置,从新公布了服务。 约半小时左右,服务又又又又重启了,这次捞到了对应的 dump 文件,开始进行剖析。 三、问题剖析关上 jvisualvm ,将 dump 文件导入,看到了如下提醒:持续跟进,查看这个线程的状态,找到了对应的办法:这是个简略的查问,依据 AgencyId 和 OrderId 进行查问,依照 id 进行倒序,而后在数据库中查问了下,发现因为没有创立索引,导致查问很慢。。。。看似找到了问题,但有个疑难仍没有解决,一个慢 sql 是怎么导致整个服务 OOM 的?。。于是开始持续深挖代码。 四、问题解决最终排查了下代码,找到了最终的起因: 这个查问语句属于一个订单查问的定时工作,外面逻辑比较复杂,且这个工作每隔 2 分钟会执行一次因为是个老服务,之前的定时工作是 http 申请触发,每次执行之前不会判断上一次是否执行实现。。有个慢 sql (单次执行 18s 左右,定时工作中会循环执行这个 sql 查问数据),导致每次定时工作执行工夫很长,约 190s 左右 综合以上个性,曾经大抵猜到了问题产生的起因: 因为慢 sql 导致执行一次定时工作耗时较长,而后每隔 2 分钟会从新触发一次定时工作,导致多个定时工作逻辑同时执行,因为外部逻辑简单,最终导致内存耗尽,服务宕机,而后被 k8s 重启,周而复始。。。dump 文件的内容,也证实了这个猜想,确定存在多个线程在执行这个定时工作,OOM 时总共有 12 个线程正在执行。。 ...

August 23, 2023 · 1 min · jiezi

关于java:真实案例Feign-切换-okhttp-无法生效被老大骂的有点慌

起源:https://www.cnblogs.com/mufeng3421/p/11442412.html 提醒:如果只看如何解决问题,请看文章的开端如何解决这个问题 1. 场景形容最近我的项目中应用了feign当做http申请工具来应用、绝对于httpclient、resttemplate来说,fegin用起来不便很多。而后我的项目有httptrace的需要,须要输入申请日志。 所以就开启了feign本人的日志,发现它自带的日志是debug级别能力打印。而且是逐行打印的,看日志十分的不不便。所以须要输入json格局的日志最好。 2.解决步骤2.1 引入feign依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${自行抉择适宜我的项目的版本}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>这里应用了spring-cloud-openfeing来防止本人手工实现feign的注入,用法上和feign一样 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice2.2 配置feign在入口类上增加 @EnableFeignClients 注解 @SpringBootApplication@EnableFeignClientspublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}应用feing本人的Contract,方便使用feign本人的注解来申明http接口。这里应用了一个配置类 @Configurationpublic class FeignConfig { @Bean public Contract feignContract() { return new feign.Contract.Default(); }}2.3 申明接口只须要申明一个带有@FeignClient注解的接口,就申明好了一个Feign的http申请接口 @FeignClient(name = "accessPlatform", url = "${url.access-platform}")public interface AccessPlatformFeignClient { @RequestLine("GET /access-platform/resource") List<AccessResource> queryResourceList(@QueryMap Map<String, Object> query);}3.切换Feign的客户端为OkHttp因为feign自带的http客户端实现是HttpURLConnection,没有连接池性能,可配置能力也比拟差,因而咱们应用okhttp作为底层的http客户端的具体实现。3.1 引入okhttp的依赖 <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-okhttp</artifactId> <version>${feign-okhttp.version}</version></dependency>3.2 批改之前的FeignConfig配置类问题就出在这里、不过先不急,咱们持续 ...

August 23, 2023 · 2 min · jiezi

关于java:告别混乱代码这份-Spring-Boot-后端接口规范来得太及时了

一、前言一个后端接口大抵分为四个局部组成:接口地址(url)、接口申请形式(get、post等)、申请数据(request)、响应数据(response)。尽管说后端接口的编写并没有对立标准要求,而且如何构建这几个局部每个公司要求都不同,没有什么“肯定是最好的”规范,但其中最重要的关键点就是看是否标准。 二、环境阐明因为解说的重点是后端接口,所以须要导入一个spring-boot-starter-web包,而lombok作用是简化类,前端显示则应用了knife4j,具体应用在Spring Boot整合knife4j实现Api文档已写明。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice另外从springboot-2.3开始,校验包被独立成了一个starter组件,所以须要引入如下依赖: <dependency><!--新版框架没有主动引入须要手动引入--> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId></dependency><dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <!--在援用时请在maven地方仓库搜寻最新版本号--> <version>2.0.2</version></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional></dependency>三、参数校验1、介绍一个接口个别对参数(申请数据)都会进行平安校验,参数校验的重要性天然不用多说,那么如何对参数进行校验就有考究了。一般来说有三种常见的校验形式,咱们应用了最简洁的第三种办法 业务层校验Validator + BindResult校验Validator + 主动抛出异样业务层校验无需多说,即手动在java的Service层进行数据校验判断。不过这样太繁琐了,光校验代码就会有很多 而应用Validator+ BindingResult曾经是十分不便实用的参数校验形式了,在理论开发中也有很多我的项目就是这么做的,不过这样还是不太不便,因为你每写一个接口都要增加一个BindingResult参数,而后再提取错误信息返回给前端(简略看一下)。 @PostMapping("/addUser")public String addUser(@RequestBody @Validated User user, BindingResult bindingResult) { // 如果有参数校验失败,会将错误信息封装成对象组装在BindingResult里 List<ObjectError> allErrors = bindingResult.getAllErrors(); if(!allErrors.isEmpty()){ return allErrors.stream() .map(o->o.getDefaultMessage()) .collect(Collectors.toList()).toString(); } // 返回默认的错误信息 // return allErrors.get(0).getDefaultMessage(); return validationService.addUser(user);}2、Validator + 主动抛出异样(应用)内置参数校验如下: 注解校验性能@AssertFalse必须是false@AssertTrue必须是true@DecimalMax小于等于给定的值@DecimalMin大于等于给定的值@Digits可设定最大整数位数和最大小数位数@Email校验是否合乎Email格局@Future必须是未来的工夫@FutureOrPresent以后或未来工夫@Max最大值@Min最小值@Negative正数(不包含0)@NegativeOrZero正数或0@NotBlank不为null并且蕴含至多一个非空白字符@NotEmpty不为null并且不为空@NotNull不为null@Null为null@Past必须是过来的工夫@PastOrPresent必须是过来的工夫,蕴含当初@PositiveOrZero负数或0@Size校验容器的元素个数首先Validator能够十分不便的制订校验规定,并主动帮你实现校验。首先在入参里须要校验的字段加上注解,每个注解对应不同的校验规定,并可制订校验失败后的信息: @Datapublic class User { @NotNull(message = "用户id不能为空") private Long id; @NotNull(message = "用户账号不能为空") @Size(min = 6, max = 11, message = "账号长度必须是6-11个字符") private String account; @NotNull(message = "用户明码不能为空") @Size(min = 6, max = 11, message = "明码长度必须是6-16个字符") private String password; @NotNull(message = "用户邮箱不能为空") @Email(message = "邮箱格局不正确") private String email;}校验规定和谬误提示信息配置结束后,接下来只须要在接口仅须要在校验的参数上加上@Valid注解(去掉BindingResult后会主动引发异样,异样产生了自然而然就不会执行业务逻辑): ...

August 23, 2023 · 6 min · jiezi

关于java:创建-elastic-search-索引的一些注意事项

在创立 Elasticsearch(简称 ES)索引时,有多个注意事项须要思考。以下是一些要害的注意事项,我会通过具体的例子进行具体阐明。 明确索引需要:在创立索引之前,咱们须要对咱们的数据和查问需要有清晰的了解。这包含数据的类型(例如文本,数字,日期等)、数据的大小(例如是否有大量的数据须要被索引)、查问的需要(例如是否须要全文搜寻,是否须要聚合操作等)。这些因素都会影响咱们如何设置索引的映射和设置。 例如,假如咱们有一个蕴含用户信息的数据集,每个用户有姓名、年龄、生日、地址等属性。如果咱们须要对姓名进行全文搜寻,对年龄进行范畴查问,对生日进行聚合操作,那么咱们在创立索引时就须要为每个字段设置相应的类型和分析器。 索引映射:映射是定义索引中字段如何存储和如何搜寻的过程。咱们能够为每个字段定义类型(例如 text,keyword,date,long 等),也能够定义分析器、格式化器等。 例如,咱们能够为上述用户信息数据集创立如下的映射: PUT /user{ `mappings`: { `properties`: { `name`: { `type`: `text` }, `age`: { `type`: `integer` }, `birthday`: { `type`: `date`, `format`: `yyyy-MM-dd` }, `address`: { `type`: `keyword` } } }}在这个映射中,name 字段被设置为 text 类型,能够进行全文搜寻。age 字段被设置为 integer 类型,能够进行范畴查问。birthday 字段被设置为 date 类型,并定义了日期的格局。address 字段被设置为 keyword 类型,能够进行准确搜寻。 索引设置:在创立索引时,咱们能够定义一些设置,包含分片数、正本数、刷新距离等。 例如,假如咱们的用户信息数据集十分大,咱们能够将分片数设置为 5,将正本数设置为 1,以进步搜寻性能和数据的可用性: PUT /user{ `settings`: { `number_of_shards`: 5, `number_of_replicas`: 1 }, ...}须要留神的是,索引的分片数在创立时就须要定义好,之后无奈更改。而正本数能够在之后进行批改。 动静映射:ES 默认开启动静映射性能,这意味着如果索引中新退出的文档蕴含新的字段,ES 会主动为这些新字段创立映射。尽管这个性能在某些状况下很有用,但在某些状况下也可能导致问题。

August 22, 2023 · 1 min · jiezi

关于java:MySQL-处理大数据表的-3-种方案写的太好了建议收藏

作者:马佩 \链接:https://juejin.cn/post/7146016771936354312 场景当咱们业务数据库表中的数据越来越多,如果你也和我遇到了以下相似场景,那让咱们一起来解决这个问题 数据的插入,查问时长较长后续业务需要的扩大 在表中新增字段 影响较大表中的数据并不是所有的都为无效数据 需要只查问工夫区间内的评估表数据体量咱们能够从表容量/磁盘空间/实例容量三方面评估数据体量,接下来让咱们别离开展来看看。 举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practice表容量:表容量次要从表的记录数、均匀长度、增长量、读写量、总大小量进行评估。个别对于OLTP的表,倡议单表不要超过2000W行数据量,总大小15G以内。访问量:单表读写量在1600/s以内 查问行数据的形式: 咱们个别查问表数据有多少数据时用到的经典sql语句如下: select count(*) from table;select count(1) from table;然而当数据量过大的时候,这样的查问就可能会超时,所以咱们要换一种查问形式: use 库名;show table status like '表名' ; show table status like '表名'\G ;上述办法不仅能够查问表的数据,还能够输出表的详细信息 , 加 \G 能够格式化输入。包含表名 存储引擎 版本 行数 每行的字节数等等,大家能够自行试一下哈 磁盘空间查看指定数据库容量大小 selecttable_schema as '数据库',table_name as '表名',table_rows as '记录数',truncate(data_length/1024/1024, 2) as '数据容量(MB)',truncate(index_length/1024/1024, 2) as '索引容量(MB)'from information_schema.tablesorder by data_length desc, index_length desc;查问单个库中所有表磁盘占用大小 selecttable_schema as '数据库',table_name as '表名',table_rows as '记录数',truncate(data_length/1024/1024, 2) as '数据容量(MB)',truncate(index_length/1024/1024, 2) as '索引容量(MB)'from information_schema.tableswhere table_schema='mysql'order by data_length desc, index_length desc;查问出的后果如下: ...

August 22, 2023 · 2 min · jiezi

关于java:面试官Feign-第一次调用为什么会很慢大部分人都答不上来

作者:Lxlxxx \链接:https://juejin.cn/post/7249624466150408250 前言首先要理解Feign是如何进行近程调用的,这外面包含,注册核心、负载平衡、FeignClient之间的关系,微服务通过不论是eureka、nacos也好注册到服务端,Feign是靠Ribbon做负载的,而Ribbon须要拿到注册核心的服务列表,将服务进行负载缓存到本地,而后FeignClient客户端在进行调用,大略就是这么一个过程。 Ribbon是如何进行负载的首先咱们要分明Ribbon是如何进行负载的,也就是如何获取nacos、eureka的服务列表,这个很要害。 RibbonClientConfigurationRibbonClientConfiguration类中通过LoadBalancer,咱们晓得ribbon是靠LoadBalancer做负载的 无非就是ILoadBalancer接口的办法,顺次是增加新的服务、在负载平衡里抉择一个服务、markServerDown服务下线、获取服务列表、获取存活的服务器、获取所有服务器(包含衰弱和不衰弱的) ZoneAwareLoadBalancerloadBalancer默认的是ZoneAwareLoadBalancer负载均衡器,通过继承父类DynamicServerListLoadBalancer的restOfInit办法,外面比拟重要的两个办法,enableAndInitLearnNewServersFeature和updateListOfServers办法 enableAndInitLearnNewServersFeature办法外面 LOGGER.info("Using serverListUpdater {}", serverListUpdater.getClass().getSimpleName());serverListUpdater.start(updateAction);让咱们看ServerListUpdater.start办法的实现,通过自定义线程去拿,这就是获取服务列表; Ribbon负载平衡策略服务列表获取说了,当然负载平衡的策略这块也有必要讲一下,次要有七种; RoundRobinRule(轮询策略,依照服务程序顺次循环调用)WeightedResponseTimeRule(权重比策略,优先选择权重比高的服务,也就是服务响应工夫比拟短的,响应工夫越长权重比越低)RandomRule(随机策略,服务提供者列表随机抉择一个服务)BestAvailableRule(最小连接数策略,获取服务列表中连接数最小的服务实例)RetryRule(重试策略,重试获取曾经生效的服务,指定工夫没有获取到返回NULL)AvailabilityFilteringRule(可用性敏感策略,过滤非衰弱服务实例,抉择lianji)ZoneAvoidanceRule(区域敏感策略)Ribbon-eager-load(饥饿加载)模式Ribbon对于负载Client是在服务启动后,产生调用的时候才会去创立Client,所以在第一次产生http申请调用的时候,不光要算上http的申请工夫,还要算上Client的创立工夫,所以第一次调用的时候才会很慢,写个办法调用下; System 服务调用System2服务 public String requestSystem2Api(){ long startTime = System.currentTimeMillis(); R<String> stringR = iTestServiceClient.testRequestMethod(); if (null !=stringR){ log.info("接口返回:"+stringR.getMsg()); } long needTime = System.currentTimeMillis() - startTime; log.info("接口调用须要的工夫:"+needTime); return "";}从调用日志能够看出,第一次调用System2服务,Ribbon的DynamicServerListLoadBalancer会将feign客户端进行负载,而后进行调用,第一次调用的工夫就是会长一些,第二次调用间接进行申请能够看到调用工夫很快。 开启Ribbon饥饿加载ribbon: nacos: enabled: true # 开启naocos轮询 eager-load: enabled: true # 开启Ribbon的饥饿加载模式(避免第一次申请超时的问题) clients: Lxlxxx-system2 # 指定须要开启的服务(须要开启Ribbon的饥饿加载模式) ReadTimeout: 10000 ConnectTimeout: 10000 MaxAutoRetries: 0 MaxAutoRetriesNextServer: 1 OkToRetryOnAllOperations: false在我的项目启动的时候,能够从日志看到,曾经把Lxlxxx-system2服务进行加载,从而防止了第一次申请超时的状况; ...

August 22, 2023 · 1 min · jiezi

关于java:颜值爆表这款开源的API工具用起来更优雅

作为一名后端开发者,咱们常常会应用API工具来调试接口,之前始终应用的Postman,用多了感觉它有点不够轻量级,有时候关上也比较慢。最近发现了一款轻量级的开源API工具Insomnia,界面挺炫酷,性能也很实用,举荐给大家!Insomnia简介Insomnia是一款开源、跨平台的API客户端工具,能够反对多种网络申请的调试,比方GraphQL、REST、WebSockets和gRPC,目前在Github上已有29K的Star。 上面是它的一张应用效果图,界面还是挺炫酷的。 装置Insomnia的装置是非常简单的,咱们能够去它的官网下载,下载实现后双击文件即可运行,下载地址:https://insomnia.rest/download 应用接下来咱们将通过Insomnia来调试下我的电商实战我的项目mall的接口,这里还是简略介绍下mall我的项目吧,mall我的项目是一套基于 SpringBoot + Vue + uni-app 的电商零碎,目前在Github已有60K的Star,包含前台商城我的项目和后盾管理系统,能反对残缺的订单流程!涵盖商品、订单、购物车、权限、优惠券、会员等性能,性能很弱小! 我的项目地址:https://github.com/macrozheng/mall文档网站:https://www.macrozheng.com首先咱们关上Insomnia,而后点击加号创立一个工程; 而后启动下mall我的项目,关上mall我的项目的Swagger界面,咱们将通过导入的形式往Insomnia中导入接口,mall我的项目Swagger接口文档地址:http://localhost:8080/swagger-ui/ 之后咱们抉择导入按钮,输出上图中圈出的url地址来导入接口; 导入胜利后,在Insomnia的我的项目中就会呈现一个汇合了; 点击这个导入的汇合,咱们就能够看到导入的接口了; 在调试这些接口之前,咱们还须要设置下环境变量,这里间接应用Swagger的默认环境变量就能够了; 之后咱们还须要对这个环境变量进行设置,次要是把base_path设置为空; 在咱们拜访接口之前,须要设置下Authorization申请头,对于不须要登录认证的接口,比如说登录接口,咱们须要在拜访前去除它; 之后咱们在申请参数中填入信息,就能够调试接口了,这里的申请参数格局Insomnia会主动填写,还是挺不便的; 如果你想拜访须要登录认证的接口,比方品牌列表接口的话,能够在环境变量中增加一个api_key的属性,填入登录接口拜访的token; 这样咱们就能够胜利拜访须要登录认证的接口了。 设置对于Insomnia来说,还有一些罕用的设置,这里简略介绍下。比方咱们如果想批改工具的字体大小,能够点击左下角的设置按钮,而后批改即可; 如果你想批改下Insomnia的主题的话,也能够在设置里实现,Insomnia反对多达18种主题,还是很炫酷的。 总结Insomnia的确是一款界面炫酷、功能强大的API治理性能,比照Postman它更加轻量级,其实有时候咱们抉择工具时,并不需要它性能很多,简略、够用、看着舒心就好。 我的项目地址https://github.com/Kong/insomnia

August 22, 2023 · 1 min · jiezi

关于java:同事写了个惊天-bug还不容易被发现

作者:树洞君 \链接:https://juejin.cn/post/7064376361334358046 事变形容从6点32分开始大量用户拜访app时会呈现首页拜访异样,到7点20分首页服务大规模不可用,7点36分问题解决。 整体通过6:58 发现报警,同时发现群里反馈首页呈现网络忙碌,思考到前几日早晨门店列表服务上线公布过,所以思考回滚代码紧急解决问题。 7:07 开始先后分割XXX查看解决问题。 7:36 代码回滚完,服务恢复正常。 事变根本原因-事变代码模仿public static void test() throws InterruptedException, ExecutionException { Executor executor = Executors.newFixedThreadPool(3); CompletionService<String> service = new ExecutorCompletionService<>(executor); service.submit(new Callable<String>() { @Override public String call() throws Exception { return "HelloWorld--" + Thread.currentThread().getName(); } });}本源就在于ExecutorCompletionService后果没 调用take,poll办法。 正确的写法如下所示: public static void test() throws InterruptedException, ExecutionException { Executor executor = Executors.newFixedThreadPool(3); CompletionService<String> service = new ExecutorCompletionService<>(executor); service.submit(new Callable<String>() { @Override public String call() throws Exception { return "HelloWorld--" + Thread.currentThread().getName(); } }); service.take().get();}一行代码引发的血案,而且不容易被发现,因为oom是一个内存迟缓增长的过程,略微粗枝大叶就会疏忽,如果是这个代码块的调用量少的话,很可能几天甚至几个月后暴雷。 ...

August 22, 2023 · 2 min · jiezi

关于java:开源Java诊断工具Arthas开篇之watch实战

一、前言还在为排查Java程序线上问题头痛吗,看咱们用阿里开源的诊断神器 Arthas 来帮您本文开篇次要介绍 阿里开源的诊断神器Arthas 3.7.0版本,watch、jad、classloader 命令,以 Debian 11、openjdk 11 为例二、Arthas 简介和装置1. 简介Arthas 是一款线上监控诊断产品,通过全局视角实时查看利用 load、内存、gc、线程的状态信息并能在不批改利用代码的状况下,对业务问题进行诊断,包含查看办法调用的出入参、异样监测办法执行耗时,类加载信息等,大大晋升线上问题排查效率。2. 装置和启动执行该程序的用户须要和指标过程具备雷同的权限,最好和指标过程的用户统一启动当前,输出 数字 抉择要察看的过程,也可减少 --select jar名称 主动抉择过程,进步操作效率还能够在 开端减少 过程号(启动后也不必抉择过程了) curl -O https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar三、watch命令1. 根本用法察看指定函数的调用状况,如 入参、返回值、抛出异样,通过编写 OGNL 表达式查看命令格局:watch 类全名或类名表达式 函数名表达式 {察看表达式} -x 输入深度 -n 次数察看表达式:默认 {params, target, returnObj},别离是 参数列表、被察看对象、返回值-x 输入深度:默认为 1,最大为 4。默认的 察看表达式中 params + 输入深度 1,只能输入 params 是否 empty,size 是 几,要看到内容就要加大 输入深度 或 改为 params[0]很多时候,咱们都不关注 被察看对象 target,指定 察看表达式 能够降低干扰,尤其是 属性多 或 输入深度大的时候察看执行频繁的办法,最好指定 -n 次数,防止刷屏 2. 只想看满足条件的如 测试环境 同时有其他人拜访,只想看到本人的申请命令格局:watch 类全名或类名表达式 函数名表达式 {察看表达式} '条件' -x 输入深度 -n 次数 3. 只想看耗时长的命令格局:条件 替换为 #cost>毫秒数 4. 重载办法重载办法,可通过参数 个数、类型 筛选命令格局:watch 类全名或类名表达式 函数名表达式 {察看表达式} 'params.length== 参数个数 && params[0] instanceof java.lang.String 5. 实现类 和 代理类 输入2次减少参数,非代理类才输入: --exclude-class-pattern *Enhance*不匹配子类:options disable-sub-class true 6. 匹配类数量超限(默认50个)错误信息:The number of matched classes is 1501, greater than the limit value 50减少参数 -m 数量,指定 Class 最大匹配数量,默认值为 50,留神值小于理论类匹配数时报错,也就是说 只能大于等于 类匹配数类名表达式 蕴含 * 导致匹配类太多的,倡议把 类名表达式 写的更准确子类太多:试试用 子类全名 + 办法,或 不匹配子类:options disable-sub-class true,或 进步匹配类数量 -m 2000 7. 察看异样4 个察看事件点,即 -b 函数调用前,-e 函数异样后,-s 函数返回后,-f 函数完结后(默认)命令格局:watch 类全名或类名表达式 函数名表达式 {throwExp} -e 8. 察看函数调用前的入参这种状况比拟少,个别是 入参、出参 是同一个 汇合 或 对象,办法中批改了 内容命令格局:watch 类全名或类名表达式 函数名表达式 {察看表达式} -b,察看表达式 中 returnObj 是 null 哦,因为还没执行完返回四、拓展1. 狐疑代码不统一,jad 反编译 确认一下吧命令格局:jad 类全名或类名表达式 函数名表达式,办法名 是 可选的(代码行数多的类倡议加 办法名,防止刷屏),不传就反编译整个类只显示源代码,不显示 ClassLoader、Location: --source-only 不显示行号: --lineNumber false 2. 啥,jad 找不到类有一次,发版发了几次都看不到成果,原来是 发错服务了,囧,谁让服务名称前缀是一样的呢,只能怪本人了手动要加载也是能够的,classloader | arthas (aliyun.com),需指定 classLoader,如下示例classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader --load java.lang.String 五、总结Arthas 能够帮咱们诊断不少线上问题,如 查看办法调用的出入参、异样,监测办法执行耗时,类加载信息等,大大晋升线上问题排查效率。FAQ | arthas (aliyun.com)后记:想当年还用过 阿里大神开源的 greys,一转眼用 Arthas 也几年了,而 Arthas 也是基于 greys 开发的本文恪守【CC BY-NC】协定,转载请保留原文出处及本版权申明,否则将查究法律责任。 本文首先公布于 https://www.890808.xyz/ ,其余平台须要审核更新慢一些。 ...

August 22, 2023 · 2 min · jiezi

关于java:Redis命令

Redis的五种数据类型及命令(先写三种)1、StringSet key value:设定指定key的value值,如果key曾经存在,则就是批改值GET key:获取指定key的值,如果没有这个key,就是nil【相当于Java的null】SETEX key seconds value:设置指定key的值,并将 key 的过期工夫设为 seconds 秒TTL key:查看key残余存活工夫&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp负数:示意还剩下多少秒存活时&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp-1:没有设置过期工夫&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp2:曾经过期SETNX key value:如果 key不存在,则设置胜利,返回1,如果key存在,就什么都不做,返回0incr key:自增1,如果key对应存储的值是一个数值类型的字符串,则把该值+1,不存数值报错incrby key 数值:要为key减少指定数值 2、hashHSET key field value:将哈希表 key 中的字段 field 的值设为 valueHGET key field:获取存储在哈希表中指定字段的值HDEL key field:删除存储在哈希表中的指定字段HKEYS key:获取哈希表中所有字段HVALS key:获取哈希表中所有值HEXISTS key field:查看哈希表key中是否有field字段存在HGETALL key:获取所有键值对 3、listLPUSH key value1 value2 ...:从列表右边压入元素RPUSH key value1 value2 ...:从列表左边压入元素LRANGE key start stop:start和stop为下标,获取指定下标地位的元素,如果0 -1则获取所有值Rpop key:弹出最初一个元素LINDEX key index:获取指定下标的元素BRPOPLPUSH原列表 指标列表 timeout :把原列表最初一个元素弹出,压入到指标列表BRPOP key1 [key2] timeout:弹出最初一个元素,从右边开始弹出元素,如果后面的列表弹完了,则顺次从前面的的列表弹出元素。 如果列表没有元素会阻塞列表直到期待超时或发现可弹出元素为止

August 21, 2023 · 1 min · jiezi

关于java:JVM整理二

JVM介绍运行时数据区运行时数据区能够分为:办法区、堆、虚拟机栈、本地办法栈、程序计数器.其中办法区和堆为线程共享区,虚拟机栈、本地办法栈和程序计数器为线程独享区.线程独享区的内存空间随线程的创立被开拓,随线程的销毁被回收,所以垃圾回收器次要是作用在办法区和堆区. 堆堆能够被分为新生代和老年代,其中新生代由能够分为eden区和surrivor1、surrrivor2区.老年代和新生代默认占比为2:1,能够通过-XX:NewRatio=2配置从新设置占比.Eden和S1、S2的占比为8:1:1,能够通过-XX:NewSurrivor=4配置从新设置占比. 堆大小设置-Xms:256M 设置JVM的初始内存大小,默认是为零碎内存的1/64之一;-Xmx:256M 设置JVM的最大内存大小,默认是为零碎内存的1/4之一;通常咱们优化是将初始化内存和最大内存设置为一样的值,这样能够防止不必要的major gc或full gc,造成STW,引起程序利用不必要的卡顿. 回收算法新生代个别都会采纳复制算法,该算法的效率较高且满足新生代的对象个性.当新生代数据区满时,个别状况下新生代百分之八十左右的数据都可能被回收掉,留下的数据和S1区域会被回收的数据一起复制到S2区.第二次放生minor gc时,eden和S2存活的对象会被复制到S1区,默认状况下,存活的对象默认状况下达到15时,下次产生minor gc时,该存活的对象会放到老年代中.能够通过-XX:MaxTenuringThreshold=15配置从新设置新生代对象的最大年龄.老年代会采纳标记革除或标记整顿算法.标记革除会产生内存空间碎片,须要额定保护一个闲暇列表,但相较于标记整顿算法会快一些.标记整顿是先将标记存活的对象都压缩到内存的一端,最初在清理掉边界之外的所有空间,所以不会产生内存碎片. 办法区办法区是JVM标准,不同jdk版本之间的实现各有不同.jdk1.7及以前,办法区的实现是永恒代(Permanent Generation),能够通过-XX:Permsize和-XX:MaxPermsize来调配永恒代的初始空间和最大可调配空间.JDK8采纳元空间来替换永恒代,最大的区别是元空间不在JVM设置的内存中,而是应用本地内存,能够通过-XX:MetaspaceSize和-XX:MaxMetaspaceSize指定元空间的初始和最大空间.办法区内寄存的构造为类信息和运行时常量池,字符串常量池、动态变量在1.7及当前被划分到了堆中.该区也会产生垃圾回收解决. 栈虚拟机栈默认大小为1M,当遇到递归次数较多的办法,可能会产生StackOverFlowError异样,能够通过-Xss100m指令配置调整栈内存大小.每个线程都会对应一个虚拟机栈,多个线程就会对应多个虚拟机栈.一个虚拟机栈外面会蕴含多个栈帧,每一个栈帧是为办法执行而创立的,栈帧中形容的是java办法执行的内存模型.栈帧中蕴含局部变量表、操作数栈、动静链接、返回地址. 局部变量表它定义为数字数组,次要用于存储办法参数和定义在办法内的局部变量.局部变量表所需的容量在编译期间确定,在运行期间是不扭转其容量. 操作数栈它是一个后进先出的栈,依据字节码指令,往栈中写入或取出数据.操作包含:复制、替换、求和等. 动静链接被调用的办法在编译期间无奈被确定下来,只能在程序运行时将调用办法的符号援用转换为间接援用,因为这种援用转换的过程具备动态性,被称为动静链接. 办法返回地址办法在返回的时候须要在栈帧中保留一些信息,用来复原调用该办法的下层办法的执行状态. 程序计数器程序计数器就是一块较小的内存空间,它是以后线程执行字节码的行号指示器.每个栈帧都会保护一个属于本人的程序计数器,这个计数器就是用来记录执行的地址的. 本地办法栈本地办法栈和虚拟机栈类所施展的作用十分相似.它们之间的区别就是虚拟机栈为虚拟机执行Java办法服务,而本地办法栈为虚拟机所应用到的native办法服务.本地办法只有被调用之前,DLL才会被加载,即通过调用java.system.loadLibrary()实现的. [下一章节 介绍执行引擎]

August 21, 2023 · 1 min · jiezi

关于java:锁住线程

多线程机制大大提高了零碎整体的并发能力以及性能,针对于线程的平安问题咱们能够应用锁来解决. 什么是锁当多个线程简直同时批改一个共享数据的时候,须要进行同步控制,线程同步可能保障多个线程平安的拜访竞争资源(全局内容),最简略的同步机制就是应用互斥锁。 某个线程要更改共享数据时,先将其锁定,此时资源的状态为锁定状态,其余线程就能更改,直到该线程将资源状态改为非锁定状态,也就是开释资源,其余的线程能力再次锁定资源。互斥锁保障了每一次只有一个线程进入写入操作。从而保障了多线程下数据的安全性。 什么是synchronized?synchronized 是 Java 中的一个关键字,翻译成中文是同步的意思,次要解决的是多个线程之间拜访资源的同步性,能够保障被它润饰的办法或者代码块在任意时刻只能有一个线程执行。synchronized 关键字的应用形式次要有3 种:润饰实例办法润饰静态方法润饰代码块 乐观锁概念乐观锁与乐观锁是一种狭义上的概念,体现了对待线程同步的不同角度。在Java和数据库中都有此概念对应的理论利用。 乐观锁/乐观锁区别乐观锁对于同一个数据的并发操作,乐观锁认为本人在应用数据的时候肯定有别的线程来批改数据,因而在获取数据的时候会先加锁,确保数据不会被别的线程批改。Java中,synchronized关键字和Lock的实现类都是乐观锁。 乐观锁而乐观锁认为本人在应用数据时不会有别的线程批改数据,所以不会增加锁,只是在更新数据的时候去判断之前有没有别的线程更新了这个数据。 如果这个数据没有被更新,以后线程将本人批改的数据胜利写入。如果数据曾经被其余线程更新,则依据不同的实现形式执行不同的操作(例如报错或者主动重试)。

August 21, 2023 · 1 min · jiezi

关于java:如何使用Redis实现分布式锁

首先来说 Redis 作为一个独立的三方零碎,其天生的劣势就是能够作为一个分布式系统来应用,因而应用 Redis 实现的锁都是分布式锁,了解了这个概念才能看懂本文所说的内容。 分布式锁的示意图,如下所示: 分布式锁实现应用 Redis 实现分布式锁,能够通过 setnx(set if not exists)命令实现,当咱们应用 setnx 创立键值胜利时,则表明加锁胜利,否则既代码加锁失败。因为 Redis 主线程是单线程运行的,所以也不会有同时加锁胜利的状况。实现命令如下: 127.0.0.1:6379> setnx lock true(integer) 1 #创立锁胜利#逻辑业务解决...127.0.0.1:6379> del lock(integer) 1 #开释锁当咱们反复加锁时执行后果如下: 127.0.0.1:6379> setnx lock true # 第一次加锁(integer) 1127.0.0.1:6379> setnx lock true # 第二次加锁(integer) 0从上述命令中能够看出,咱们能够应用执行的后果是否为 1 来判断加锁是否胜利。 散布锁问题然而,应用 setnx 实现散布锁有一个【死锁问题】,就是当加锁的线程(或利用)掉电或解体之后,其余线程只能有限期待上来的问题。 此时,咱们解决死锁问题能够通过增加设置锁的过期工夫来实现。也就是 setnx 和 expire 配合应用,在 Redis 2.6.12 版本之后,新增了一个弱小的性能,咱们能够应用一个原子操作也就是一条命令来执行 setnx 和 expire 操作了,实现命令如下: 127.0.0.1:6379> set lock true ex 30 nxOK #创立锁胜利127.0.0.1:6379> set lock true ex 30 nx(nil) #在锁被占用的时候,希图获取锁失败其中 ex 为设置超时工夫, nx 为元素非空判断,用来判断是否能失常应用锁的。 ...

August 21, 2023 · 1 min · jiezi

关于java:GC的前置工作聊聊GC是如何快速枚举根节点的

本文已收录至GitHub,举荐浏览 Java随想录 微信公众号:Java随想录 原创不易,重视版权。转载请注明原作者和原文链接上篇文章中咱们留下了个坑:「根节点枚举」,这篇文章就把坑填上。 在上篇文章中咱们晓得了HotSpot应用的是可达性剖析算法,该算法须要进行根节点枚举。 然而查找根节点枚举的过程要做到高效并非一件容易的事件,当初Java利用越做越宏大,光是办法区的大小就常有数百上千兆,外面的类、常量等更是「恒河沙数」(一种修辞手法),若要一一查看以这里为起源的援用必定得耗费不少工夫。 大家能够思考下,如果你是JVM的开发者,你会怎么去做? 后面的文章大伙可能有点忘了,那么首先咱们对根节点枚举,先做个温习(我相对不是在混字数)。 什么是根节点枚举顾名思义,根节点枚举就是找出所有的GC Roots。 当然要成为GC Roots是有条件的,固定可作为GC Roots的对象包含以下几种(摘抄自《深刻了解虚拟机 第3版》): 在虚拟机栈(栈帧中的本地变量表)中援用的对象,譬如各个线程被调用的办法堆栈中应用到的参数、局部变量、长期变量等。在办法区中常量援用的对象,譬如字符串常量池(String Table)里的援用。在本地办法栈中JNI(即通常所说的Native办法)援用的对象。Java虚拟机外部的援用,如根本数据类型对应的Class对象,一些常驻的异样对象(比方NullPointExcepiton、OutOfMemoryError)等,还有零碎类加载器。所有被同步锁(synchronized关键字)持有的对象。反映Java虚拟机外部状况的JMXBean、JVMTI中注册的回调、本地代码缓存等。 下面说的这些,大伙必定记不住,反正总结就一句话:固定可作为GC Roots的节点次要在全局性的援用(例如常量或类动态属性)与执行上下文(例如栈帧中的本地变量表)中。 根节点枚举存在的问题迄今为止,所有收集器在根节点枚举这一步骤时都是必须暂停用户线程的。因而毫无疑问根节点枚举与之前提及的整顿内存碎片一样会面临类似的「Stop The World」的困扰。 根节点枚举必须在一个能保障一致性的快照中才得以进行——这里「一致性」的意思是整个枚举期间执行子系统看起来就像被解冻在某个工夫点上。 为什么要这么做? 试想一下,你妈给你清扫房间,你妈一边清扫,你一边丢垃圾,房间永远也清扫不洁净。 所以实质上来说,根节点枚举遇到的问题,就是并发问题。 如果不「解冻」的话,根节点汇合的对象援用关系在一直变动,那么剖析后果准确性也就无奈保障。 所以即便是号称进展工夫可控,或者(简直)不会产生进展的CMS、G1、ZGC等收集器,在枚举根节点这一步也是必须要进展的。 弄明确问题之后,咱们开动脑筋想想怎么解决。 如何解决根节点枚举的问题目前支流Java虚拟机应用的都是「精确式垃圾收集」。 所谓精确式垃圾收集是指垃圾收集器可能准确地确定内存中哪些区域被对象援用,哪些区域曾经不再应用,并且能够立刻回收不再应用的内存。 在精确式垃圾收集中,垃圾收集器须要晓得每一个援用类型变量(包含实例字段、动态字段、本地变量和输出参数等)在内存中的确切地位,以及这个地位是否正在被援用。 这样,当垃圾收集器须要进行回收时,它就能够准确地找到并回收那些不再有任何援用的对象所占用的内存。 绝对应的,还有一种叫做「激进式垃圾收集」,它不能准确地辨认所有的援用,只能激进地认为所有看起来像对象援用的值都可能是援用。这种形式可能会导致某些实际上能够被回收的内存得不到回收。 HotSpot采纳的是精确式垃圾收集。 所以当用户线程停顿下来之后,其实并不需要一个不漏地查看完所有执行上下文和全局的援用地位,虚拟机该当是有方法间接失去哪些地方寄存着对象援用的。 在HotSpot的解决方案里,是应用一组称为OopMap的数据结构来达到这个目标。OopMap能够了解为就是映射表,存储栈上的对象援用的信息,这是一种空间换工夫的做法。 在 GC Roots 枚举时,只须要遍历每个栈桢的 OopMap,通过 OopMap 存储的信息,快捷地找到 GC Roots,这样就不须要进行全局扫描。 用大白话说,其实就是用相似映射表这种伎俩记录下来援用关系,时不时去更新下映射表,而后根节点枚举只须要扫描映射表就晓得哪些地方寄存援用了,而不必去进行全局扫描。 OK,弄明确之后,问题又来了,既然OopMap是一个映射表,这个表什么时候被更新? 你可能会感觉这有啥难的,援用更新的时候同步去更新映射表不就完事了吗,然而事件并没有想的那么简略。 要晓得援用关系变动是非常频繁的,如果援用每变动一次就更新对应的OopMap,那将会须要大量的额定存储空间,这样垃圾收集随同而来的空间老本就会变得无法忍受的昂扬。 平安点解决这个问题的方法就是「平安点」,事实上,只是在「特定的地位」记录了这些信息,这些地位被称为平安点(Safepoint)。 因而GC不是随时随地来的,失去达平安点时才能够开始GC。 所以流程咱们就分明了:先是达到平安点,而后更新OopMp,而后进行根节点枚举,找到GC Roots,开始GC。 平安点的选举,个别会在如下几个地位呈现: 循环的开端办法临返回前调用办法之后抛异样的地位到这里为止,貌似问题咱们都解决了,but,还有一个问题咱们须要思考,咱们后面说了零碎要在某个工夫点处于「解冻」状态,那么如何在垃圾收集产生时让所有线程都跑到最近的平安点,而后停顿下来? 有两种计划可供选择:领先式中断(Preemptive Suspension)和主动式中断(Voluntary Suspension)。 「领先式中断」:不须要线程的执行代码被动去配合,在垃圾收集产生时,零碎首先把所有用户线程全副中断,如果发现有用户线程中断的中央不在平安点上,就复原这条线程执行,让它一会再从新中断,直到跑到平安点上。当初简直没有虚拟机实现采纳领先式中断来暂停线程响应GC事件。 「主动式中断」:当垃圾收集须要中断线程的时候,不间接对线程操作,仅仅简略地设置一个标记位,各个线程执行过程时会不停地被动去轮询这个标记,一旦发现中断标记为真时就本人在最近的平安点上被动中断挂起。平安点的设计仿佛曾经完满解决如何进展用户线程,然而依然有问题,平安点机制保障了程序执行时,在不太长的工夫内就会遇到可进入垃圾收集过程的平安点。然而,程序「不执行」的时候呢? 所谓的程序不执行就是没有调配处理器工夫,典型的场景便是用户线程处于Sleep状态或者Blocked状态,这时候线程无奈响应虚拟机的中断请求,不能再走到平安的中央去中断挂起本人。 对于这种状况,JVM引入平安区域(Safe Region)来解决。 平安区域平安区域是指可能确保在某一段代码片段之中,援用关系不会发生变化。因而,在这个区域中任意中央开始垃圾收集都是平安的。咱们也能够把平安区域看作被扩大拉伸了的平安点。 ...

August 21, 2023 · 1 min · jiezi

关于java:azkaban调研

架构 Azkaban Web Server 提供了Web UI,是azkaban的次要管理者,包含 project 的治理,认证,调度,对工作流执行过程的监控等。Azkaban Executor Server 负责具体的工作流和工作的调度提交MySQL用于保留我的项目、日志或者执行打算之类的信息 web界面 能够查看工作的dag图,工作执行历史和日志,创立工作的定时调度,手动杀死工作等 工作创立Azkaban应用以.job为后缀名的键值属性文件来定义工作流中的各个工作,以及应用dependencies属性来定义作业间的依赖关系链。这些作业文件和关联的代码最终以*.zip的形式通过Azkaban UI上传到Web服务器上,并存储到mysql中 -- a.jobtype=commandcommand=echo 'xxx'-- b.jobtype=commanddependencies=acommand=echo 'xxx'执行流程Webserver依据内存中缓存的各Executor的资源状态(Webserver有一个线程会遍历各个active executor,去发送http申请获取其资源状态信息缓存到内存中),依照抉择策略(包含executor资源状态、最近执行流个数等)抉择一个executor下发作业流;executor判断是否设置作业粒度调配,如果未设置作业粒度调配,则在以后executor执行所有作业;如果设置了作业粒度调配,则以后节点会成为作业调配的决策者,即调配节点被调配到作业的executor即成为执行节点,执行作业,而后更新数据库部署solo server mode:最简略的模式,数据库内置的H2数据库,AzkabanWebServer和AzkabanExecutorServer都在一个过程中运行,任务量不大我的项目能够采纳此模式。two server mode:数据库为MySQL,治理服务器和执行服务器在不同过程,这种模式下,AzkabanWebServer和AzkabanExecutorServer互不影响。multiple executor mode:该模式下,AzkabanWebServer和AzkabanExecutorServer运行在不同主机上,且AzkabanExecutorServer能够有多个劣势对工作执行的监控,手动杀死/启动等性能集中到了web界面上提供模块化的可插拔机制,原生反对command、java、hive、hadoop;告警也能够通过此扩大基于java开发,代码构造清晰,易于二次开发反对重试,告警劣势web server存在单点故障危险工作须要手动编写脚本创立,并打包成zip包上传工作数量过大时广泛反馈存在卡死,可能就是因为web server单点导致的 参考https://blog.csdn.net/clypm/article/details/79076801

August 21, 2023 · 1 min · jiezi

关于java:面试官Stringintern-有什么用和常量池有什么关系问倒一大片

作者:GuoMell \起源:blog.csdn.net/gcoder_/article/details/106644312 0. Background在 JAVA 语言中有8中根本类型和一种比拟非凡的类型String。这些类型为了使他们在运行过程中速度更快,更节俭内存,都提供了一种常量池的概念。常量池就相似一个JAVA零碎级别提供的缓存。 8种根本类型的常量池都是零碎协调的,String类型的常量池比拟非凡。 它的次要应用办法有两种: 间接应用双引号申明进去的String对象会间接存储在常量池中。如果不是用双引号申明的String对象,能够应用String提供的intern办法。intern 办法会从字符串常量池中查问以后字符串是否存在,若不存在就会将以后字符串放入常量池中举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice1. 常量池1.1 常量池是什么? JVM常量池次要分为Class文件常量池、运行时常量池,全局字符串常量池,以及根本类型包装类对象常量池 1.1.0 办法区办法区的作用是存储Java类的构造信息,当创建对象后,对象的类型信息存储在办法区中,实例数据寄存在堆中。类型信息是定义在Java代码中的常量、动态变量、以及类中申明的各种办法,办法字段等;实例数据则是在Java中创立的对象实例以及他们的值。 该区域进行内存回收的次要目标是对常量池的回收和对内存数据的卸载;个别说这个区域的内存回收率比起Java堆低得多。 1.1.1 Class文件常量池class文件是一组以字节为单位的二进制数据流,在Java代码的编译期间,咱们编写的Java文件就被编译为.class文件格式的二进制数据寄存在磁盘中,其中就包含class文件常量池。 class文件常量池次要寄存两大常量:字面量和符号援用。 字面量:字面量靠近java语言层面的常量概念 文本字符串,也就是咱们常常申明的:public String s = "abc";中的"abc"用final润饰的成员变量,包含动态变量、实例变量和局部变量:public final static int f = 0x101;,final int temp = 3;而对于根本类型数据(甚至是办法中的局部变量),如int value = 1常量池中只保留了他的的字段描述符int和字段的名称value,他们的字面量不会存在于常量池。符号援用:符号援用次要设波及编译原理方面的概念 类和接口的全限定名,也就是java/lang/String;这样,将类名中原来的".“替换为”/"失去的,次要用于在运行时解析失去类的间接援用字段的名称和描述符,字段也就是类或者接口中申明的变量,包含类级别变量和实例级的变量办法中的名称和描述符,也即参数类型+返回值1.1.2 运行时常量池当Java文件被编译成class文件之后,会生成下面的class文件常量池,JVM在执行某个类的时候,必须通过加载、链接(验证、筹备、解析)、初始化的步鄹,运行时常量池则是在JVM将类加载到内存后,就会将class常量池中的内容寄存到运行时常量池中,也就是class常量池被加载到内存之后的版本,是办法区的一部分。 在解析阶段,会把符号援用替换为间接援用,解析的过程会去查问字符串常量池,也就StringTable,以保障运行时常量池所援用的字符串与字符串常量池中是统一的。 运行时常量池绝对于class常量池一大特色就是具备动态性,Java标准并不要求常量只能在运行时才产生,也就是说运行时常量池的内容并不全副来自class常量池,在运行时能够通过代码生成常量并将其放入运行时常量池中,这种个性被用的最多的就是String.intern()。 1.1.3 字符串常量池在JDK6.0及之前版本,字符串常量池寄存在办法区中,在JDK7.0版本当前,字符串常量池被移到了堆中了。至于为什么移到堆内,大略是因为办法区的内存空间太小了。在HotSpot VM里实现的string pool性能的是一个StringTable类,它是一个Hash表,默认值大小长度是1009;这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。字符串常量由一个一个字符组成,放在了StringTable上。 在JDK6.0中,StringTable的长度是固定的,长度就是1009,因而如果放入String Pool中的String十分多,就会造成hash抵触,导致链表过长,当调用String#intern()时会须要到链表上一个一个找,从而导致性能大幅度降落;在JDK7.0中,StringTable的长度能够通过参数指定。 字符串常量池设计思维: 字符串的调配,和其余的对象调配一样,消耗昂扬的工夫与空间代价,作为最根底的数据类型,大量频繁的创立字符串,极大水平地影响程序的性能JVM为了进步性能和缩小内存开销,在实例化字符串常量的时候进行了一些优化为字符串开拓一个字符串常量池,相似于缓存区创立字符串常量时,首先查看字符串常量池是否存在该字符串存在该字符串,返回援用实例,不存在,实例化该字符串并放入池中实现的根底实现该优化的根底是因为字符串是不可变的,能够不必放心数据抵触进行共享运行时实例创立的全局字符串常量池中有一个表,总是为池中每个惟一的字符串对象保护一个援用,这就意味着它们始终援用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收2. String.intern()与字符串常量池/** * Returns a canonical representation for the string object. * <p> * A pool of strings, initially empty, is maintained privately by the * class <code>String</code>. * <p> * When the intern method is invoked, if the pool already contains a * string equal to this <code>String</code> object as determined by * the {@link #equals(Object)} method, then the string from the pool is * returned. Otherwise, this <code>String</code> object is added to the * pool and a reference to this <code>String</code> object is returned. * <p> * It follows that for any two strings <code>s</code> and <code>t</code>, * <code>s.intern()&nbsp;==&nbsp;t.intern()</code> is <code>true</code> * if and only if <code>s.equals(t)</code> is <code>true</code>. * <p> * All literal strings and string-valued constant expressions are * interned. String literals are defined in section 3.10.5 of the * <cite>The Java&trade; Language Specification</cite>. * * @return a string that has the same contents as this string, but is * guaranteed to be from a pool of unique strings. */public native String intern();字符串常量池的地位也是随着jdk版本的不同而地位不同。在jdk6中,常量池的地位在永恒代(办法区)中,此时常量池中存储的是对象。在jdk7中,常量池的地位在堆中,此时,常量池存储的就是援用了。 ...

August 21, 2023 · 3 min · jiezi

关于java:jdk动态代理和cglib动态代理

1、区别:JDK 动静代理和 CGLIB 动静代理是 Java 中两种罕用的动静代理实现形式,它们在实现原理和应用情境上存在一些区别。 JDK 动静代理:基于接口:JDK 动静代理只能代理实现了接口的指标对象。动静生成代理类:在运行时通过反射和字节码生成技术动静生成代理类。代理类通过实现与指标对象雷同的接口,并将办法的调用委托给 InvocationHandler 处理器。效率较高:JDK 动静代理因为间接操作字节码,因而在性能上比拟高效。 CGLIB 动静代理:基于继承:CGLIB 动静代理能够代理没有实现任何接口的指标对象。应用字节码加强库:通过应用 ASM 字节码加强库,CGLIB 在运行时生成指标对象的子类作为代理。创立子类对象:CGLIB 动静代理通过创立指标对象的子类,并重写办法来实现代理性能。效率较低:绝对于 JDK 动静代理来说,CGLIB 动静代理的生成过程比较复杂,性能稍低。 2、抉择应用 JDK 动静代理还是 CGLIB 动静代理,能够依据具体需要来决定:如果指标对象实现了接口,且接口办法较为简单,能够抉择应用 JDK 动静代理。如果指标对象没有实现接口,或者须要代理的办法较简单,能够抉择应用 CGLIB 动静代理。须要留神的是,动静代理只能代理公共办法,而无奈代理公有办法。另外,对于 final 类型的指标对象或者 final 办法,无论是 JDK 动静代理还是 CGLIB 动静代理都不能代理。

August 20, 2023 · 1 min · jiezi

关于java:动手写Amazon-SQS客户端

Amazon SQS是AWS上支流的音讯队列服务,按理说它是有SDK的,那么为什么还要本人编写客户端呢?因为它提供的SDK太简略,就几个Web API,没有方法间接用。咱们具体来说一说。 SQS SDK中的API,咱们次要用到的也就是getQueueUrl, sendMessage, receiveMessage等。getQueueUrl能依据传入的queueName查找到queueUrl,后续用这个queueUrl来拜访相应的queue(即:调用sendMessage发消息,或调用receiveMessage收音讯)。次要复杂度在于收音讯:这个API是要被动调用的,可是你怎么晓得有没有新音讯须要你去收呢?事实上,这个receiveMessage API是基于拉模式(pull mode)的,你须要轮询来不停地拉取新音讯,这个比拟像Kafka。随之而来的,就须要线程治理,须要一个对SDK做了进一步包装的客户端库。 Spring Cloud Messaging提供了SQS的客户端库。然而当咱们在2023年3月构建基于SQS的应用程序时,咱们用的是AWS SDK V2,而Spring Cloud Messaging尚未正式反对AWS SDK V2。因而,咱们决定本人编写SQS的客户端库。而且咱们的设计也与Spring Cloud Messaging的有所不同:咱们同时应用多个AWS账号,为此,咱们间接在配置中援用queueUrl(它其实是动态值,可间接援用);而Spring Cloud Messaging只能在配置中援用queueName,而后再运行时获取以后AWS账号中相应的queueUrl。 当初就来讲一讲设计与实现。音讯队列客户端遵循生产者-消费者模型,分为Producer和Consumer。SQS的音讯体必须是不大于256KB的文本,因而能够把音讯体当成一个String。 ProducerProducer很简略,把音讯收回去就行了,顺便对超时和异样做适当的解决。库的用户能够自行决定音讯体的序列化和反序列化形式,咱们不干预这件事。 Producer的应用形式很简略: new SqsMessageProducer(queueUrl) .produce(yourMessagePayload);Producer的残缺实现代码大抵如下: /** How to use: Call produce() with your serialized message string. */public class SqsMessageProducer { private final String queueUrl; private final int timeoutSeconds; private final SqsAsyncClient client; public SqsMessageProducer(String queueUrl, int timeoutSeconds) { this.queueUrl = queueUrl; this.timeoutSeconds = timeoutSeconds; client = new SqsClientFactory().createSqsAsyncClient(); } public void produce(String payload) { var sendMessageFuture = client.sendMessage( SendMessageRequest.builder().queueUrl(queueUrl).messageBody(payload).build()); // 不能有限期待future,要有超时机制 try { sendMessageFuture.get(timeoutSeconds, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { throw new ProducerException(e); } } public static class ProducerException extends RuntimeException { public ProducerException(Throwable cause) { super(cause); } }}如果想进一步提高Producer的性能,能够让它异步获取sendMessageFuture的后果,不必同步期待。然而这么做会升高可靠性,不能保障调用了Producer就肯定胜利发送了音讯,因而须要衡量。 ...

August 20, 2023 · 6 min · jiezi

关于java:万字长文彻底搞懂二叉树

算法是面试考查的重点,数据结构是算法的根基。明天次要和大家探讨下数据结构中的二叉树,当然也不仅限于二叉树,还有其余类型的扩大。 1 基础知识一棵树由称作跟的节点r以及0个或多个非空的树T1,T2, ...Tk组成,这些子树中每一颗的根都被来至根r的一条有向的边所连贯。 深度: 对任意节点ni,ni的深度为从根到ni的惟一门路的长。因而,根的深度为0.高: 从ni到一片树叶的最长门路的长。因而所有树叶的高都是0.一颗树的低等于它的根的高。 1.1 树的遍历树有很多利用,风行的用法包含Unix在内的很多罕用操作系统的目录构造。 遍历包含先序遍历(对节点的解决在它的诸儿子节点解决之前进行的)和后续遍历(在诸儿子节点解决之后进行) 2 二叉树二叉树是一棵树,其中每个节点不能有多于两个的儿子。 遍历办法: 先序:节点,左,右中序:左,节点,右后序:左,右,节点满二叉树: 一颗高度为h,并且含有2^h-1个节点的二叉树称为满二叉树,即树的每一层都含有最多的节点。齐全二叉树: 设一个高度为h,有n个节点的二叉树,当且仅当其每一个节点都与高度为h的满二叉树中编号为1~n的节点一一对应时,称为齐全二叉树。 struct TreeNode{ int val; TreeNode* left; // left child TreeNode* right; // right child}3 二叉查找树使二叉树成为二叉查找树的性质是,对于树中的每个节点X,它的左子树中所有关键字值小于X的关键字值,而它的右子树中所有关键字值大于X的关键字值。 1 查找留神对是否为空树进行判断,能够应用递归,应用的栈空间的量只是O(logN)。 2 查找最小值或最大值查找最小值时,从根开始并且只有有左儿子就向左进行,终止点是最小的元素。查找最大值时与之相同。 3 插入为了将X插入到树T中,能够像查找那样沿着树查找。如果找到X,能够什么也不做或者做一些更新。否则将X插入到遍历的门路上的最初一点上。 4 删除分3种状况: 节点是一片叶子节点:能够被立刻删除;节点有一个儿子:则该节点能够在其父节点调整指针绕过该节点后被删除; 节点有两个儿子:用其右子树中的最小的数据代替该节点的数据并递归地删除那个节点。 void remove(const int& x, BinaryNode* root){ if (root == NULL) reutrn; else if (x < root->val) remove(x, root->left); else if (x > root->val) remove(x, root->right); else if(t->left != NULL && t->right != NULL) { root->val = findMin(root->right)->val; remove(root->val, root->right); } else { BinaryNode *oldNode = root; root = (root->left != NULL) ? root->left : root->right; delete oldNode; }}Java版本如下: ...

August 20, 2023 · 4 min · jiezi

关于java:咕泡P6Java互联网高级架构师VIP涨薪班5期

download:咕泡P6:Java互联网高级架构师(VIP涨薪班)5期Java互联网架构师的职责和技能Java互联网架构师的主要职责是: 需要剖析:依据业务需要,剖析零碎性能和性能要求,制订零碎设计方案和技术选型,评估零碎危险和老本。架构设计:依据零碎设计方案,采纳适合的架构格调和模式,设计零碎的整体架构和各个模块的接口和协定,确保零碎的可扩展性、可维护性、可测试性和可靠性。技术领导:依据架构设计,领导开发团队进行代码编写、单元测试、集成测试、压力测试等,解决开发过程中遇到的技术问题,保障代码品质和开发进度。系统优化:依据零碎运行状况,监控和剖析零碎的性能瓶颈和故障点,采纳适合的优化伎俩和工具,晋升零碎的性能和稳定性。技术创新:依据业务倒退和技术变动,摸索新的技术计划和办法,继续改良零碎的架构和性能,晋升零碎的竞争力和价值。Java互联网架构师须要具备以下技能: 编程能力:熟练掌握Java语言的语法、个性、标准和最佳实际,可能编写高效、优雅、标准的代码,相熟罕用的设计模式、数据结构和算法,可能应用相干的工具和框架进行代码治理、测试、调试、部署等。数据库能力:熟练掌握关系型数据库和非关系型数据库的原理和应用,如MySQL、Oracle、MongoDB、Redis等,可能进行数据建模、查问优化、索引设计等,相熟罕用的分库分表、读写拆散、缓存穿透等数据库相干的架构问题和解决方案。中间件能力:熟练掌握罕用的中间件的原理和应用,如Spring Boot、Spring Cloud、Dubbo、MyBatis、Kafka、RabbitMQ等,可能应用相干的工具和框架进行服务治理、配置管理、服务发现、负载平衡、熔断降级等。分布式能力:相熟分布式系统的基本概念和原理,如集群、负载平衡、容错、一致性等,相熟罕用的分布式计算框架和存储系统的应用和优化,如Hadoop、Spark、HBase等,相熟罕用的分布式问题和解决方案,如分布式锁、分布式事务、分布式ID等。微服务能力:相熟微服务架构的基本概念和原理,如服务拆分、服务治理、服务网关等,相熟罕用的微服务框架和工具的应用和优化,如Spring Cloud、Dubbo、Nacos、Zuul等,相熟罕用的微服务问题和解决方案,如服务发现、服务调用、服务监控等。高并发能力:相熟高并发零碎的基本概念和原理,如线程池、异步编程、并发模型等,相熟罕用的高并发框架和工具的应用和优化,如Netty、Tomcat、Nginx等,相熟罕用的高并发问题和解决方案,如缓存、限流、降级等。高可用能力:相熟高可用零碎的基本概念和原理,如冗余、备份、切换等,相熟罕用的高可用框架和工具的应用和优化,如Zookeeper、Keepalived、HAProxy等,相熟罕用的高可用问题和解决方案,如故障检测、故障复原、故障转移等。高性能能力:相熟高性能零碎的基本概念和原理,如吞吐量、响应工夫、资源利用率等,相熟罕用的高性能框架和工具的应用和优化,如JMeter、JProfiler、Arthas等,相熟罕用的高性能问题和解决方案,如性能测试、性能剖析、性能调优等。项目管理能力:相熟项目管理的根本办法和流程,如麻利开发、需要剖析、进度管制等,可能应用相干的工具和平台进行项目管理,如Git、Maven、Jenkins等,可能协调好我的项目中人员的关系,做出正当的分工,最终实现我的项目指标。技术创新能力:关注业界最新的技术动静和趋势,如人工智能、云计算、物联网等,可能学习和把握新的技术计划和办法,继续改良零碎的架构和性能,晋升零碎的竞争力和价值。Java互联网架构师的薪资待遇依据我从网络上搜寻到的信息123 ,Java互联网架构师的薪资待遇受到多方面因素的影响,如地区差别、行业差别、学历差别、教训差别等。

August 20, 2023 · 1 min · jiezi

关于java:ON-JAVA-8读书笔记前言

ON JAVA 8这本书是基于Java 8的个性进行编程教学的,同时也依据Java11、Java17这三大LTS【长期反对版本】版本新个性做了要害更新。Java 8最大的改良是引入了函数式编程【lambda表达式、流(stream),函数式根本类型(functional primitive)】,这也是Java 8 经久不衰的起因,是里程碑式的版本【Java 8 比 Java 17还要反对久一年】。但Java与例如Python2与Python3算是两个齐全不互通的编程语言不同,Java有招向后兼容【指新的版本的软/硬件能够应用老版本的软/硬件产生的数据】的个性,Java仍旧是类"Smalltalk"的面向对象编程语言。Java是一门派生语言,因为晚期程序员并不想用过后最风行的C/C++来开发我的项目就创立了和C/C++有相似之处但又齐全不同的新编语言,该语言最大的改变就是退出了虚拟机和垃圾收集机制---Java就由此诞生了。Java还有一个最次要也是最重要的概念--“对象”,“对象”这个概念是毁誉参半的,有些人判定对象的概念是彻头彻底的失败应该抛弃,而“万物皆可对象”的slogan也是阐明这个概念的胜利。编程是一门治理复杂性的艺术,而问题的复杂程度取决于机器的复杂程度,这种复杂性的存在就会导致编程我的项目的失败。每一种语言都会存在设计缺点,就如人一样没有完满的人。了解语言和库的设计缺点是十分有必要的,因为会影响到程序员的生产力,了解了设计缺点就会通知咱们那些语言能很好的去做什么,不能去做什么。所以Java“对象”的概念是有肯定的设计缺点的---“把所有内容都封装成对象不仅是一种累赘,而且还会将程序设计推向谬误的方向”。

August 19, 2023 · 1 min · jiezi

关于java:SpringAOP能干什么

AOP(Aspect Orient Programming),直译过去就是面向切面编程,AOP是一种编程思维,是面向对象编程(OOP)的一种补充。面向切面编程,是再不批改源代码的状况下给程序动静对立增加额定性能的一种技术.AOP能够拦挡指定的办法并且对办法加强,而且无需侵入到业务代码中,使业务与非业务解决逻辑拆散,比方Spring的事务,通过事务的注解配置,Spring会主动在业务办法中开启、提交业务,并且在业务解决失败时,执行相应的回滚策略。 AOP的作用AOP 采取横向抽取机制(动静代理),取代了传统纵向继承机制的重复性代码,其利用次要体现在事务处理、日志治理、权限管制、异样解决等方面。次要作用是拆散功能性需要和非功能性需要,使开发人员能够集中处理某一个关注点或者横切逻辑,缩小对业务代码的侵入,加强代码的可读性和可维护性。简略的说,AOP 的作用就是保障开发者在不批改源代码的前提下,为零碎中的业务组件增加某种通用性能。 例如对于一些公共的信息,创立工夫、创建者、批改工夫以及批改者这些信息都能够应用AOP对须要设值的对象进行赋值.还比方,当咱们进行登录验证的时候,能够应用AOP去动静的获取用户输出的用户名与明码,而后删除掉前后空格.SpringAOP能够对代码进行简化,咱们在写代码的时候遇到常常反复的代码应该要有一种思维,如何去对这些代码进行简化.

August 19, 2023 · 1 min · jiezi

关于java:ThreadLocalT学习心得

1、ThreadLocal<T>介绍:它是java.lang包下的类,T指的是泛型,类型取决于它成员办法中的占位符,ThreadLocal中有几个比拟罕用成员的办法 &nbsp&nbsp&nbsp&nbsp(1)set(T value) :配合拦截器应用,在申请解决前进行一些操作,例如把前端页面登陆之后的id用ThreadLocal中的非凡的数据结构来存储线程的公有数据,称为 "ThreadLocalMap",每个线程领有本人的 ThreadLocalMap,因而不同线程对同一个 ThreadLocal 对象的操作是互相独立的,互不烦扰。 &nbsp&nbsp&nbsp&nbsp(2)T get():用于获取以后线程中与 ThreadLocal 对象关联的值 &nbsp&nbsp&nbsp&nbsp(3)remove:删除ThreadLocalMap所有的数据 2会有内存透露问题吗?怎么解?&nbsp&nbsp&nbsp如果在应用ThreadLocal的过程中不留神开释资源,可能会导致内存透露的问题。这是因为 ThreadLocal 应用了一个非凡的数据结构 ThreadLocalMap 来存储每个线程的公有数据,而 ThreadLocalMap 是弱援用类型的键值对。 &nbsp&nbsp&nbsp当线程完结时,ThreadLocalMap 中与该线程关联的键值对并不会主动被清理,如果 ThreadLocal 对象没有手动删除或调用 remove 办法进行清理,那么对应的键值对就会始终存在于 ThreadLocalMap 中,这样就会导致内存透露。 为了防止 ThreadLocal 的内存透露问题,能够采取以下两种罕用的解决方案:&nbsp&nbsp&nbsp(1)及时清理:在应用完 ThreadLocal 后,应该手动调用 remove 办法将其与以后线程关联的键值对从 ThreadLocalMap 中移除。能够应用 ThreadLocal 的 remove 办法或者应用 try-finally 语句块来确保清理操作肯定会执行。&nbsp&nbsp&nbsp(2)应用 InheritableThreadLocal:InheritableThreadLocal 是 ThreadLocal 的一个子类,容许子线程继承父线程设置的 ThreadLocal 值。应用 InheritableThreadLocal 的益处是,能够防止在子线程中从新设置 ThreadLocal 值,从而缩小了内存透露的危险。 补充:&nbsp&nbsp&nbsp强援用(Strong Reference):强援用是最常见的援用类型,在代码中间接通过变量进行援用。只有存在强援用指向一个对象,垃圾回收器就不会回收该对象。即便内存不足时,零碎也不会回收强援用对象。例如:Object obj = new Object(); // obj为强援用 &nbsp&nbsp&nbsp软援用(Soft Reference):软援用用于形容一些还有用但非必须的对象。当内存不足时,垃圾回收器可能会回收软援用对象。能够利用软援用来实现内存敏感的高速缓存等场景。例如:SoftReference<Object> softRef = new SoftReference<>(obj); // softRef为软援用 ...

August 18, 2023 · 1 min · jiezi

关于java:ThreadLocalT之我见

1.咱们在进行表创立的时候通常会创立出一条批改人与创建人的数据,能够很不便的看出有谁批改了数据库.那这条数据要通过怎么的代码去实时实现呢,能够通过ThreadLocal技术,当咱们应用token去定义拦截器的时候,前端页面中会携带一个token数据,能够通过token数据实时的去获取以后用户的id,而后能够放入线程中,在须要应用的中央应用办法去获取.ThreadLocal 并不是一个Thread,而是Thread的局部变量.ThreadLocal为每个线程提供独自一份存储空间,具备线程隔离的成果,只有在线程内能力获取到对应的值,线程外则不能拜访。ThreadLocal有三个办法是咱们罕用的,别离是public void set(T value) 设置以后线程的线程局部变量的值public T get() 返回以后线程所对应的线程局部变量的值public void remove() 移除以后线程的线程局部变量 2.存在内存透露问题吗?在ThreadLocal的动态外部类ThreadLocalMap中,援用ThreadLocal的key为弱援用,而value为强援用,因而可能呈现key值被回收而value依然存在的状况,即key为null,这样的话value始终不会被回收掉,从而会造成内存透露.怎么解决?能够在应用完ThreadLocal后应用remove办法开释掉资源.

August 18, 2023 · 1 min · jiezi

关于java:ThreadLocal

ThreadLocal作用ThreadLocal是本地线程变量,而ThreadLocal中寄存的是该线程的变量,且只能被本线程拜访。ThreadLocal 为每个线程都创立了变量正本,从而防止了并发拜访抵触。 上面让咱们来看一个例子: public class ThreadLocalTest02 { public static void main(String[] args) { ThreadLocal<String> local = new ThreadLocal<>(); IntStream.range(0, 10).forEach(i -> new Thread(() -> { local.set(Thread.currentThread().getName() + ":" + i); System.out.println("线程:" + Thread.currentThread().getName() + ",local:" + local.get()); }).start()); }}输入后果:线程:Thread-0,local:Thread-0:0线程:Thread-1,local:Thread-1:1线程:Thread-2,local:Thread-2:2线程:Thread-3,local:Thread-3:3线程:Thread-4,local:Thread-4:4线程:Thread-5,local:Thread-5:5线程:Thread-6,local:Thread-6:6线程:Thread-7,local:Thread-7:7线程:Thread-8,local:Thread-8:8线程:Thread-9,local:Thread-9:9从后果能够看到,每一个线程都有本人的local 值,这就是TheadLocal的根本应用 。 上面咱们从源码的角度来剖析一下,ThreadLocal的工作原理。 ThreadLocal 源码剖析1、set 办法/** * Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * * @param value the value to be stored in the current thread's copy of * this thread-local. */public void set(T value) { //首先获取以后线程对象 Thread t = Thread.currentThread(); //获取线程中变量 ThreadLocal.ThreadLocalMap ThreadLocalMap map = getMap(t); //如果不为空, if (map != null) map.set(this, value); else //如果为空,初始化该线程对象的map变量,其中key 为以后的threadlocal 变量 createMap(t, value);}/** * Create the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @param firstValue value for the initial entry of the map *///初始化线程外部变量 threadLocals ,key 为以后 threadlocalvoid createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue);}/** * Construct a new map initially containing (firstKey, firstValue). * ThreadLocalMaps are constructed lazily, so we only create * one when we have at least one entry to put in it. */ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY);}static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; }}其中ThreadLocalMap是ThreadLocal的一个动态外部类,外面定义了Entry来保留数据。而且是继承的弱援用。在Entry外部应用ThreadLocal作为key,应用咱们设置的value ...

August 18, 2023 · 2 min · jiezi

关于java:业务开发时接口不能对外暴露怎么办

在业务开发的时候,常常会遇到某一个接口不能对外裸露,只能内网服务间调用的理论需要。面对这样的状况,咱们该如何实现呢? 明天,咱们就来理一理这个问题,从几个可行的计划中,筛选一个来实现。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice1. 内外网接口微服务隔离将对外裸露的接口和对内裸露的接口别离放到两个微服务上,一个服务里所有的接口均对外裸露,另一个服务的接口只能内网服务间调用。 该计划须要额定编写一个只对外部裸露接口的微服务,将所有只能对内裸露的业务接口聚合到这个微服务里,通过这个聚合的微服务,别离去各个业务侧获取资源。 该计划,新增一个微服务做申请转发,减少了零碎的复杂性,增大了调用耗时以及前期的保护老本。 2. 网关 + redis 实现白名单机制在 redis 里保护一套接口白名单列表,内部申请达到网关时,从 redis 获取接口白名单,在白名单内的接口放行,反之回绝掉。 该计划的益处是,对业务代码零侵入,只须要保护好白名单列表即可; 不足之处在于,白名单的保护是一个持续性投入的工作,在很多公司,业务开发无奈间接涉及到 redis,只能提工单申请,减少了开发成本;另外,每次申请进来,都须要判断白名单,减少了零碎响应耗时,思考到失常状况下内部进来的申请大部分都是在白名单内的,只有极少数歹意申请才会被白名单机制所拦挡,所以该计划的性价比很低。 3. 计划三 网关 + AOP相比于计划二对接口进行白名单判断而言,计划三是对申请起源进行判断,并将该判断下沉到业务侧。防止了网关侧的逻辑判断,从而晋升零碎响应速度。 咱们晓得,内部进来的申请肯定会通过网关再被散发到具体的业务侧,外部服务间的调用是不必走内部网关的(走 k8s 的 service)。 依据这个特点,咱们能够对所有通过网关的申请的header里增加一个字段,业务侧接口收到申请后,判断header里是否有该字段,如果有,则阐明该申请来自内部,没有,则属于外部服务的调用,再依据该接口是否属于外部接口来决定是否放行该申请。 该计划将内外网拜访权限的解决散布到各个业务侧进行,打消了由网关来解决的系统性瓶颈;同时,开发者能够在业务侧间接确定接口的内外网拜访权限,晋升开发效率的同时,减少了代码的可读性。 当然该计划会对业务代码有肯定的侵入性,不过能够通过注解的模式,最大限度的升高这种侵入性。 具体实操上面就计划三,进行具体的代码演示。 首先在网关侧,须要对进来的申请header增加外网标识符: from=public @Componentpublic class AuthFilter implements GlobalFilter, Ordered { @Override public Mono < Void > filter ( ServerWebExchange exchange, GatewayFilterChain chain ) { return chain.filter( exchange.mutate().request( exchange.getRequest().mutate().header("id", "").header("from", "public").build()) .build() ); } @Override public int getOrder () { return 0; } }接着,编写内外网拜访权限判断的AOP和注解 ...

August 18, 2023 · 1 min · jiezi

关于java:104K-Star程序员为程序员针对性优化的开源免费笔记

平时我始终用Notion来记录内容为主,但也始终关注着其余开源产品。上周正好看到一款十分受欢迎的开源收费笔记,明天就举荐给大家:VNote。 VNote一个由程序员为程序员打造的开源笔记利用,基于Qt开发,专一于应用 Markdown 来写作的群体。它提供完满的编辑体验和弱小的笔记治理性能,使得应用Markdown记笔记更加轻松简略。VNote未来还会反对更多的文档格局。因为Qt的反对,VNote能够高效地运行在Linux、Windows和macOS平台上。 VNote的编辑能够通过上面的几张截图来初步理解: 能够看到,VNote的界面十分简洁且合乎古代审美。它反对原地预览和双边预览,不便咱们查看编写成果。同时,在界面左右两侧提别离提供了文件目录和文章纲要,不便作者疾速切换。 对于一些简单的UML图、流程图、数学公式也有很好的反对,具体如下: 对于文章内容的存储,是很多作者都会关注的。VNote在这方面采纳了以文件模式的本地存储,一个笔记对应一个目录。所以,用户能够自在的抉择第三方同步服务来备份和同步多端工作。 怎么样,VNote是你心目中想要的笔记软件吗? 最初,老规矩,奉上相干地址: 官方网站:https://app.vnote.fun/zh_cn/#!index.md开源地址:https://github.com/vnotex/vnote最初最初,欢送关注TJ,给本文点个赞、在看反对一下哦~ 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

August 18, 2023 · 1 min · jiezi

关于java:面试官Java-线程有哪几种状态它们之间是怎么切换的

起源:https://blog.csdn.net/limenghua9112/article/details/106975105 为何要理解Java线程状态线程是 JVM 执行工作的最小单元,了解线程的状态转换是了解后续多线程问题的根底。 Java线程状态转换图 Java线程有哪些状态?在 JVM 运行中,线程一共有 NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED 六种状态,这些状态对应 Thread.State 枚举类中的状态。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practiceThread.State枚举源码: 为不便浏览,在此去掉了文档正文 public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED;}在给定的工夫点,线程只能处于这些状态中的一种状态。这些状态是不反映任何操作系统线程状态的虚拟机状态。 NEW,TERMINATED这两个状态比拟好了解,当创立一个线程后,还没有调用start()办法时,线程处在 NEW 状态,线程实现执行,退出后变为TERMINATED终止状态。 RUNNABLE运行 Thread 的 start 办法后,线程进入 RUNNABLE 可运行状态 /** * 程序目标:察看线程的各种状态 * created at 2020-06-26 19:09 * @author lerry */class MyThread extends Thread { @Override public void run() { System.out.printf("%s线程运行\n", Thread.currentThread().getName()); }}/** * 别离察看创立线程后、start()后、和线程退出后的线程状态。 * 其中Thread.sleep(50);是为了期待线程执行完 */public class ThreadStateDemo { public static void main(String[] args) throws InterruptedException { MyThread myThread = new MyThread(); System.out.printf("创立线程后,线程的状态为:%s\n", myThread.getState()); myThread.start(); System.out.printf("调用start()办法后线程的状态为:%s\n", myThread.getState()); // 休眠50毫秒,期待MyThread线程执行完 Thread.sleep(50); System.out.printf("再次打印线程的状态为:%s\n", myThread.getState()); }}输入后果: ...

August 18, 2023 · 4 min · jiezi

关于java:聊聊java的javasecurityegd

序本文次要钻研一下java的java.security.egd SunEntries/Library/Java/JavaVirtualMachines/temurin-8.jdk/Contents/Home/src.zip!/sun/security/provider/SunEntries.java // name of the *System* property, takes precedence over PROP_RNDSOURCE private final static String PROP_EGD = "java.security.egd"; // name of the *Security* property private final static String PROP_RNDSOURCE = "securerandom.source"; final static String URL_DEV_RANDOM = "file:/dev/random"; final static String URL_DEV_URANDOM = "file:/dev/urandom"; private static final String seedSource; static { seedSource = AccessController.doPrivileged( new PrivilegedAction<String>() { @Override public String run() { String egdSource = System.getProperty(PROP_EGD, ""); if (egdSource.length() != 0) { return egdSource; } egdSource = Security.getProperty(PROP_RNDSOURCE); if (egdSource == null) { return ""; } return egdSource; } }); }这里优先读取java.security.egd,如果没有设置则读取$JAVA_HOME/jre/lib/security/java.security文件中的securerandom.source配置,默认值为file:/dev/randomSeedGenerator/Library/Java/JavaVirtualMachines/temurin-8.jdk/Contents/Home/src.zip!/sun/security/provider/SeedGenerator.java ...

August 18, 2023 · 3 min · jiezi

关于java:Spring注解

@Data :标注的类会主动生成getset办法equals、hashcode、tostring@AllARrgsConstructor :标注的类会主动生成全参结构@NoARrgsConstructor :主动生成无参结构@Component:把标注的类退出到ioc容器中@Mapper:标注在长久层上,把类退出ioc容器@Service:把类标注在业务层上,把类退出ioc容器@Controller:把类标注在表示层@Scope:标注在类上用于指定bean的范畴@RestController:相当于ResponseBody+Controller@Configuration:作用:当spring容器启动的时候主动扫描并加载所有配置类,而后将配置类中的Bean放入spring容器中@Aspect //标注在加强类上@PointCut 切点表达式 相当于exception:"execution(com.公司名.service.impl . * (..))"@Around //盘绕告诉@EnableAspectAutoProxy //激活切面主动代理 相当于 < aop : aspectj - AutoProxy / >@EnableTransactionManagement //激活事务管理@Autowired 主动拆卸@Qualifier :@RequestParam:标注在办法的参数前,用于对传入的参数做一些限度标注在办法的参数前,用于对传入的参数做一些限度value:默认的属性用于指定前端传入的参数名称require:用于指定参数是否为必传@ExceptionHandler:标注在办法上,申明以后办法能够解决的异样@PostMapping::仅仅接管POST申请,有申请体@GetMapping:仅仅接管GET申请,没有申请体@DeletMapping:仅仅接管删除申请:有申请体@PutMapping:仅仅接管更新申请,有申请体@PathVariable:标注在申请参数之前,用于从申请门路中取值赋值给办法参数;占位符 {}@RequestBody:规定传入参数为json格局@RequestMapper:两个属性值,一个是value示意申请门路,前面参数是RequestMethod枚举能够设置数组反对多种数据申请形式

August 17, 2023 · 1 min · jiezi

关于java:在ZshZshell终端中执行java带的命令

在mac执行一个命令时 java -cp .:/release/bin/../conf:/release/bin/../lib/* com.ex.TestApplication发现报错 zsh: no matches found: .:/release/bin/../conf:/release/bin/../lib/*那么这是一个什么样的状况呢?起因是在Zsh终端中,通配符(例如*)默认是开启的,这可能导致java命令中的类门路无奈正确解析,能够通过执行setopt +o nomatch命令来禁用通配符,然而,如果脚本中增加了这一行, 在linux环境下, 又无奈执行,怎么办呢? if [ "$SHELL" = "/bin/zsh" ]; then echo "以后Shell解释器为Zsh" setopt +o nomatchfi能够通过上述代码来实现,在上述代码中,通过查看$SHELL环境变量的值是否为/bin/zsh来判断以后Shell是否为Zsh。当然, 这个办法实用于大多数状况, 但不是百分百精确的。

August 17, 2023 · 1 min · jiezi

关于java:记录一次使用多线程调用kafka发送消息产生的内存泄漏问题

在布控预警的需要实现里,我须要把长久化在数据库中的布控对象(身份证、姓名、手机号、imsi、faceId等等都可别离作为布控对象)始终往kafka里发送,而后由flink进行生产,把以后的布控对象和存储的用户轨迹记录(有旅客、航班、车辆卡口、人脸等等数据)同时蕴含身份证、姓名等等信息进行比对,如果比对胜利则触发布控预警最开始我是通过单线程发送,发现发送速度有点慢,这外面我须要把布控对象做一些解决(比方split,flat,fitler)后才发送到kafka,大略30w+的布控对象须要十多分钟那边能力预警到,于是开始进行性能优化,应用并行流进行解决,扭转之后同样30w的数据这次只须要8秒左右就能发送实现,然而跑了一阵之后程序开始呈现报错 Received invalid metadata error in produce request on partition xxxTopic due to org.apache.kafka.common.errors.NetworkException: The server disconnected before a response was received.. Going to request metadata update now 第一眼看到这个错,我认为是kafka或者网络出问题了,也去看了broker的日志,发现是有一些对于以后topic被删除的谬误,然而日志级别只是一个info,我认为是topic呈现谬误,又尝试了应用kakfa的生产命令,发现是可能失常生产的,阐明这个topic和metadata应该是没有问题的。我也在网上搜寻着,发现很少有这个问题的阐明,然而我发现了一些特色,通过我重启后程序又是能够持续发送的,而且速度还是很快,然而跑了一会儿,开始又有这个报错了,开始是一个报错,其余的都胜利,起初是缓缓的,报错越来越多,胜利的越来越少。接着过了很久居然还产生了nacos的心跳超时导致服务不可用的状况。我这时想到了之前看过的一些文章,说频繁fullgc可能会导致心跳申请失败的问题,最开始的时候看了cpu使用率,发现十分高,600%左右,我认为是因为我的程序外面因为是有定时工作去循环发送音讯所有有点占用是失常的,没有当回事,起初我用起了arthas和gc命令,先应用dashboard,看了下cpu线程,发现gc线程占用以及那个并行流forkjoinpool的线程占用十分大的cpu利用率,而后full gc次数十分多,又应用 jstat -gcutil $pid 1000命令进行确认,开始我就发现了old区的占用比十分高,且fullgc的频率十分高,简直是几秒钟就有一次,最重要的是,最开始是能回收一些内存,随着工夫的推移,old区占用比基线始终在增长,最初到了100,在这个过程中我也发现了,呈现报错的频率和old区占用比之间是存在关系的,报错越来越多的时候,old区被占用的越多,fullgc越频繁。这里我才意识到这是呈现内存透露的问题了吧,可能是我写的代码有点问题,于是我持续开始排查,通过 jmap dump:format=b,file=xx.hprof $pid而后导出文件到本地,用java visualvm关上(也能够用mat,我这里解析类实例的还报了堆内存不足,要改一下/lib/visualvm/etc/visualvm.conf,把-xms改大点)

August 17, 2023 · 1 min · jiezi

关于java:230816Bug总结

1.sql语句报错查看之后发现是最初少了一个小括号 2.ReflectionException反射异样解决:在xml中写sql的时候没有指定返回的数据 3.依赖导入异样在定义实体类的时候对变量的数据格式填写谬误.批改后程序失常运行

August 17, 2023 · 1 min · jiezi

关于java:也谈不可变对象

前言很久之前跟敌人聊String的不可变性,那个时候对这个问题不感兴趣,感觉这个问题的价值不高,这段时间写DDD感觉有点卡文,索性就来摸索这个问题。所谓不可变性也就是指咱们不能够批改这个对象,如下代码: String s = "hello world";String upperCase = s.toUpperCase();System.out.println(System.identityHashCode(s));System.out.println(System.identityHashCode(upperCase));输入值是不同的。咱们来解释一下上述代码做了什么,首先咱们String类型的援用变量s,并将其存储到栈外面,而后咱们用=,示意让s存储字符串hello world的地址,咱们通过援用变量s就能调用字符串对象hello world的toUpperCase办法,将字符串转为大写。而后申明一个String类型的援用变量,接管这个办法的返回值。而后咱们调用输入语句打印出s和upperCase对应变量的hashCode。输入值不同阐明s和upperCase指向的是不同的对象,个别咱们一般的对象批改成员变量,批改的还是本来的对象,所以咱们能够这么做: Card card = new Card("test card");System.out.println(System.identityHashCode(card));card.setCardNumber("4444");System.out.println(System.identityHashCode(card));你会发现打印的都是一样的,这就代表咱们批改的是援用变量card指向的对象。然而对字符串援用变量每一次调用批改的办法,咱们再应用identityHashCode办法取得对象的hashCode值会发现,每次都不一样,这就是在阐明对于String对象的每一次产生批改动作的时候,都会产生一个新的对象。这也就是不可变对象(immutable object)的真义。咱们能够toUpperCase办法来验证咱们的论断: public String toUpperCase() { return toUpperCase(Locale.getDefault());}public String toUpperCase(Locale locale) { if (locale == null) { throw new NullPointerException(); } int firstLower; final int len = value.length; /* Now check if there are any characters that need to be changed. */ scan: { for (firstLower = 0 ; firstLower < len; ) { int c = (int)value[firstLower]; int srcCount; if ((c >= Character.MIN_HIGH_SURROGATE) && (c <= Character.MAX_HIGH_SURROGATE)) { c = codePointAt(firstLower); srcCount = Character.charCount(c); } else { srcCount = 1; } int upperCaseChar = Character.toUpperCaseEx(c); if ((upperCaseChar == Character.ERROR) || (c != upperCaseChar)) { break scan; } firstLower += srcCount; } return this; } /* result may grow, so i+resultOffset is the write location in result */ int resultOffset = 0; char[] result = new char[len]; /* may grow */ /* Just copy the first few upperCase characters. */ System.arraycopy(value, 0, result, 0, firstLower); String lang = locale.getLanguage(); boolean localeDependent = (lang == "tr" || lang == "az" || lang == "lt"); char[] upperCharArray; int upperChar; int srcChar; int srcCount; for (int i = firstLower; i < len; i += srcCount) { srcChar = (int)value[i]; if ((char)srcChar >= Character.MIN_HIGH_SURROGATE && (char)srcChar <= Character.MAX_HIGH_SURROGATE) { srcChar = codePointAt(i); srcCount = Character.charCount(srcChar); } else { srcCount = 1; } if (localeDependent) { upperChar = ConditionalSpecialCasing.toUpperCaseEx(this, i, locale); } else { upperChar = Character.toUpperCaseEx(srcChar); } if ((upperChar == Character.ERROR) || (upperChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) { if (upperChar == Character.ERROR) { if (localeDependent) { upperCharArray = ConditionalSpecialCasing.toUpperCaseCharArray(this, i, locale); } else { upperCharArray = Character.toUpperCaseCharArray(srcChar); } } else if (srcCount == 2) { resultOffset += Character.toChars(upperChar, result, i + resultOffset) - srcCount; continue; } else { upperCharArray = Character.toChars(upperChar); } /* Grow result if needed */ int mapLen = upperCharArray.length; if (mapLen > srcCount) { char[] result2 = new char[result.length + mapLen - srcCount]; System.arraycopy(result, 0, result2, 0, i + resultOffset); result = result2; } for (int x = 0; x < mapLen; ++x) { result[i + resultOffset + x] = upperCharArray[x]; } resultOffset += (mapLen - srcCount); } else { result[i + resultOffset] = (char)upperChar; } } return new String(result, 0, len + resultOffset);}验证咱们的论断其实只用看toUpperCase的返回语句就能够,咱们在toUpperCase的return语句之中看到,又new了一个 String返回给咱们。在这个办法中有个语法是咱们未曾看到过的: ...

August 17, 2023 · 5 min · jiezi

关于java:这几个SQL语法的坑你踩过吗

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、常见框架、分布式、微服务、设计模式、架构等外围知识点,欢送star~ 地址:https://github.com/Tyson0314/Java-learning 大家好,我是大彬~ 明天给大家分享几个SQL常见的“坏毛病”及优化技巧。 SQL语句的执行程序: [外链图片转存失败,源站可能有防盗链机制,倡议将图片保留下来间接上传(img-uvETY0Tv-1692201969979)(http://img.topjavaer.cn/img/sql优化1.png)] 1、LIMIT 语句分页查问是最罕用的场景之一,但也通常也是最容易出问题的中央。比方对于上面简略的语句,个别 DBA 想到的方法是在 type, name, create_time 字段上加组合索引。这样条件排序都能无效的利用到索引,性能迅速晋升。 SELECT *FROM operationWHERE type = 'SQLStats' AND name = 'SlowLog'ORDER BY create_timeLIMIT 1000, 10;好吧,可能90%以上的 DBA 解决该问题就到此为止。但当 LIMIT 子句变成 “LIMIT 1000000,10” 时,程序员依然会埋怨:我只取10条记录为什么还是慢? 要晓得数据库也并不知道第1000000条记录从什么中央开始,即便有索引也须要从头计算一次。呈现这种性能问题,少数情景下是程序员偷懒了。 在前端数据浏览翻页,或者大数据分批导出等场景下,是能够将上一页的最大值当成参数作为查问条件的。SQL 从新设计如下: SELECT *FROM operationWHERE type = 'SQLStats'AND name = 'SlowLog'AND create_time > '2017-03-16 14:00:00'ORDER BY create_time limit 10;在新设计下查问工夫根本固定,不会随着数据量的增长而发生变化。 2、隐式转换SQL语句中查问变量和字段定义类型不匹配是另一个常见的谬误。比方上面的语句: mysql> explain extended SELECT * > FROM my_balance b > WHERE b.bpn = 14000000123 > AND b.isverified IS NULL ;mysql> show warnings;| Warning | 1739 | Cannot use ref access on index 'bpn' due to type or collation conversion on field 'bpn'其中字段 bpn 的定义为 varchar(20),MySQL 的策略是将字符串转换为数字之后再比拟。函数作用于表字段,索引生效。 ...

August 17, 2023 · 7 min · jiezi

关于java:记录遇到过的报错SQLSyntaxErrorExceptionExecutorException

1. 想必各位出这个错的也跟我一样批量操作SQL的时候,最初一个字段也加上了个","遗记删除了吧### Error updating database. Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') VALUES ('李四', 'lisi', 'e10adc3949b' at line 12### The error may exist in file [E:\fortyThousand\codes\projectOne\sky-server\target\classes\mapper\EmployeeMapper.xml]### The error may involve com.sky.mapper.EmployeeMapper.save-Inline### The error occurred while setting parameters### SQL: INSERT INTO employee (name, username, password, phone, sex, id_number, status, create_time, update_time, create_user, update_user,) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,)### Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') VALUES ('李四', 'lisi', 'e10adc3949b' at line 12; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') VALUES ('李四', 'lisi', 'e10adc3949b' at line 12] with root causejava.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') VALUES ('李四', 'lisi', 'e10adc3949b' at line 12 at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120) ~[mysql-connector-java-8.0.30.jar:8.0.30] at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.30.jar:8.0.30] at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:916) ~[mysql-connector-java-8.0.30.jar:8.0.30] at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:354) ~[mysql-connector-java-8.0.30.jar:8.0.30] at com.alibaba.druid.pool.DruidPooledPreparedStatement.execute(DruidPooledPreparedStatement.java:497) ~[druid-1.2.1.jar:1.2.1] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:59) ~[mybatis-3.5.7.jar:3.5.7] at jdk.proxy3/jdk.proxy3.$Proxy105.execute(Unknown Source) ~[na:na] at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:47) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76) ~[mybatis-3.5.7.jar:3.5.7] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) ~[mybatis-3.5.7.jar:3.5.7] at jdk.proxy2/jdk.proxy2.$Proxy103.update(Unknown Source) ~[na:na] at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:194) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:181) ~[mybatis-3.5.7.jar:3.5.7] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) ~[mybatis-spring-2.0.6.jar:2.0.6] at jdk.proxy2/jdk.proxy2.$Proxy82.insert(Unknown Source) ~[na:na] at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:272) ~[mybatis-spring-2.0.6.jar:2.0.6] at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:62) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86) ~[mybatis-3.5.7.jar:3.5.7] at jdk.proxy2/jdk.proxy2.$Proxy83.save(Unknown Source) ~[na:na] at com.sky.service.impl.EmployeeServiceImpl.save(EmployeeServiceImpl.java:101) ~[classes/:na] at com.sky.controller.admin.EmployeeController.save(EmployeeController.java:60) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.22.jar:5.3.22] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.22.jar:5.3.22] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.22.jar:5.3.22] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.22.jar:5.3.22] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.22.jar:5.3.22] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.22.jar:5.3.22] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1070) ~[spring-webmvc-5.3.22.jar:5.3.22] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.22.jar:5.3.22] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.22.jar:5.3.22] at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.22.jar:5.3.22] at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[tomcat-embed-core-9.0.65.jar:4.0.FR] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.22.jar:5.3.22] at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.65.jar:4.0.FR] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.22.jar:5.3.22] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.22.jar:5.3.22] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]2. 没找到后果映射解决办法:在SQL中指定一下返回后果映射resultType ...

August 16, 2023 · 4 min · jiezi

关于java:京东面试题ElasticSearch深度分页解决方案

大家好,我是不才陈某~ Elasticsearch 是一个实时的分布式搜寻与剖析引擎,在应用过程中,有一些典型的应用场景,比方分页、遍历等。 在应用关系型数据库中,咱们被告知要留神甚至被明确禁止应用深度分页,同理,在 Elasticsearch 中,也应该尽量避免应用深度分页。 这篇文章次要介绍 Elasticsearch 中分页相干内容! 关注公众号:码猿技术专栏,回复关键词:1111 获取阿里外部Java性能调优手册!From/Size参数在ES中,分页查问默认返回最顶端的10条匹配hits。 如果须要分页,须要应用from和size参数。 from参数定义了须要跳过的hits数,默认为0;size参数定义了须要返回的hits数目的最大值。一个根本的ES查问语句是这样的: POST /my_index/my_type/_search{ "query": { "match_all": {}}, "from": 100, "size": 10}下面的查问示意从搜寻后果中取第100条开始的10条数据。 那么,这个查问语句在ES集群外部是怎么执行的呢? 在ES中,搜寻个别包含两个阶段,query 和 fetch 阶段,能够简略的了解,query 阶段确定要取哪些doc,fetch 阶段取出具体的 doc。 Query阶段 如上图所示,形容了一次搜寻申请的 query 阶段:· Client 发送一次搜寻申请,node1 接管到申请,而后,node1 创立一个大小为from + size的优先级队列用来存后果,咱们管 node1 叫 coordinating node。coordinating node将申请播送到波及到的 shards,每个 shard 在外部执行搜寻申请,而后,将后果存到外部的大小同样为from + size 的优先级队列里,能够把优先级队列了解为一个蕴含top N后果的列表。每个 shard 把暂存在本身优先级队列里的数据返回给 coordinating node,coordinating node 拿到各个 shards 返回的后果后对后果进行一次合并,产生一个全局的优先级队列,存到本身的优先级队列里。在下面的例子中,coordinating node 拿到(from + size) * 6条数据,而后合并并排序后抉择后面的from + size条数据存到优先级队列,以便 fetch 阶段应用。 ...

August 16, 2023 · 3 min · jiezi

关于java:Java扩展Nginx之四远程调试

欢送拜访我的GitHub这里分类和汇总了欣宸的全副原创(含配套源码):https://github.com/zq2599/blog_demos本篇概览本文是《Java扩大Nginx》系列的第四篇,一起来体验个实用的性能,此能力定会让爱学习的您大呼过瘾,它就是宽广java程序员在日常开发和定位问题过程中罕用的神技:近程调试;看变量、看堆栈,不管浏览代码还是定位问题,打断点都是咱们最值得信赖的伎俩,当您的代码运行在nginx-clojure模块中的时候,如果能像tomcat那样近程打断点,单步调试,会大幅度提高工作效率近程断点的成果如下图所示,通过IDEA的<font color="blue">Remote JVM Debug</font>性能近程连贯到nginx-clojure监听的近程debug端口,当浏览器申请触发了java代码的执行时,就会进入断点状态,停留在断点地位,能够看到堆栈和内存中的变量状况,以及单步执行: 对于工具本篇应用的编码工具是IntelliJ IDEA 2021.3.2 (Ultimate Edition) 对于代码本篇间接应用《Java扩大Nginx之一:你好,nginx-clojure》中的工程和代码,这里简略回顾如下,只有一个类: package com.bolingcavalry.simplehello;import nginx.clojure.java.ArrayMap;import nginx.clojure.java.NginxJavaRingHandler;import java.time.LocalDateTime;import java.util.Map;import static nginx.clojure.MiniConstants.CONTENT_TYPE;import static nginx.clojure.MiniConstants.NGX_HTTP_OK;public class HelloHandler implements NginxJavaRingHandler { @Override public Object[] invoke(Map<String, Object> request) { return new Object[] { NGX_HTTP_OK, //http status 200 ArrayMap.create(CONTENT_TYPE, "text/plain"), //headers map "Hello, Nginx clojure! " + LocalDateTime.now() //response body can be string, File or Array/Collection of them }; }}在nginx.conf中,配置了一个location,path是<font color="blue">/java</font>: location /java { content_handler_type 'java'; content_handler_name 'com.bolingcavalry.simplehello.HelloHandler';}以上就是明天要打断点调试的代码和配置了 nginx-clojure的近程调试配置关上nginx.conf文件,在http的配置中减少以下两行,即可开启nginx-clojure的近程调试: ...

August 16, 2023 · 1 min · jiezi

关于java:分页查询PageHelper

1、写一个存储数据的总条数和所有数据汇合的实体类 @Data@NoArgsConstructor //无参结构器@AllArgsConstructor //全参结构器@Builder //构建者设计模式public class PageBean<T> {/** * 总条数 */private Long total;/** * 当前页汇合 */private List<T> rows;}2、在mapper层写一个查询数据库所有数据的办法 @Select("select id,username,password,name,gender,image,job,entrydate,dept_id,create_time,update_time from emp")List<Emp> findList2(); 3、在service层执行mapper层办法,并调用PageHelper的startPage办法设置页数和每页多少条数据,而后把数据库的数据强转为Page对象,封装成自定义的对象返回 @Overridepublic PageBean<Emp> findByPage(Integer page, Integer pageSize) { //设置分页参数PageHelper.startPage(page,pageSize);//执行查问List<Emp> empList = empMapper.findList2();//查问后果转为Page对象Page<Emp> p = (Page<Emp>) empList;//封装对象返回return new PageBean<>(p.getTotal(),p.getResult());}4、controller层调用service层办法,把前端分页的参数传给service办法中履行分页,传给前端实体类以供前端进行操作

August 15, 2023 · 1 min · jiezi

关于java:Spring事务管理

1.1.什么是事务?事务是一组操作的汇合,它是一个不可分割的工作单位。事务会把所有的操作作为一个整体,一起向数据库提交或者是撤销操作申请。所以这组操作要么同时胜利,要么同时失败。 事务的操作次要有三步: 开启事务(一组操作开始前,开启事务):start transaction / begin ;提交事务(这组操作全副胜利后,提交事务):commit ;回滚事务(两头任何一个操作出现异常,回滚事务):rollback ;1.2 Spring事务管理1.2.1 案例需要:当部门遣散了不仅须要把部门信息删除了,还须要把该部门下的员工数据也删除了。 步骤: 依据ID删除部门数据依据部门ID删除该部门下的员工代码实现: DeptServiceImpl@Slf4j@Servicepublic class DeptServiceImpl implements DeptService { @Autowired private DeptMapper deptMapper; @Autowired private EmpMapper empMapper; //依据部门id,删除部门信息及部门下的所有员工 @Override public void delete(Integer id){ //依据部门id删除部门信息 deptMapper.deleteById(id); //删除部门下的所有员工信息 empMapper.deleteByDeptId(id); }}DeptMapper@Mapperpublic interface DeptMapper { /** * 依据id删除部门信息 * @param id 部门id */ @Delete("delete from dept where id = #{id}") void deleteById(Integer id);}EmpMapper@Mapperpublic interface EmpMapper { //依据部门id删除部门下所有员工 @Delete("delete from emp where dept_id=#{deptId}") public int deleteByDeptId(Integer deptId); }在办法运行之前,开启事务,如果办法胜利执行,就提交事务,如果办法执行的过程当中出现异常了,就回滚事务。 ...

August 15, 2023 · 1 min · jiezi

关于java:开源免费的文件投喂与问答工具构建你的第二大脑

利用AI帮你读文章、利用AI帮你剖析非结构化数据,这些最为潮流的AI辅助工具,置信很多读者都在各种媒体上看到过了。但还是有不少人并没有真正的应用过,这里有很多起因导致,具体就不细说了,懂的都懂。 明天TJ就给大家举荐一个你能够在线应用,也能够本人搭建的AI辅助工具:Quivr。Quivr简直能够解决任何类型的数据,包含:文本、图像、代码、音视频。采纳GPT来检索和输入。以速度和效率为外围设计,确保快速访问解决您的数据并为您服务。 上面就来一起意识和体验一下它吧! 应用体验Quivr上手非常简单,能够间接通过官网网站登录之后,上传一个你要让AI学习的文件: 对于上传文件,目前曾经反对以下文本和音视频内容: TextMarkdownPDFPowerpointCSVWordAudioVideo上传实现之后,进入聊天框,你就能够间接对AI进行发问了,Quivr会依据学习到的内容来答复您: 对于AI的配置还能够通过右下角的设置按钮做进一步微调,比方:采纳更高级的GPT-4模型: 在线应用是不是很简略呢? 如果你还有更高的需要,比方:本人搭建的话,能够进入它的开源我的项目,部署本人的服务或者基于其做二次开发: 最初,奉上相干链接,感兴趣的小伙伴,连忙冲吧! 开源地址:https://github.com/StanGirard/quivr官网网站:https://www.quivr.app欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

August 15, 2023 · 1 min · jiezi

关于java:谈谈对CAS的理解

谈谈对CAS的了解CAS 是 Compare and Swap(比拟并替换)的缩写,是一种并发编程中罕用的原子操作。它是一种乐观锁技术,用于解决多线程环境下的并发问题。 CAS 操作蕴含三个参数:内存地址(或变量的援用)、期望值和更新值。CAS 操作的执行过程如下: 首先,它比拟内存地址中的值与期望值是否相等。如果相等,阐明内存中的值与期望值统一,能够进行更新操作。CAS 通过原子形式将内存中的值更新为新的值。如果更新胜利,CAS 操作返回 true;否则,返回 false。CAS 操作是原子的,意味着在执行期间不会被其余线程中断。因而,它能够保障在多线程环境下,对共享变量进行原子操作,防止了传统锁机制的开销。 CAS 的一个重要利用是实现无锁数据结构,例如非阻塞算法和无锁队列。它能够在不应用锁的状况下,实现线程平安的数据操作。 然而,CAS 也存在一些限度和问题。首先,CAS 操作须要在执行期间对比拟的值放弃不变,否则会导致更新失败。其次,CAS 操作在高并发环境下可能会呈现自旋重试的状况,减少了 CPU 的开销。最初,CAS 操作无奈解决 ABA 问题,即一个值被批改为其余值,而后又被批改回原来的值,这种状况下 CAS 无奈感知到两头的批改。 为了解决 CAS 的限度和问题,Java 提供了 java.util.concurrent.atomic 包,其中蕴含了一些基于 CAS 的原子类,例如 AtomicInteger、AtomicLong 等,它们提供了更高级别的原子操作,能够更不便地实现线程平安的操作。 CAS的底层原理?CAS(Compare and Swap)是一种并发编程中的原子操作,用于实现无锁算法。它的底层原理能够简略形容为以下几个步骤: 比拟:首先,CAS 操作会比拟共享变量的以后值与期望值是否相等。如果相等,则继续执行后续步骤;如果不相等,则示意其余线程曾经批改了共享变量,CAS 操作失败。替换:如果比拟相等,CAS 操作会尝试将共享变量的以后值批改为新的值。这个批改操作是原子的,不会被其余线程中断。查看后果:CAS 操作会返回批改前的旧值。开发人员能够依据返回的后果来判断 CAS 操作是否胜利。CAS 操作的关键在于硬件提供的原子性操作指令。在古代计算机体系结构中,通常应用原子性的 CPU 指令来实现 CAS 操作。这些指令保障了比拟和替换这两个步骤的原子性,确保在多线程环境下的正确性。 须要留神的是,CAS 操作依然存在竞态条件,即多个线程同时执行 CAS 操作时可能会导致抵触。为了解决这个问题,CAS 操作通常联合循环重试的形式应用,即在 CAS 操作失败时,反复执行整个 CAS 操作过程,直到胜利为止。 总结起来,CAS 的底层原理是通过比拟共享变量的值与期望值,并在比拟相等的状况下原子地替换新值,以实现无锁的并发操作。这种原子操作的实现依赖于底层硬件提供的原子性指令。 谈谈对UnSafe的了解Unsafe 是 Java 中一个十分非凡的类,它提供了一些底层的、间接操作内存和线程的办法。它位于 sun.misc 包中,是一个不稳固的、不举荐应用的类,通常状况下不应该间接应用它。 ...

July 13, 2023 · 2 min · jiezi

关于java:volatile关键字

谈谈你对 volatile 的了解?在Java中,volatile 是一个关键字,用于润饰变量。它的次要目标是保障多线程环境下的可见性和有序性。 当一个变量被申明为 volatile 时,它将具备以下个性: 可见性(Visibility):volatile 变量在多线程环境下,当一个线程批改了该变量的值,其余线程能够立刻看到最新的值。这是因为 volatile 变量的值会被立刻刷新到主内存中,并且读取操作时会从主内存中获取最新的值。有序性(Ordering):volatile 变量的读写操作都是依照申明程序执行的,不会被重排序。这意味着在多线程环境下,对 volatile 变量的操作不会受到指令重排的影响,保障了操作的有序性。然而,volatile 并不能解决所有的并发问题。它实用于以下场景: 状态标记:当一个变量用于示意状态标记,多个线程须要共享该标记并对其进行批改时,应用 volatile 能够确保所有线程都能看到最新的标记值。双重查看锁定(Double-Checked Locking):在单例模式中,应用双重查看锁定能够在保障线程平安的状况下进步性能。在这种状况下,将单例对象申明为 volatile 能够防止指令重排导致的线程平安问题。须要留神的是,volatile 并不能保障原子性。对于复合操作,例如 i++,volatile 不能保障线程平安,须要应用其余的同步机制,例如 synchronized 或 Lock。 总之,volatile 是一种轻量级的同步机制,用于保障变量的可见性和有序性。它实用于一些特定的并发场景,但并不能解决所有的并发问题。在编写多线程代码时,须要依据具体的需要抉择适合的同步机制。 volatile 关键字次要用于以下几个方面:状态标记位: public class Example { private volatile boolean flag = false; public void setFlag() { flag = true; } public void doSomething() { while (!flag) { // 期待标记位变为 true } // 执行工作 }}在上述示例中,flag 被申明为 volatile,它用作一个状态标记位。doSomething() 办法在一个循环中期待 flag 变为 true,而 setFlag() 办法用于批改 flag 的值。应用 volatile 润饰 flag 能够保障在一个线程批改了 flag 的值后,其余线程能够立刻看到最新的值,从而实现线程间的通信。 ...

July 13, 2023 · 2 min · jiezi

关于java:一万字带你吃透RocketMQ

前言工作中很多种场景下会用到音讯队列,音讯队列简略来说就是 音讯的传输过程中保留音讯的容器。音讯队列次要解决了利用耦合、异步解决、流量削峰等问题。明天咱们来理解一下阿里开源的一款产品 RocketMQ。 RocketMQ简介RocketMQ 是一款低提早、高并发、高可用、高牢靠的分布式消息中间件。具备异步通信的劣势,零碎拓扑简略、上下游耦合较弱,次要利用于异步解耦,流量削峰填谷等场景。 NameServerNameServer 是整个 RocketMQ 的“大脑”,是 RocketMQ 的 路由核心。NameServer 的次要作用是为音讯生产者和音讯消费者提供无关 Topic 的路由信息,所以 NameServer 就须要存储路由信息,并且可能治理 Broker 节点,包含路由注册、路由删除等性能。 路由核心高可用“大脑”一旦故障,那可不是闹着玩的,那么必然要有对策来解决。NameServer 的 高可用能够通过部署多台 NameServer 服务器来实现,但彼此之间互不通信。尽管 NameServer 服务器之间在某一时刻的数据并不会完全相同,但对音讯发送不会在成重大影响,无非就是短暂造成音讯发送不平衡(是不是有很相熟的滋味呢?没错CAP实践,这不就是AP嘛)。RocketMQ 在 NameServer 这个模块的设计上抉择了 AP。 元数据存储既然是路由核心,那么路由信息是如何存储的呢?咱们来看一下RouteInfoManager这个类。 public class RouteInfoManager { // Topic音讯队列的路由信息 private final HashMap<String/* topic */, List<QueueData>> topicQueueTable; // Broker的根底信息 private final HashMap<String/* brokerName */, BrokerData> brokerAddrTable; // Broker的集群信息 private final HashMap<String/* clusterName */, Set<String/* brokerName */>> clusterAddrTable; // Broker的状态信息,NameServer每次收到心跳包时会替换该信息 private final HashMap<String/* brokerAddr */, BrokerLiveInfo> brokerLiveTable; // Broker对应的FilterServer列表,用于类模式音讯过滤。类模式过滤机制在4.4及当前版本被废除 private final HashMap<String/* brokerAddr */, List<String>/* Filter Server */> filterServerTable;}NameServer 存储的信息,就在RouteInfoManager这个类里。 ...

July 13, 2023 · 3 min · jiezi

关于java:全栈教程Spring-Boot-和-Vuejs-入门

在本教程中,你将创立一个 CoffeeBot 应用程序。该应用程序就像机器人咖啡机的控制器。遗憾的是,它实际上不会为你提供咖啡,但它将演示大量有用的编程技术。该应用程序将有一个 Vue.js 客户端和一个 Spring Boot 资源服务器。它将应用 JHipster 进行疏导,节俭大量工夫并演示一些最佳实际,包含在客户端和服务器中主动配置端到端 JWT 身份验证。你还将应用 Split 来展现如何别离应用 Split 的 Javascript SDK 和 Java SDK 在运行时动静地应用性能标记来治理前端和后端的功能集。该应用程序自身提供饮料。服务器保护着一份饮料清单,次要是咖啡,附有尺寸、价格和名称。为简略起见,饮料列表将应用内存中的开发数据库进行保留,但如果须要,能够轻松地重新配置以实现持久性。客户端从服务器申请饮料列表,如果用户通过身份验证,则传递任何身份验证数据。 客户端接管此列表并将饮料列表显示为按钮列表。第二次宰割纯正与客户无关。增加了一项新性能:可能在饮料中增加奶油。正如你能够设想的那样,思考到人们对咖啡中奶油的青睐水平,虚构骚乱曾经开始要求此性能。人们在叫嚷。但经理们心愿在宽泛公布之前确保奶油性能失常工作(CoffeeBot 有时会失灵)。因而,依据通过身份验证的用户,增加奶油的能力被切换。你能够在这个链接: 看到如何应用 Split 的 Javascript SDK 来管制客户端的奶油性能,以及如何应用 Split 的 Java SDK 来管制服务器的饮料列表 Java + Vue.js 教程依赖项Java:我在本教程中应用了 Java 12。你能够拜访AdaptOpenJdk 网站下载并装置 Java 。或者你能够应用SDKMAN甚至Homebrew等版本管理器。 Node:依照 Node网站上的阐明装置 Node 。本教程是应用 Node 12.14.0 编写的。 JHipster:一旦装置了 Java 和 Node,就能够装置 JHipster。依照其网站上的阐明进行操作(如果呈现问题,有助于排除故障)或只需运行此命令:npm install -g generator-jhipster@6.9.0应用npm. 拆分:如果你还没有收费的拆分帐户,请注册一个。这就是实现性能标记的形式。 应用 JHipster 疏导你的 Spring Boot 应用程序要创立示例 CoffeBot 应用程序,你将应用 JHipster。正如其网站上所述,“JHipster 是一个疾速生成、开发和部署古代 Web 应用程序和微服务架构的开发平台。” 它容许你疾速启动具备各种前端和服务器配置的基于 Java 的我的项目。本教程将应用 Vue.js。 ...

July 13, 2023 · 6 min · jiezi

关于java:用-Spring-管理-Controller你觉得可行吗

上篇文章和小伙伴们聊了 Spring 容器中的父子容器问题,也和小伙伴们梳理了 Spring 容器和 SpringMVC 容器之间的关系,其中,Spring 容器是父容器,SpringMVC 是子容器,子容器能够拜访父容器中的 Bean,然而父容器无法访问子容器中的 Bean。 在一个 SSM 我的项目中,你能够单纯应用 SpringMVC 容器,这个没问题,我的项目能够失常运行。然而,有的小伙伴可能要问了,如果把所有的 Bean 都扫描到 Spring 容器中行不行? 先来说论断:能够!然而须要额定配置。 浏览本文须要先理解 Spring 容器的父子容器哦,如果还不理解的话倡议先浏览上篇文章。 为什么不能把所有 Bean 都注册到 Spring 容器中呢?依照咱们上篇文章中的剖析,所有 Bean 都注册到 Spring 容器之后,Spring 容器作为父容器,SpringMVC 作为子容器,按理说,因为子容器能够拜访父容器中的 Bean,所以 SpringMVC 是能够失常拜访 Spring 容器中的 Bean 的,所以,仿佛把所有的 Bean 都扫描到 Spring 容器应该是没有问题的? 其实不然! 问题就出在 SpringMVC 容器查找 Controller 的形式上,SpringMVC 容器查找 Controller,默认状况下,只在以后容器中查找,并不会去父容器中查找,所以如果把 Controller 都扫描到父容器的话,对于 SpringMVC 来说,相当于零碎中就没有 Controller 了,所以你一拜访,间接就 404 了。 接下来,我联合源码和小伙伴们剖析一下。 首先,小伙伴们晓得,在 SpringMVC 中,当申请达到服务端之后,须要由处理器映射器 HandlerMapping 来确定这个申请应该由哪个处理器来解决,所以,按理说,HandlerMapping 中就会记录所有的处理器信息,也就是 Controller 的信息。个别咱们在 SpringMVC 中应用的 HandlerMapping 都是 RequestMappingHandlerMapping,所以这里咱们就通过 RequestMappingHandlerMapping 的初始化来看一下,SpringMVC 到底是如何查找 Controller 的。 ...

July 13, 2023 · 2 min · jiezi

关于java:springbootplus2712-版本重磅发布三年磨一剑兄弟们等久了感谢你们的陪伴

spring-boot-plus是一套集成spring boot罕用开发组件的后盾疾速开发框架Spring-Boot-Plus是易于应用,疾速,高效,功能丰富,开源的spring boot 脚手架.指标每个人都能够独立、疾速、高效地开发我的项目!开源协定 MIT-License任何集体或公司,均可基于此框架进行二次开发后,进行商业应用,无需受权!GITHUB | GITEE[V2.7.12] 2023.7.10单体架构公布,更简略实用⭐️ New Features多模块变更为单体架构框架代码重构,更精简,更易懂springboot降级为2.7.12mybatis-plus降级为3.5.3.1应用pagehelper分页,更不便去掉mapstruct,应用Spring的BeanUtils用户降级为多角色治理,更灵便应用Vue3、TS重构前端页面应用SwaggerV3去掉Shiro,应用拦截器实现登录鉴权去掉JWT,应用自定义生成token登录性能重构,登录鉴权相干放在auth登录反对用户单回话或多回话同时在线配置生成代码重构,新增addDto、updateDto、infoVo部署脚本优化新增JsonRequestBodyFilter过滤器,打印实在json申请参数新增GlobalStringTrimHandler处理器,全局字符串去除空格新增DataRangeAop数据范畴切面,数据范畴过滤新增TraceIdLogFilter,日志链路ID,方面定位起因新增IpRegionUtil,获取ip归属地信息xss反对自定义启用禁用申请日志记录字段欠缺拜访我的项目Swagger文档http://localhost:8888/swagger-ui/index.html 拜访Knife4j文档http://localhost:8888/doc.html spring-boot-plus-vue 前端我的项目GITHUB-REPO零碎用户列表 零碎角色列表 零碎菜单列表 零碎部门列表 系统日志 集体核心

July 13, 2023 · 1 min · jiezi