关于java:面试官说说SpringAOP实现原理

<article class=“article fmt article-content”><p>AOP(Aspect-Oriented Programming,面向切面编程)是一种编程技术,它容许开发者在不扭转现有代码的状况下,减少新的性能或行为,这些性能或行为被称为“切面”。</p><p>AOP 能够通过预编译形式和运行期动静代理的形式来实现,它的次要目标是升高业务逻辑的耦合性,进步程序的可重用性和开发效率。</p><p>AOP 罕用于对立性能的解决,例如:事务管理、日志记录、权限查看等性能。</p><h2>1.AOP长处剖析</h2><p>应用 AOP 的次要起因有以下几点:</p><ol><li><strong>模块化</strong>:通过将公共行为(如日志记录、事务管理)提取为独立的切面,能够使代码更加模块化,进步代码的可维护性和可读性。</li><li><strong>缩小反复代码</strong>:通过应用 AOP,能够将反复的代码(如日志记录、权限查看)提取到一个切面中,防止在多个中央反复编写雷同的代码。</li><li><p><strong>解耦</strong>:AOP 容许开发者将业务逻辑与横切关注点(如日志记录、事务管理)拆散,从而升高业务逻辑的耦合性,进步程序的可重用性和可扩展性。</p><h2>2.AOP技术实现</h2><p>AOP 实现技术次要分为两大类:动态代理和动静代理。</p></li><li><strong>动态代理</strong>:通过 AOP 框架提供的命令进行编译,从而在编译阶段生成 AOP 代理类。这种形式也被称为编译时加强。动态代理包含编译时编织和类加载时编织两种形式。</li><li><p><strong>动静代理</strong>:在运行时在内存中“长期”生成 AOP 动静代理类,因而也被称为运行时加强。动静代理次要有两种实现形式:</p><ol><li><strong>JDK 动静代理</strong>:JDK 动静代理要求被代理的类必须实现一个接口,它通过反射来接管被代理的类,并应用 InvocationHandler 接口和 Proxy 类实现代理。</li><li><p><strong>CGLIB 动静代理</strong>:CGLIB 则是一个代码生成的类库,它能够在运行时动静地生成某个类的子类,通过继承的形式实现代理。如果指标类没有实现接口,Spring AOP 会抉择应用 CGLIB 来动静代理指标类。</p><h2>3.AOP实现原理</h2><p>Spring AOP(面向切面编程)的实现原理次要基于动静代理技术,它提供了对业务逻辑各个方面的关注点拆散和模块化,使得非功能性需要(如日志记录、事务管理、安全检查等)能够集中管理和保护,而不是扩散在各个业务模块中。</p></li></ol></li></ol><p>Spring AOP 实现原理的要害要点如下:</p><ol><li><p><strong>代理机制</strong>:</p><ul><li><strong>JDK 动静代理</strong>:对于实现了接口的指标类,Spring AOP 默认应用 JDK 的 java.lang.reflect.Proxy 类来创立代理对象。代理对象会在运行时实现代理接口,并笼罩其中的办法,在办法调用前后执行切面逻辑(即告诉,advice)。</li><li><strong>CGLIB 动静代理</strong>:对于未实现接口的类,Spring AOP 会抉择应用 CGLIB 库来生成代理对象。CGLIB 通过字节码技术创立指标类的子类,在子类中重写指标办法并在办法调用前后插入切面逻辑。</li></ul></li><li><p><strong>要害概念</strong>:</p><ul><li><strong>切面(Aspect)</strong>:切面是一个蕴含了横切关注点申明的模块化单元,它能够有多个切入点和告诉组成。</li><li><strong>切入点(Pointcut)</strong>:切入点定义了匹配告诉应该被织入的办法或办法执行点的规定表达式。</li><li><strong>告诉(Advice)</strong>:告诉是在特定切入点处执行的代码片段,分为多种类型,如前置告诉(Before advice)、后置告诉(After returning advice)、异样后告诉(After throwing advice)、最终告诉(After (finally) advice)以及盘绕告诉(Around advice)。</li></ul></li><li><strong>织入(Weaving)</strong>:织入是指将切面利用到指标对象来创立一个新的代理对象的过程。在 Spring AOP 中,织入产生在运行时,通过代理对象的形式实现。</li><li><strong>代理工厂</strong>:Spring 外部通过 ProxyFactory 或相干的 AOP 基础设施(如 Advisor、AdvisorChainFactory 等)来创立和治理代理对象。</li><li><strong>执行流程</strong>:当客户端通过代理对象调用指标办法时,代理对象会拦挡这个调用,依据切面配置找到对应的告诉,并依照告诉类型的不同执行相应的加强逻辑。例如,如果是盘绕告诉,它会齐全管制原始办法的调用过程,能够在调用前后插入自定义逻辑,甚至决定是否执行原办法。</li></ol><p>通过上述形式,Spring AOP 奇妙地实现了对指标对象办法的拦挡和加强,从而实现了面向切面编程的性能。</p><h2>课后思考</h2><p>Spring 动静代理生效的场景有哪些?Spring Boot 动静代理默认实现是 JDK 动静代理还是 CGLIB?怎么证实?</p><blockquote>本文已收录到我的面试小站 www.javacn.site,其中蕴含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、音讯队列等模块。</blockquote></article> ...

March 5, 2024 · 1 min · jiezi

关于java:导入Excel文件的时候公式为Ref应该怎么解决

<article class=“article fmt article-content”><p><strong>前言</strong></p><p>在咱们应用Excel时,常常会遇到一个问题,就是导入Excel时公式显示为【#Ref!】的状况。这通常是因为公式中援用的单元格已被删除或对应的工作表被删除,导致原公式无奈辨认对应的参数而显示为【#Ref!】。</p><p>比方在一张Excel表中,sheet1 中 A1 单元格的公式为‘=Sheet2!B1’,如果 Sheet2 因为各种历史起因失落,那么此时 sheet1 中 A1 计算结果为【#Ref!】,如果此时想查找到 Sheet2 怎么办呢?明天小编就将为大家介绍如何用葡萄城公司的Java API 组件——GrapeCity Documents for Excel(以下简称GcExcel)来查找失落的Sheet页。</p><p><strong>具体操作步骤</strong></p><p><strong>1)筹备</strong></p><p>首先创立公式</p><pre><code class=“Java”>Workbook workbook = new Workbook();IWorksheet workSheet = workbook.getWorksheets().get(0);workSheet.setName(“sheet1”);workSheet.getRange(1, 1).setFormula(“sheet2!F7”);workSheet.getRange(3, 3).setFormula(“Sheet3!A1”);</code></pre><p><strong>2)查找</strong></p><p>接下来,通过Find进行遍历查问所有的【#Ref!】公式,GcExcel提供了各种类型的查找替换。</p><pre><code class=“Java”>FindOptions tempVar = new FindOptions();//设置通过文本查找tempVar.setLookIn(FindLookIn.Texts);IRange range = null;do { range = searchRange.find(“Ref”, range, tempVar); if (range == null) { break; } else { //在这里做相应的逻辑 }} while (true);</code></pre><p>上述代码是查找替换的根底代码,咱们发现上述代码 searchRange 未定义,searchRange 能够是整个 sheet, 也能够是一片区域,接下来咱们定义searchRange 。</p><p><strong>3)非凡单元格</strong></p><p>GcExcel 提供了找到谬误公式的能力,通过 specialCells 能够查找到谬误公式,并返回谬误公式的区域为第二步中的searchRange变量 。</p><pre><code class=“Java”>IRange searchRange = workSheet.getCells().specialCells(SpecialCellType.Formulas, SpecialCellsValue.Errors);</code></pre><p>当初咱们曾经找到了对应的所有为【#Ref!】的单元格,接下来开始做查找胜利之后的逻辑。</p><p><strong>4)公式解析</strong></p><p>查找胜利后,能够通过 range.getFormula() 获取到公式,接下来对公式进行解析,因为 Excel 公式有的简略,有的简单,不能单纯判断等号后,感叹号前的字符串为sheet 名称,咱们要通过公式树去遍历解析。 <br/>GcExcel 提供了公式解析器,调用 parse 拿到公式树,之后能够通过 getWorksheetName) 获取 sheetName,相干代码如下:</p><pre><code class=“Java”>//将公式中等号去掉,并进行解析FormulaSyntaxTree syntaxTree = FormulaSyntaxTree.Parse(range.getFormula().replaceFirst("=", “”));addNotFoundSheet(syntaxTree.getRoot(), workbook);</code></pre><p>addNotFoundSheet 定义如下:</p><pre><code class=“Java”>private static void addNotFoundSheet(SyntaxNode node, Workbook workbook) { if (node == null) { return; } if (node instanceof ReferenceNode) { String sheetName = ((ReferenceNode) node).getReference().getWorksheetName(); if (workbook.getWorksheets().get(sheetName) == null) { IWorksheet tempSheet = workbook.getWorksheets().add(); tempSheet.setName(sheetName); } } for (SyntaxNode child : node.getChildren()) { addNotFoundSheet(child, workbook); } }</code></pre><p>在上述代码中首先判断node是否是 ReferenceNode 类型,如果是的话,通过 node.getReference().getWorksheetName() 获取 sheetName,并判断当前工作簿是否存在此sheet,如果不存在则进行增加。</p><p>解决后,对其子节点进行递归判断,反复上述步骤,直到 node 节点为 null,退出递归查问。</p><p>最初附上完整版的代码:</p><pre><code class=“Java”>public static void main(String[] args) throws Exception { Workbook workbook = new Workbook(); IWorksheet workSheet = workbook.getWorksheets().get(0); workSheet.setName(“sheet1”); workSheet.getRange(1, 1).setFormula(“sheet2!F7”); workSheet.getRange(3, 3).setFormula(“Sheet3!A1”); FindOptions tempVar = new FindOptions(); tempVar.setLookIn(FindLookIn.Texts); IRange searchRange = workSheet.getCells().specialCells(SpecialCellType.Formulas, SpecialCellsValue.Errors); IRange range = null; do { range = searchRange.find(“Ref”, range, tempVar); if (range == null) { break; } else { FormulaSyntaxTree syntaxTree = FormulaSyntaxTree.Parse(range.getFormula().replaceFirst("=", “”)); addNotFoundSheet(syntaxTree.getRoot(), workbook); } } while (true); } private static void addNotFoundSheet(SyntaxNode node, Workbook workbook) { if (node == null) { return; } if (node instanceof ReferenceNode) { String sheetName = ((ReferenceNode) node).getReference().getWorksheetName(); if (workbook.getWorksheets().get(sheetName) == null) { IWorksheet tempSheet = workbook.getWorksheets().add(); tempSheet.setName(sheetName); } } for (SyntaxNode child : node.getChildren()) { addNotFoundSheet(child, workbook); } }</code></pre><p>通过上述代码,能够查找到”sheet2“与”sheet3“,并进行增加。</p><p><strong>总结</strong></p><p>以上就是应用GcExcel解决导入Excel文件的时候公式为【#Ref!】问题的全过程,如果您想理解更多详细信息,欢送点击这里查看。</p></article> ...

March 5, 2024 · 2 min · jiezi

关于java:Java编程思想读书笔记一

很早之前就买了《Java编程思维》这本书,初学时看这本书看的云里雾里的,切实吃力,就放在一边垫桌底了。感觉这本书是适宜C/C++程序员转行到Java学习的一本书,并不适宜零根底的初学者去看这本书,毕竟当初花了一百多买了这本书,当初还是把它倒腾进去看一下吧,当作是坚固Java基础知识,本文会把本人感兴趣的知识点记录一下,相干实例代码:https://gitee.com/reminis_com/thinking-in-java第一章:对象导论 这一章次要是帮忙咱们理解面向对象程序设计的全貌,更多是介绍的背景性和补充性的资料。其实萌新应该跳过这一章,因为这章并不会去讲语法相干的常识,当然能够在看完这本书后续章节后,再来回看这一章,这样有助于咱们理解到对象的重要性,以及怎么应用对象进行程序设计。 Alan Kay已经总结了第一个胜利的面向对象语言、同时也是Java所基于的语言之一的Smalltalk的五个根本个性,这些个性体现了一种纯正的面向对象的程序设计形式: 万物皆为对象。实践上讲,你能够抽取待求解问题的任何概念化构件(狗、建筑物、服务等),将其示意为程序中的对象。程序是对象的汇合,它们通过发送音讯来告知彼此所要做的。要想申请一个对象,就必须对该对象发送一条音讯。更具体的说,能够把音讯设想为对某个特定对象的办法的调用申请。每个对象都有本人的由其它对象所形成的存储。换句话说,能够通过创立蕴含现有对象的形式来创立新类型的对象。每个对象都领有其类型。依照通用的说法,“每个对象都是某个类(class)的一个实例(instance)”,每个类最重要的区别与其余类的个性就是“能够发送什么样的音讯给它”。某一特定类型的所有对象都能够承受同样的音讯。第二章:所有都都是对象用援用操纵对象 每种编程语言都有本人操作内存中元素的形式。有时候,程序员必须留神将要解决的数据是什么类型,你是间接操纵元素,还是用某种非凡语法的间接示意(例如C/C++里得指针)来操作对象? 所有这所有在Java里都失去了简化。所有都被视为对象,因而可采纳繁多固定的语法。只管所有都看作对象,但操纵的标识符实际上是对象的一个"援用"(reference)。能够将这情景想像成用遥控器(援用)来操纵电视机(对象)。只有握住这个遥控器,就能放弃与电视机的连贯。当有人想扭转频道或者减小音量时,理论操控的是遥控器(援用),再由遥控器来调控电视机(对象)。如果想在房间里到处走走,同时仍能调控电视机,那么只需携带遥控器(援用)而不是电视机(对象)。
此外,即便没有电视机,遥控器亦可独立存在。也就是说,你领有一个援用,并不一定须要有一个对象与它关联。 存储到什么中央 程序运行时,对象是怎么进行搁置安顿的呢?特地是内存是怎么调配的呢?对这些方面的理解会对你有很大的帮忙。有五个不同的中央能够存储数据∶1)寄存器。这是最快的存储区,因为它位于不同于其余存储区的中央——处理器外部。然而寄存器的数量极其无限,所以寄存器依据需要进行调配。你不能间接管制,也不能在程序中感觉到寄存器存在的任何迹象(另一方面,C和C++容许您向编译器倡议寄存器的调配形式)。2)堆栈。位于通用RAM(随机拜访存储器)中,但通过堆栈指针能够从处理器那里取得间接反对。堆栈指针若向下挪动,则调配新的内存;若向上挪动、则开释那些内存。这是一种疾速无效的调配存储办法,仅次于寄存器。创立程序时,Java零碎必须晓得存储在堆栈内所有项的确切生命周期,以便高低挪动堆栈指针。这一束缚限度了程序的灵活性,所以尽管某些Java 数据存储于堆栈中--特地是对象援用,然而Java对象并不存储于其中。3)堆。一种通用的内存池(也位于RAM区),用于寄存所有的Java对象。堆不同于堆栈的益处是∶编译器不须要晓得存储的数据在堆里存活多长时间。因而,在堆里调配存储有很大的灵活性。当须要一个对象时,只需用new写一行简略的代码,当执行这行代码时、会主动在堆里进行存储调配。当然,为这种灵活性必须要付出相应的代价∶用堆进行存储调配和清理可能比用堆栈进行存储调配须要更多的工夫(如果的确能够在Java中像在C++中一样在栈中创建对象)。4)常量存储。常量值通常间接寄存在程序代码外部,这样做是平安的,因为它们永远不会被扭转。有时,在嵌入式零碎中,常量自身会和其余局部隔离开,所以在这种状况下,能够抉择将其寄存在ROM(只读存储器)中。5)非RAM存储。如果数据齐全存活于程序之外,那么它能够不受程序的任何管制,在程序没有运行时也能够存在。其中两个根本的例子是流对象和长久化对象。在流对象中,对象转化成字节流,通常被发送给另一台机器。在"长久化对象"中,对象被寄存于磁盘上,因而,即便程序终止,它们仍能够放弃本人的状态。这种存储形式的技巧在于∶把对象转化成能够寄存在其它媒介上的事物,在须要时,可复原成惯例的、基于RAM的对象。java提供了对轻量级长久化的反对,而诸如JDBC和Hibernate这样的机制提供了更加简单的对在数据库中存储和读取对象信息的反对。 第三章:操作符本章的内容比拟根底,次要讲了赋值、算数操作符、关系操作符、逻辑操作符、按位操作符、移位操作符、三元操作符等基础知识。本章只是记录下递增和递加的相干常识。 主动递增和递加递增和递加操作符不仅扭转了变量,并且以变量的值作为生成的后果。这两个操作符各有两种应用形式,通常称为前缀式和后缀式,对于前缀递增和前缀递加(假如a是一个int值,如++a或--a),会先执行运算,再生成值,而对于后缀递增和后缀递加(如a++或a--),会学生成值,在执行运算,上面是一个例子: public class AutoInc { public static void main(String[] args) { int i = 1; System.out.println("i: " + i); // 1 System.out.println("++i: " + ++i); // 执行完运算后才失去值,故输入2 System.out.println("i++: " + i++); // 运算执行之前就失去值,故输入2 System.out.println("i: " + i); // 3 System.out.println("--i: " + --i); // 执行完运算后才失去值,故输入2 System.out.println("i--: " + i--); // 运算执行之前就失去值,故输入2 System.out.println("i: " + i); // 1 }}总结:对于前缀模式,咱们在执行完运算后才失去值。但对于后缀模式,则是在运算执行之前就失去值。 ...

March 4, 2024 · 9 min · jiezi

关于java:如何在-Java-中以编程的方式将-CSV-转为-Excel-XLSX-文件

前言 Microsoft Excel的XLSX格局以及基于文本的CSV(逗号分隔值)格局,是数据交换中常见的文件格式。应用程序通过实现对这些格局的读写反对,能够显著晋升性能。在本文中,小编将为大家介绍如何借助葡萄城公司地Java API组件GrapeCity Documents for Excel(以下简称GcExcel)将CSV文件转化为XLSX 文件。 具体操作步骤如下: 创立我的项目(应用intelliJ IDEA创立一个新的Maven我的项目)查问数据(应用AlphaVantage Web服务获取CSV格局的月度BTC-USD数据)加载CSV解决CSV(重新排列、创建表格并创立带有趋势线的图表)返回XLSX1)创立我的项目 (1)应用intelliJ IDEA,创立一个新我的项目。 (2)为我的项目输出项目名称“BTC_Chart_WebService”,并在左侧菜单中选择Maven Archetype后抉择一个我的项目寄存地位,而后点击下一步。 (3)关上pom.xml文件并增加GcExcel依赖项 <dependency> <groupId>com.grapecitysoft.documents</groupId> <artifactId>gcexcel</artifactId> <version>7.0.1</version></dependency> 2)查问数据 创立一个CSV类,用于从AlphaVantage Web服务查问CSV格局的月度BTC-USD数据。 public static String getCsvData() { String csv = null; String apiKey = "YOUR_API_KEY"; String queryUrl = String.format( "https://www.alphavantage.co/query?function=DIGITAL_CURRENCY_MONTHLY&symbol=BTC&market=USD&apikey=%s&datatype=csv", apiKey); HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(queryUrl)) .GET() .build(); try { HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); csv = response.body(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } return csv;}3)加载CSV ...

March 4, 2024 · 2 min · jiezi

关于java:装配行业如何通过MES系统实现生产管理数字化

一、拆卸行业生产现状:拆卸行业作为我国根底制作产业之一,在工厂数字化革新的大潮下,使用数字化伎俩进步企业的生产效率、产品良率,进一步塑造企业的外围竞争力,已成为大势所趋。我国目前的拆卸企业,生产制作信息化水平较低,手工操作记录还是很多工作的惟一办法。下层治理次要是通过工单记录的拆卸过程信息去理解生产情况,对于现场的情况无奈实时把握。一方面,生产打算的任务分配须要车间专职人员进行工作传播,且车间生产治理执行艰难,另一方面装配车间部门间互相独立、数据流通碰壁、信息检索艰难等问题也造成了管理工作无奈达到准确性、完整性和实时性。 MES零碎作为连贯ERP与生产现场的关键所在,能够打消信息流通中的梗塞。通过整合拆卸流程的数据,提供智能剖析和总结报表:买通工厂打算层、执行层之间数据传递,实现工厂外面数据的及时精确流通。 二、万界星空拆卸行业MES零碎利用场景针对拆卸企业的生产个性,设计拆卸行业MES零碎的总体架构,而且对于其外围需要设计绝对应的功能模块,做到生产过程实时可视化,日常动静排程、数据跟踪与追溯要求。根据打算部门下发的生产工单,拆卸MES零碎按照生产线流水生产的组织模式进行治理,采纳产线拉动的形式,以交货期为导向,思考在制品和产能,实现排产。同时,联合交货期的变动,反对打算的滚动编制及对打算长期进行调整。车间线边仓按照生产线物料配送打算将物料运送到指定的上料工位,而后进行物料接管的确认,接管的确认过程要对物料的准确性进行核查,接管的人员扫描产品条码、物料条码后,MES零碎根据扫描的信息,主动与以后的工单打算及产品的工位物料清单数据进行比拟,确认送料的准确性。如果不统一则进行报警,进行物料配错治理。MES零碎针对拆卸企业车间现场作业的解决方案,次要蕴含以下几个方面:打算治理、生产过程治理、物料治理、品质治理、设施治理、异样报警预警治理、过程追溯、报表治理。通过MES零碎的利用,使车间的生产制作过程的实时数据可视化、实时生产排程、实时的生产制作过程跟踪。同时实现零碎的可配置、可集成,以疾速响应车间的变动、进步产品的品质、实现企业生产制作过程和品质过程的透明化管制,实现车间制作执行全过程的跟踪与治理。 如果您的企业也属于流水线拆卸加工的生产模式,同时也打算通过MES零碎来治理整个生产流程,欢送百度万界星空科技官网征询,咱们将安顿业余帮助制订解决方案并发送相干案例材料!

March 4, 2024 · 1 min · jiezi

关于java:春招开始面试也多起来了

最近敌人们反馈,口试和面试都多起来了,下午投的简历,没一会的功夫就收到口试邀请了,比方金山:还塞力斯:其余的还有华为 OD 也开始做口试了,招银网络最近也开始约面试了,所以春招的气氛慢慢来了,还没投递简历的小伙伴能够动起来了。 越早投递越有劣势,面试前期的岗位招聘人数会少很多,因而面试难度就会大很多(狼多肉少)。 1.投递渠道校招和社招简历的投递渠道不太一样。 1.1 校招(或实习)BOSS 直聘公司官网:例如,投递小米,在百度搜寻“小米 校园招聘”点击官网进行投递。牛客网 PS:年前很多实习生辞职回去过年了,所以年后实习十分好找,大家最近抓住机会。1.2 社招BOSS 直聘智联招聘51Job 2.如何打造优质简历?一个优良的简历须要具备以下模块和特质: 3.如何进行“自我介绍”?细节决定成败,面试实质上是“自我采购”的过程。如何在短短的几十分钟内感动面试官,素来都不是一个简略的问题。 所以怎么收场?怎么让面试官对我产生趣味?十分要害。 好的自我介绍,肯定要讲明确以下 4 点: 你是谁?你会啥?你有什么成就?为什么是你? a.你是谁?自我介绍的第一步肯定是自报家门,例如,我是张三,2015 年毕业于西安电子科技大学,毕业之后始终从事 Java 开发的工作,做过 XXX 公司的高级研发工程师,也很快乐加入贵公司的面试。 校招版本:我是李四,24 届学生,目前就读于西安电子科技大学,硕士学历,就读的业余是软件工程(非软件相干业余就不要介绍你的业余了),很荣幸加入贵公司的面试。b.你会啥?技术岗位,最看重的就是你的技术能力,所以这一步肯定要好好筹备,并具体的介绍你会的技能。 要做好这一步,在面试前肯定要查阅应聘公司的岗位要求和应用的技术栈,这样你就能针对性的进行技能介绍了。而当面试官看到一个应聘者的技术栈,和本人公司的技术栈齐全匹配的时候,你的面试成功率就大幅晋升了。 例如,你能够这样介绍。我会的技能是并发编程、MySQL、Redis、Spring、Spring MVC、Spring Boot、Spring Cloud Alibaba Nacos、Sentinel、Seata、Spring Cloud Gateway、Skywalking、RabbitMQ 等技术栈。 c.你有什么成就?学以致用很重要,尤其是校招,你下面说你会,那么怎么证实你真的会你说的哪些技术呢?你应用上述技能取得过什么成就?或做过什么我的项目呢? 如果你加入过 ACM、蓝桥杯等编程竞技大赛,能够在自我介绍的时候具体的说一下,参赛状况和获奖经验。 如果你没有参赛经验和获奖经验,那么你能够介绍你用下面的技能做过什么我的项目? 例如,我应用 Spring Cloud Alibaba 全家桶 + Spring Cloud Gateway + MySQL + Redis + RabbitMQ 总共做过 3 个我的项目,其中有两个我的项目我曾经写在简历上了,等会您有任何对于我的项目或技能点的问题都能够问我。 d.为什么是你?后面三点是陈说,而最初这点就要升华了,这也是你进行“自我吹嘘”最初的机会,也是感动面试官最要害的时刻,“峰终定律”就是讲这个事。 为什么要你?就是你要介绍本人的长处了,例如(但不限)以下这些: 我的技术栈和公司十分匹配:因为我的技术栈和公司的技术栈十分匹配,所以来了之后就能间接干活,大大节俭了新人造就老本。我对公司的业务比拟相熟:我之前从事过,或者具体的理解过公司的相干业务,所以来了之后间接能干活,大大节俭了业务培训老本。我做事比拟专一:例如,去图书馆看书,常常遗记吃中午饭,等到肚子饿的不行了,低头一看表曾经下午 3 点了。我自学能力比拟强:例如,整个微服务,像 Spring Cloud Alibaba 整个技术栈,我只用了 2 周的工夫就全副学会了,并且能用它开发一个 Java 我的项目,期间遇到的所有问题,我都能自行解决。我喜爱编程:例如,您能够看我的 GitHub 我每天都有练习和提交代码。 ...

March 4, 2024 · 1 min · jiezi

关于java:Java-21-终于对这些功能动刀了

起源:https://medium.com/@benweidig 只管 Java 是我应用过的向后兼容水平最高的语言和环境之一,但始终存在性能弃用甚至删除的可能性。Java 21 将弃用两个性能,这就是咱们明天要探讨的内容。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice1、为什么要弃用性能?弃用代码或性能意味着不激励应用它,并且可能在将来的版本中不再存在。为什么不激励它可能有很多起因。 弃用的最常见起因是: 它已被更好的代替计划所取代。存在设计缺点,甚至应用起来可能存在危险。但因为向后兼容性,它不能立刻删除,或者基本不能删除。它被认为是多余的,应该删除以简化零碎及其应用形式。将来的更新将使得反对旧性能/代码变得不可能/不切实际。无论根本原因如何,已弃用的性能依然是零碎的一部分,因而依然可用,最起码到当初。 弃用 Windows 32 位 x86 端口JEP 449旨在弃用 Windows 的 32 位 x86 反对,最终目标是在未来齐全删除它。 这种弃用及其将来删除背地的起因次要是技术性的。 Windows 32 位反对为任何零碎提供软件总是须要决定您理论想要反对哪些平台。针对不再受反对的平台或版本是可能的,但通常意味着减少反对工作、向后移植、自行修复内容等。 以Windows平台为例,最初一个32位版本于2020年公布,官网反对于2025年10月完结。 如果您晓得 64 位 Windows 如何解决 32 位应用程序,您可能想晓得为什么不能通过 Windows集成的 WOW64 模仿层来运行 JVM ?嗯,通常能够以这种形式运行应用程序,但性能会急剧下降。 这就是 OpenJDK 团队决定持续弃用的起因,因为它只影响 Java 的将来版本。旧零碎依然能够应用删除之前的所有 Java 版本。 Java 21 中的一项间接更改会影响 JDK 的构建过程,因为默认状况下禁用配置构建的可能性。尝试运行bash ./configure会呈现谬误: ...checking compilation type... nativeconfigure: error: The Windows 32-bit x86 port is deprecated and may be removed in a future release. \Use --enable-deprecated-ports=yes to suppress this error.configure exiting with result code 1因为该性能只是被弃用,而不是被删除,因而 OpenJDK 团队增加了新的配置选项(如谬误所示),--enable-deprecated-ports=yes以依然容许配置。然而,会收回正告以强调弃用和将来可能的删除。 ...

March 4, 2024 · 2 min · jiezi

关于java:从零开始学Spring-Boot系列集成MySQL

在Spring Boot中集成MySQL是为了让开发者可能轻松地与MySQL数据库进行交互。本篇文章将领导你如何在Spring Boot 3.2.3我的项目中应用Gradle来集成MySQL。在此之前,咱们须要在Ubuntu 22.04上装置MySQL 8作为咱们的数据库服务器。 装置MySQL8本文是在wsl2上的Ubuntu 22.04上装置MySQL8. 步骤1: 更新零碎关上终端,并应用以下命令更新零碎: apt update apt upgrade步骤2: 装置MySQL应用以下命令装置MySQL服务器: apt install mysql-server 步骤3: 启动MySQL服务装置实现后,启动MySQL服务, WSL子系统Ubuntu中不蕴含systemctl命令,应用service命令。 service mysql start 步骤4: 验证MySQL装置通过以下命令验证MySQL是否正在运行: service mysql status 咱们还能够用查看过程 ps -ef | grep mysql如果一切正常,你将看到MySQL服务正在运行的信息。 步骤5: 登录Mysql第一种登录办法root用户没有设置明码,不能从本地登录,能够应用sudo命令进入,此时不须要输出明码回车即可进入。 mysql -u root -p 第二种登录办法MySQL在装置时会创立很多默认用户,其中就蕴含一个 debian-sys-maint,并且创立了该用户的随机明码,存储该用户信息的文件位于 /etc/mysql/debian.cnf文件中。能够利用debian-sys-main用户登录MySQL。 步骤6: 更改root用户明码批改 root 明码 mysql 8.+ 的批改明码形式 alter user 'root'@'localhost' identified with mysql_native_password by '123456';flush privileges; 步骤7: 设置root用户的近程拜访此时root用户的host属性依然是localhost,也就是只能从本地拜访,因而能够将root用户的拜访权限由本地改为本地和内部都能够拜访,将host的值由localhost改为 %。 update user set user.host='%' where user.user='root';flush privileges;WSL中的Ubuntu子系统拜访能够间接应用127.0.0.1或localhost进行拜访。然而在内部一旦换成Ubuntu真正的IP地址拜访就会报错。这时还须要批改MySQL配置文件中的相干配置项 /etc/mysql/mysql.conf.d/mysqld.cnf, 批改 bind-address = 0.0.0.0 。重启MySQL后,再次通过IP地址近程连贯。 ...

March 3, 2024 · 2 min · jiezi

关于java:Java中的图数据库应用Neo4j入门

第1章:引言在数据驱动的时代,咱们解决的不仅仅是数字和文本,还有简单的关系和网络。设想一下社交网络中人与人之间盘根错节的分割,或者是互联网上网页之间的链接关系,传统的表格数据库曾经难以高效地解决这些关系密集型的数据了。这时候,图数据库就退场了,它以图的模式存储数据,节点代表实体,边代表实体之间的关系,非常适合解决简单的网络关系。 那为什么咱们要抉择Neo4j作为图数据库的代表来深刻学习呢?首先,Neo4j是目前最风行的图数据库之一,它提供了十分直观的图形化界面和弱小的查询语言Cypher,让治理和查问图数据变得简略直观。更重要的是,Neo4j具备十分好的性能体现,即使是在解决大规模数据时也能放弃高效的查问速度。对于Java程序员来说,Neo4j提供了良好的Java API反对,让咱们能够轻松地在Java利用中集成和应用Neo4j。 第2章:Neo4j根底要了解Neo4j,咱们得先搞清楚几个外围概念:节点(Node)、关系(Relationship)、属性(Property)和标签(Label)。节点能够了解为图中的一个个实体,比方人、地点或事物。每个节点都能够有多个标签,用于分类或标记。关系则形容了节点之间的分割,每个关系都有方向,指从一个节点指向另一个节点,并且关系自身也能够有属性。属性则是节点或关系的详细信息,比方人的姓名、地点的名称等。 接下来,让咱们用一个简略的例子来看看Neo4j是如何工作的。假如咱们要在Neo4j中建设一个示意敌人关系的小网络。在这个网络中,每个人都是一个节点,人与人之间的敌人关系则是边。 // 连贯到Neo4j数据库Driver driver = GraphDatabase.driver("bolt://localhost:7687", AuthTokens.basic("用户名", "明码"));try (Session session = driver.session()) { // 创立节点 String createNodeQuery = "CREATE (a:Person {name: '小明'}) RETURN a"; session.run(createNodeQuery); // 创立另一个节点,并建设敌人关系 String createAnotherNodeAndRelationQuery = "CREATE (b:Person {name: '小红'})-[:FRIEND]->(a:Person {name: '小明'}) RETURN b"; session.run(createAnotherNodeAndRelationQuery);} 在这个例子中,咱们首先创立了两个标签为Person的节点,别离代表“小明”和“小红”,而后通过:FRIEND关系将它们连接起来。这段代码尽管简略,但曾经涵盖了Neo4j操作的外围:节点的创立、关系的建设以及属性的赋值。 通过这个例子,咱们能够看出,Neo4j使得图数据的示意和查问变得直观而简略。无论是社交网络、举荐零碎还是简单的网络分析,Neo4j都能提供弱小的反对。而且,对于习惯了Java开发的小黑来说,通过Neo4j提供的Java API,将这些性能整合到本人的利用中只是手到擒来的事件。 小黑偷偷通知你一个生财信息差网站: 小黑的生财材料站第3章:装置与配置Neo4j咱们要开始入手实际了,第一步天然是将Neo4j装置到咱们的机器上。不论你是用Windows, Linux还是Mac,Neo4j的装置过程都设计得十分敌对,接下来就一起看看怎么在这些操作系统上搞定它。 在Windows上装置Neo4j对于Windows用户来说,咱们能够间接从Neo4j官网下载Neo4j的Windows版安装包。下载实现后,双击安装文件,跟着装置向导走就行。装置向导会提醒咱们设置数据库的存储门路、HTTP和Bolt端口等,通常状况下,放弃默认设置即可。装置实现后,咱们能够通过Neo4j Desktop利用来治理Neo4j数据库,十分不便。 在Linux上装置Neo4jLinux用户可能更偏向于应用命令行,所以咱们能够通过包管理器来装置Neo4j。以Ubuntu为例,咱们能够先增加Neo4j的仓库,而后应用apt-get命令装置: wget -O - https://debian.neo4j.com/neotechnology.gpg.key | sudo apt-key add -echo 'deb https://debian.neo4j.com stable 4.x' | sudo tee -a /etc/apt/sources.list.d/neo4j.listsudo apt-get updatesudo apt-get install neo4j装置实现后,咱们能够应用sudo service neo4j start命令来启动Neo4j服务。 ...

March 2, 2024 · 2 min · jiezi

关于java:模拟服务器响应的测试框架moco

第1章:引言大家好,我是小黑,在这篇博客中,咱们要聊聊Moco测试框架。这个框架,可不是个别的小伙伴,它在模仿服务器响应这块儿,可是有不少看家本领。 首先,Moco是啥呢?简略说,Moco是一个用来模仿服务器行为的轻量级测试框架,尤其在解决HTTP和RESTful API测试方面表现出色。对于咱们这些程序员来说,测试是个既重要又头疼的活儿,特地是当你须要一个稳固、可控的测试环境时。这时候,Moco就像是一个救星,它能帮你模仿各种服务器响应,让测试变得简略又高效。 那为啥要用Moco而不是别的呢?次要有几个理由:首先,它超级简略易用。你不须要搭建简单的测试环境,几行代码就能搞定。其次,它灵便多变,无论是动态响应还是动静逻辑,Moco都能轻松应答。 第2章:Moco的基本概念接下来,咱们深刻一下,聊聊Moco的基本概念和工作原理。了解了这些,用起Moco来会更得心应手。 Moco的核心理念是“模仿实在”,它通过提供一个虚构的服务器环境,让你能在不依赖实在服务器的状况下进行各种测试。这听起来可能有点形象,咱们用个例子来阐明。 假如你正在开发一个须要调用第三方API的利用。在开发过程中,频繁地向实在的第三方服务器发送申请不仅效率低,而且可能因为网络问题或第三方服务器的不稳定性影响开发进度。这时,Moco就能发挥作用了。你能够用Moco来模仿这个第三方API的响应,这样在开发和测试阶段就不必依赖实在的第三方服务了。 import com.github.dreamhead.moco.HttpServer;import com.github.dreamhead.moco.Runner;import com.github.dreamhead.moco.Moco;public class MocoDemo { public static void main(String[] args) { // 创立一个Moco的HTTP服务器,监听12306端口 HttpServer server = Moco.httpServer(12306); // 当接管到对"/hello"门路的GET申请时,响应"Hello" server.get(Moco.path("/hello")).response("Hello"); // 启动服务器 Runner runner = Runner.runner(server); runner.start(); // 这里能够写测试代码,模仿发送申请到服务器 // ... // 测试完结,进行服务器 runner.stop(); }}// 在这个例子中,咱们创立了一个Moco的HTTP服务器,它监听12306端口。// 当有申请拜访"/hello"这个门路时,服务器就会回应一句“Hello”。// 这样,咱们就能够在本地测试这个响应,而不必依赖实在的服务器环境。 通过这个简略的例子,咱们能够看到Moco的根本应用办法。但这只是冰山一角,Moco还有很多高级性能等着咱们去开掘。比如说,动静响应、条件响应、甚至模仿简单的业务逻辑,Moco都能轻松搞定。 小黑偷偷通知你一个生财信息差网站: 小黑的生财材料站第3章:环境搭建与配置Moco环境搭建要应用Moco,你得有Java环境。因为Moco是用Java写的,所以必须装置Java Development Kit (JDK)。一般来说,装置最新的版本是最好的抉择,这样能确保兼容性和安全性。 接着,咱们须要一个构建工具。Moco反对多种构建工具,比方Maven或Gradle。这里以Maven为例,展现怎么配置。 在你的我的项目的pom.xml文件中,退出Moco的依赖。这样,Maven就会在构建时主动下载和治理Moco库。上面是Moco依赖的例子: <dependencies> <dependency> <groupId>com.github.dreamhead</groupId> <artifactId>moco-core</artifactId> <version>最新版本号</version> </dependency> <!-- 依据须要,可能还要退出其余依赖 --></dependencies>根本配置好了,环境搭建好了,咱们来看看怎么配置一个根本的Moco服务器。这里小黑用一个简略的例子,展现怎么启动一个HTTP服务器,并对一个申请做出响应。 import com.github.dreamhead.moco.HttpServer;import com.github.dreamhead.moco.Runner;import com.github.dreamhead.moco.Moco;public class SimpleMocoServer { public static void main(String[] args) { // 创立一个Moco的HTTP服务器,监听8080端口 HttpServer server = Moco.httpServer(8080); // 当接管到对"/test"门路的GET申请时,响应"测试胜利" server.get(Moco.path("/test")).response("测试胜利"); // 启动服务器 Runner runner = Runner.runner(server); runner.start(); // 这里能够退出你的测试代码 // ... // 记得测试实现后,要进行服务器 runner.stop(); }} ...

March 2, 2024 · 3 min · jiezi

关于java:Java中的动态代理与Spring-AOP编程

第一章:引言大家好,我是小黑,在Java里,动静代理和Spring AOP(面向切面编程)是两个能让代码更加灵便、更加洁净的弱小工具。作为一名Java程序员,小黑感觉把握它们对于写出高质量的代码来说十分重要。动静代理让咱们能在运行时创立一个实现了一组给定接口的新类,这个过程齐全由Java的反射机制管制。而Spring AOP则让咱们能在不批改源代码的状况下,加强办法的性能,比方日志记录、性能统计、安全控制等等。 咱们常常据说,要想做好一件事,最重要的是用对办法。在编程世界里,这句话同样实用。通过动静代理和Spring AOP,咱们能够更加聚焦于业务逻辑的实现,而将那些反复的代码逻辑,比方日志记录、权限查看这些,通过AOP的形式对立解决,大大提高了代码的复用性和可维护性。 第二章:动静代理根底动静代理,这个听起来有点浅近的概念,实际上和咱们日常生活中的代理没什么两样。就像咱们有时候会委托旅行社帮咱们订机票、订酒店一样,程序中的动静代理也是帮咱们实现一些工作,然而更智能一些,因为它是在程序运行时动态创建的,齐全由Java的反射机制管制。 Java中实现动静代理的形式次要有两种:一种是基于接口的JDK动静代理,另一种是CGLIB动静代理。JDK动静代理是通过实现被代理类的接口,而后在调用理论办法前后退出本人的逻辑来实现的。而CGLIB动静代理,则是通过继承被代理类,笼罩其办法来实现加强性能。 让咱们通过一个简略的例子来看看JDK动静代理是怎么回事。假如有一个接口和一个实现类,接口定义了一个办法,实现类实现了这个办法。小黑当初用动静代理在这个办法调用前后打印一些信息: interface Greeting { void sayHello(String name);}class GreetingImpl implements Greeting { public void sayHello(String name) { System.out.println("你好, " + name); }}class DynamicProxyHandler implements InvocationHandler { private Object target; public DynamicProxyHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("办法调用前"); Object result = method.invoke(target, args); System.out.println("办法调用后"); return result; } public static void main(String[] args) { Greeting greeting = (Greeting) Proxy.newProxyInstance( Greeting.class.getClassLoader(), new Class[]{Greeting.class}, new DynamicProxyHandler(new GreetingImpl())); greeting.sayHello("世界"); }}小黑偷偷通知你一个买会员便宜的网站: 小黑整的视頻会园优惠站第三章:深刻Spring AOP咱们谈过动静代理后,接下来进入Spring AOP的世界。AOP(面向切面编程)是一种编程范式,它容许咱们将横切关注点(比方日志、事务管理等)与业务逻辑拆散,从而使得业务逻辑更加洁净、模块化。Spring AOP就是Spring框架提供的一套AOP实现,它利用了动静代理来实现。 ...

March 1, 2024 · 2 min · jiezi

关于java:Java3集合框架

一、思维导图Java汇合框架.xmind 二、知识点及实际2.1、CollectionList列表(元素有序并且能够反复的汇合,被称为序列) 1. ArrayList排列有序,可反复底层应用数组查问快,增删慢线程不平安当容量不够时,ArrayList是以后容量*1.5+1 2. LinkedList排列有序,可反复底层应用双向循环链接数据结构查问慢,增删快线程不平安 3. Vector排列有序,可反复底层应用数组查问快,增删慢线程平安,效率低当容量不够时,Vector是以后容量1 Stack栈是Vector的一个子类,它实现了一个规范的后进先出的栈Set汇合(不能退出反复元素,无序) 1. HashSet排列无序,不可反复底层应用Hash表实现存取速度快外部是HashMap public class SetData { public static void main(String[] args) { List<String> list = List.of("a", "b", "c", "a"); Set<String> stringSet = new HashSet<>(); stringSet.addAll(list); // 输入Set汇合 stringSet.forEach(System.out::println); SortedSet<String> strings = new TreeSet<>(Set.of("a", "b", "c", "d", "e", "f")); SortedSet<String> subSet = strings.subSet("aa", "d"); System.out.println("sub set = " + subSet); List<String> strings1 = new ArrayList<>(Arrays.asList("0", "1", "2", "3", "4")); List<String> immutableStrings = Collections.unmodifiableList(strings1); System.out.println(immutableStrings); strings.add("5"); System.out.println(immutableStrings); }} 2. TreeSet排列无序,不可反复底层应用二叉树实现排序存储外部是TreeMap的SortedSet ...

March 1, 2024 · 5 min · jiezi

关于java:Java2基本特性2

一、思维导图Java个性.xmind 二、知识点及实际1、Java根本个性1.1、封装封装是指暗藏对象的属性和细节,但对外提供公共的拜访形式办法 办法重载(办法名称雷同,参数项不雷同,重载只跟参数无关,与返回类型无关)留神: 应用重载办法时,记住这两条重要的规定: 不能仅通过更改一个办法的返回类型来重载该办法。 不能有两个名称和参数列表都雷同的办法构造方法重载this关键字(代表对象,this就是所在函数的所属对象的援用) 当成员变量和局部变量重名,能够用关键字this来辨别this也能够用于在构造函数中调用其它构造函数。(this只能定义在构造函数的第一行,因为初始化动作必须要先执行)封装劣势 良好的封装可能缩小耦合类外部的构造能够自在批改能够对成员变量进行更准确的管制暗藏信息,实现细节代码public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } // 构造函数、getter和setter办法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } // 其余办法,比方一个简略的打招呼办法 public void sayHello() { System.out.println("你好,我是" + name + ",往年" + age + "岁。"); }}1.2、 继承继承能够被定义为一个对象获取另一个对象属性的过程办法(办法覆写)子类的办法的名称、参数签名和返回类型必须与父类的办法的名称、参数签名和返回类型统一子类办法不能放大父类的拜访权限子类办法不能抛出比父类更多的异样办法笼罩只存在于子类和父类(包含间接父类和间接父类)之间父类的静态方法不能被子类笼罩为非静态方法子类能够定义与父类的静态方法同名的静态方法,以便在子类中暗藏父类的静态方法父类的非静态方法不能被子类笼罩为静态方法父类的公有办法不能被子类笼罩父类的形象办法能够被子类通过两种路径笼罩:一是子类实现父类的形象办法;二是子类从新申明父类的形象办法(例如,扩充拜访权限)父类的非形象办法能够被笼罩为形象办法super关键字拜访成员变量:super.成员变量拜访构造方法:super(……)拜访成员办法:super.成员办法() ...

March 1, 2024 · 3 min · jiezi

关于java:利用Quartz实现复杂的任务调度

第一章:引言大家好,我是小黑,任务调度,简而言之,就是依照预约打算主动执行工作的过程。不论是数据库备份、报表生成还是发送定时邮件,它们都须要一个牢靠的任务调度零碎来保障按时实现。 那么,为什么小黑要抉择Quartz这个框架来实现简单的任务调度呢?起因有很多,但最吸引人的莫过于它的灵活性和弱小性能。Quartz不仅反对简略的到简单的cron表达式,还能在运行时动静调整工作打算,这对于须要高度灵活性的我的项目来说是十分重要的。 第二章:Quartz根底Quartz是一个开源的作业调度库,能够集成到简直任何Java利用中。在深刻理解Quartz之前,咱们先来看看它的几个基本概念:作业(Job)、触发器(Trigger)和调度器(Scheduler)。 作业(Job):这是咱们想要调度的工作,就是咱们要执行的具体逻辑。触发器(Trigger):定义了作业执行的工夫规定。在Quartz中,最罕用的触发器是SimpleTrigger和CronTrigger。调度器(Scheduler):调度器就像一个容器,它负责包容作业和触发器,并依照触发器定义的规定执行作业。当初,小黑来展现如何应用Quartz创立一个简略的任务调度。首先,咱们须要增加Quartz的依赖到我的项目中。应用Maven的话,就是在pom.xml文件中退出以下依赖: <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.2</version> <!-- 请依据理论状况抉择适合的版本 --></dependency>小黑偷偷通知你一个买会员便宜的网站: 小黑整的视頻会园优惠站第三章:Hello Quartz在前两章,咱们理解了任务调度的概念以及Quartz的根本形成。当初,小黑将率领咱们通过一个简略的示例,深刻理解如何应用Quartz实现任务调度。这个示例将会是一个经典的“Hello, Quartz!”程序,通过它,咱们能够看到Quartz在实际操作中是如何工作的。 咱们曾经创立了一个HelloJob类,它实现了Job接口,并笼罩了execute办法。这个办法里的逻辑会在工作触发时执行。上面,小黑要展现的是如何创立一个调度器(Scheduler),以及如何定义触发器(Trigger)来按计划执行咱们的HelloJob。 import org.quartz.*;import org.quartz.impl.StdSchedulerFactory;public class HelloQuartz { public static void main(String[] args) { try { // 创立调度器 Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); // 启动调度器 scheduler.start(); // 定义一个作业,并将其与HelloJob类绑定 JobDetail job = JobBuilder.newJob(HelloJob.class) .withIdentity("job1", "group1") .build(); // 创立一个触发器,立刻执行,而后每2秒反复一次 Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(2) .repeatForever()) .build(); // 通知调度器应用触发器来安顿作业 scheduler.scheduleJob(job, trigger); // 让调度器运行一段时间后敞开 Thread.sleep(10000); scheduler.shutdown(); } catch (SchedulerException | InterruptedException se) { se.printStackTrace(); } }}在这段代码中,咱们首先通过StdSchedulerFactory.getDefaultScheduler()获取一个调度器实例,并通过调用start()办法启动它。接着,创立一个JobDetail实例,这里指定了作业的类为HelloJob,并给这个作业以及所属的组调配了一个惟一标识符。紧接着,定义了一个触发器,这个触发器配置了作业的执行打算:从以后时刻开始,每隔2秒执行一次,且有限反复。 ...

March 1, 2024 · 2 min · jiezi

关于java:Spring-Boot-liteflow-规则引擎太香了

作者:豫州牧\链接:https://juejin.cn/post/7296771770098745344 1、前言在日常的开发过程中,常常会遇到一些串行或者并行的业务流程问题,而业务之间不用存在相关性。 在这样的场景下,应用策略和模板模式的联合能够很好的解决这个问题,然而应用编码的形式会使得文件太多,在业务的局部环节能够这样操作,在我的项目角度就无奈一眼洞穿其中的环节和逻辑。在本文中,将引入规定引擎从全局角度来解决这个问题,这就是明天要介绍的配角 liteflow。 2、liteflow 规定引擎liteflow 是一个笨重而且弱小的规定引擎,可能实现开箱即用,能够在短时间内就能够实现简单的规定编排,下图是 liteflow 的整体架构。liteflow 反对较多的规定文件格式,比方 xml/json/yaml, 对于规定文件的存储形式能够有sql/zk/nacos/apollo 等。 liteflow 的应用是从获取上下文开始的,通过数据上下文来解析对应的规定文件,通过 liteflow 执行器来执行对应的链路,每个链路上都有须要执行的业务 node(即节点组件,能够反对多种语言脚本, groovy/js/python/lua等), 各个业务node 之间是独立的。 liteflow 对应的官网网址和依赖如下所示: # liteflow 规定引擎官网网址https://liteflow.yomahub.com# springboot 集成 liteflow<dependency> <groupId>com.yomahub</groupId> <artifactId>liteflow-spring-boot-starter</artifactId> <version>2.10.6</version></dependency>liteflow 能够反对如下所示的简单流程 此外,liteflow 能够反对热部署,能够实时替换或者减少节点,即批改规定文件后能够实时失效。 3、liteflow 的应用办法3.1 组件liteflow 的组件在规定文件中即对应的节点,组件对应的品种有很多,具体的如下所示: 一般组件一般组件须要集成的是 NodeComponent, 能够用在 when 和 then 逻辑中,具体的业务须要在 process 中去执行。同时在 node 节点中,能够笼罩 iaAccess 办法,示意是否进入该节点执行业务逻辑,isContinueOnError 判断在出错的状况下是否继续执行下一个组件,默认为 false。 isEnd 办法示意是否终止流程,默认为true。 抉择组件抉择组件是通过业务逻辑来判断接下来的动作要执行哪一个节点,相似于 Java中的 switch , 在代码中则须要继承 NodeSwitchComponent 实现 processWitch 办法来解决业务。 # flow 规定表达式 抉择组件SWITCH(a).to(b, c);# processWitch 表达式须要返回的是 b 或者 c 字符串来执行相应的业务逻辑# flow 规定表达式 条件组件IF(x, a, b);条件组件条件组件称之为 if 组件,返回的后果是 true 或者 false, 代码须要集成 NodeIfComponent 重写 processIf 办法,返回对应的业务节点,这个和抉择组件相似。 ...

March 1, 2024 · 2 min · jiezi

关于java:Java中的时间APIDateCalendar到Javatime的演变

引言在软件开发中,解决工夫和日期是一项根本且不可或缺的工作。无论是日志记录、用户信息管理还是简单的定时工作,精确地解决工夫都显得至关重要。然而,工夫的解决并不像它看起来那么简略,尤其是当咱们思考到时区、夏令时等因素时。在Java的晚期,咱们次要依赖于java.util.Date和java.util.Calendar类来解决工夫,但这两个API存在着不少问题。 小黑记得在开始学习Java的那会儿,工夫解决这一块总是让人头疼。特地是当咱们试图创立一个简略的日程安排利用时,那些看似不起眼的工夫问题就像暗藏的地雷一样,随时筹备爆炸。因而,了解Java工夫API的演变,不仅能帮忙咱们防止踩坑,还能让咱们更加高效地解决工夫相干的业务逻辑。 晚期的挑战:Date和CalendarDate的局限性java.util.Date最早在Java 1.0中被引入,设计初衷是提供一个简略的形式来示意工夫和日期。应用Date类能够轻松获取到以后工夫: Date now = new Date();System.out.println("以后工夫:" + now.toString());只管Date类在应用上相当直观,但它很快就显示出了局限性。首个问题是Date的可变性——一旦创立了Date对象,就能够通过setTime办法随便扭转它的值,这在多线程环境下是十分危险的。再者,Date类中的年份是从1900开始计数的,月份也是从0开始,这些设计让人感到不直观,容易导致谬误。 Calendar的改良和新问题为了解决Date的这些问题,Java 1.1引入了Calendar类。Calendar提供了更多的性能,比方能够示意多种日历零碎(如公历、农历等),并且提供了丰盛的API来进行日期的计算和转换。应用Calendar获取以后工夫的代码示例如下: Calendar now = Calendar.getInstance();System.out.println("以后工夫:" + now.getTime());Calendar尽管在性能上有所加强,但它的API应用起来相当简单,且效率不高。更重要的是,Calendar同样是可变的,这意味着它在多线程环境下依然不平安。此外,Calendar的设计仍然沿用了一些Date的不直观之处,比方月份的示意仍然是从0开始的。 综上所述,只管Date和Calendar在Java的晚期版本中解决了工夫和日期的根本示意和操作问题,但它们在应用上的不便和设计上的缺点,使得开发者在解决略微简单一点的工夫逻辑时,常常感到力不从心。这就迫切需要一种更加现代化、更加易用且平安的工夫API来满足日益增长的开发需要。而这,正是java.time包诞生的背景。 Joda-Time的启发在Java官网提供更好的工夫日期解决方案之前,社区并没有进行摸索。Joda-Time库的呈现,就像是一股清爽的空气,为Java中的日期和工夫解决带来了前所未有的改良。Joda-Time不仅解决了Date和Calendar的许多问题,还引入了一种更加直观、更加易用的API设计。 Joda-Time的设计理念Joda-Time的设计理念是简略但弱小:提供一个不可变的日期和工夫库,这意味着一旦创立了日期或工夫对象,就无奈批改它们。这种设计显著晋升了在多线程环境下解决日期和工夫的安全性。此外,Joda-Time还提供了丰盛的API,反对各种简单的日期和工夫操作,而且其直观的设计让开发者可能疾速上手。 Joda-Time的根本用法让咱们通过一些代码示例来看看Joda-Time是如何工作的。首先,获取以后日期和工夫: DateTime now = new DateTime();System.out.println("以后工夫:" + now.toString());能够看到,与Date和Calendar相比,Joda-Time的API更为直观。如果咱们想要进行日期的加减操作,也非常简单: DateTime tomorrow = now.plusDays(1);System.out.println("今天的这个时候:" + tomorrow.toString());DateTime lastMonth = now.minusMonths(1);System.out.println("一个月前的明天:" + lastMonth.toString());这些操作的返回后果是一个新的DateTime对象,保障了操作的不可变性。 小黑偷偷通知你一个买会员便宜的网站: 小黑整的视頻会园优惠站Joda-Time对Java工夫API的启发Joda-Time的呈现和遍及,不仅仅是因为它解决了旧API的问题,更重要的是,它对Java工夫API的将来倒退提供了贵重的启发。Joda-Time证实了一个功能强大且易于应用的工夫库不仅是可能的,而且是十分必要的。 Joda-Time的设计理念和API在很大水平上影响了Java 8中java.time包的造成。事实上,java.time的次要贡献者之一就是Joda-Time的作者Stephen Colebourne,这也是为什么咱们会发现java.time中很多设计思维和API与Joda-Time十分类似。 通过Joda-Time,小黑和咱们一起看到了更好的工夫日期解决形式的可能性。它不仅仅是一个库的胜利,更是一种对Java将来倒退方向的预示。随着java.time的引入,Java在日期和工夫解决方面迈入了一个新的时代。 Java.time的诞生通过多年的倒退和期待,Java终于在其8版本中引入了一个全新的日期和工夫API——java.time包。这一变革性的提高,不仅排汇了Joda-Time的设计精髓,还在性能、易用性和准确性方面做了进一步的优化和晋升。java.time包的引入,标记着Java对日期和工夫解决形式的根本性扭转。 设计指标和次要个性java.time包的设计指标是清晰和统一的API,强调不可变性以确保线程平安,提供对时区的全面反对,并且笼罩日期工夫解决的宽泛需要。其中一些外围个性包含: 不可变对象:所有的日期和工夫类都是不可变的,这意味着它们是线程平安的。清晰的API:与Date和Calendar相比,java.time提供了更加直观和易于应用的API。时区反对:全面的时区解决能力,包含对夏令时的智能解决。宽泛的工夫日期操作:提供了丰盛的API来执行各种日期和工夫的计算、解析和格式化操作。java.time的外围类让咱们来看一些java.time中的外围类及其根本用法: LocalDate:示意没有时区的日期(年月日)。LocalDate today = LocalDate.now();System.out.println("明天的日期是:" + today);LocalTime:示意没有时区的工夫(时分秒)。LocalTime now = LocalTime.now();System.out.println("以后的工夫是:" + now);LocalDateTime:联合了日期和工夫,但不蕴含时区信息。LocalDateTime now = LocalDateTime.now();System.out.println("以后的日期和工夫是:" + now);ZonedDateTime:蕴含时区的日期和工夫。ZonedDateTime zonedDateTime = ZonedDateTime.now();System.out.println("以后的日期和工夫(含时区)是:" + zonedDateTime);java.time与Joda-Time的关系java.time包在很多方面都受到了Joda-Time的影响,这不仅体现在API的设计上,更重要的是,它继承了Joda-Time不可变性的核心理念。同时,java.time也在性能和标准化方面做了进一步的晋升。java.time的引入,让Java的日期和工夫解决变得前所未有的弱小和便捷。 ...

February 29, 2024 · 2 min · jiezi

关于java:深入理解Java泛型及其在实际编程中的应用

第1章:泛型的起源与重要性大家好,我是小黑,在Java里,泛型(Generics)是一种不可或缺的个性,它容许咱们在编码时应用类型(Type)作为参数。这听起来可能有点绕,但其实就像是给办法传递参数一样,只不过这次传递的是数据类型而不是数据值。这样一来,咱们就能写出更加通用、更加平安的代码。设想一下,如果有一个容器,这个容器能够装任何类型的数据,不论是整数、字符串还是自定义的对象,这岂不是十分不便?但如果在取出数据的时候,咱们不晓得它是什么类型,那就得转换类型,这时候很容易出错。泛型就是来解决这个问题的。 泛型最早在其余编程语言中呈现,Java直到JDK 5.0版本才引入泛型,这一改良大大加强了Java的表达能力,同时也进步了代码的安全性和可读性。通过泛型,编译器能够在编译期间查看类型,防止了运行时的ClassCastException,这对于晋升大型应用程序的稳定性和健壮性有着显而易见的益处。 简略来说,泛型就像是一种严格的门卫,确保咱们在代码中严格遵守类型平安,不会不小心把猫当成狗来养。这样一来,就能够大大减少运行时呈现问题的可能性,让咱们的程序更加强壮。 第2章:泛型的基本概念泛型的根底概念围绕着类型参数(Type Parameters)和类型变量(Type Variables)。让小黑来举个栗子,假如咱们要写一个能够存储任意类型元素的容器类。在不应用泛型的世界里,可能会用Object类型来实现,但这样做既不平安也不不便。引入泛型后,状况就大不相同了。 public class GenericContainer<T> { private T element; public void setElement(T element) { this.element = element; } public T getElement() { return this.element; }}在这个例子中,T就是一个类型参数,它代表着任何类型。当创立GenericContainer实例的时候,能够指定T的具体类型: GenericContainer<String> stringContainer = new GenericContainer<>();stringContainer.setElement("泛型真好玩");String element = stringContainer.getElement(); // 不须要类型转换这样一来,咱们就能够在编译期间确保类型的安全性,防止了运行时的类型转换谬误。此外,泛型不仅仅能够用在类上,还能够用在接口和办法上。比方,咱们能够有一个泛型接口,示意任何能够比拟本人的类型: public interface Comparable<T> { int compareTo(T o);}或者是一个泛型办法,用来替换数组中两个元素的地位: public class ArrayUtil { public static <T> void swap(T[] array, int i, int j) { T temp = array[i]; array[i] = array[j]; array[j] = temp; }}通过这个swap办法的例子,能够看到泛型办法的弱小之处:它不依赖于类或接口的泛型。这个办法能够用于任何类型的数组,减少了代码的复用性。 ...

February 29, 2024 · 3 min · jiezi

关于java:面试官说说volatile底层实现原理

在 Java 并发编程中,有 3 个最罕用的关键字:synchronized、ReentrantLock 和 volatile。 尽管 volatile 并不像其余两个关键字一样,能保障线程平安,但 volatile 也是并发编程中最常见的关键字之一。例如,单例模式、CopyOnWriteArrayList 和 ConcurrentHashMap 中都离不开 volatile。 那么,问题来了,咱们晓得 synchronized 底层是通过监视器 Monitor 实现的,ReentrantLock 底层是通过 AQS 的 CAS 实现的,那 volatile 的底层是如何实现的? 1.volatile 作用在理解 volatile 的底层实现之前,咱们须要先理解 volatile 的作用,因为 volatile 的底层实现和它的作用非亲非故。 volatile 作用有两个:保障内存可见性和有序性(禁止指令重排序)。 1.1 内存可见性说到内存可见性问题就不得不提 Java 内存模型,Java 内存模型(Java Memory Model)简称为 JMM,次要是用来屏蔽不同硬件和操作系统的内存拜访差别的,因为在不同的硬件和不同的操作系统下,内存的拜访是有肯定的差别得,这种差别会导致雷同的代码在不同的硬件和不同的操作系统下有着不一样的行为,而 Java 内存模型就是解决这个差别,对立雷同代码在不同硬件和不同操作系统下的差别的。 Java 内存模型规定:所有的变量(实例变量和动态变量)都必须存储在主内存中,每个线程也会有本人的工作内存,线程的工作内存保留了该线程用到的变量和主内存的正本拷贝,线程对变量的操作都在工作内存中进行。线程不能间接读写主内存中的变量,如下图所示:然而,Java 内存模型会带来一个新的问题,那就是内存可见性问题,也就是当某个线程批改了主内存中共享变量的值之后,其余线程不能感知到此值被批改了,它会始终应用本人工作内存中的“旧值”,这样程序的执行后果就不合乎咱们的预期了,这就是内存可见性问题,咱们用以下代码来演示一下这个问题: private static boolean flag = false;public static void main(String[] args) { Thread t1 = new Thread(new Runnable() { @Override public void run() { while (!flag) { } System.out.println("终止执行"); } }); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("设置 flag=true"); flag = true; } }); t2.start();}以上代码咱们预期的后果是,在线程 1 执行了 1s 之后,线程 2 将 flag 变量批改为 true,之后线程 1 终止执行,然而,因为线程 1 感知不到 flag 变量产生了批改,也就是内存可见性问题,所以会导致线程 1 会永远的执行上来,最终咱们看到的后果是这样的:如何解决以上问题呢?只须要给变量 flag 加上 volatile 润饰即可,具体的实现代码如下: ...

February 29, 2024 · 3 min · jiezi

关于java:开年就该拼性价比迅易一站式人才服务助您巧妙节流

人勤春早争朝夕,策马扬鞭开新局。企业之间的竞争日趋激烈,市场投入和经营老本也在逐年攀升。新的一年,招聘人才仍旧企业组织的头等大事,然而,企业组织招聘总会呈现各种各样的情况: 场景1:人力资源工作上破费太长时间 场景2:外部人力资源人员不足,无奈很好地均衡招聘工作和员工管理工作 场景3:不足雇佣新员工或领取外部人力资源员工福利的资金 如何能力无效升高企业人力资源老本,晋升资源利用效率?人力外包,便是企业降本增效的理智抉择之一。 着眼于泛滥企业的数字化需要,迅易科技趁势而为,依靠于在数字化技术服务畛域丰盛的我的项目教训和团队劣势,将技术人才资源进行整合,开始摸索人力外包业务,以更加精准、高效的运作形式服务于宽广企业客户,激发组织和更多行业的可能性,提供全方位、多层次、高端化、灵便的一站式人才服务。 咱们的服务内容1、全方位、多层次人才供应:实现疾速、批量招聘,依据业务变动提供组合用工计划 2、轻松解决人员治理:实现根底人事、员工关系,薪酬福利等的一体化治理 3、保障用工危险管控:基于业务人效提供绩效解决方案,保障全流程用工危险防备 4、提供标准化职能培训:领有体系化招聘和培训流程,保障人员与岗位技能深度匹配 5、企业个性化人才服务:定制专属人力资源解决方案,HR一对一全流程提供服务 总而言之,迅易科技一站式人才服务堪称“遥遥领先”,不仅有业余的服务,性价比还相当高。比方: 咱们的服务劣势1.残缺的服务体系:从JD解读、简历推送、面试安顿、候选人背调、入职安顿等环节,全套24小时为您提供“收费”服务; 2.成熟的服务响应模式:具备及时、精准的需要响应速度和剖析反馈能力,实现客户需要和解决方案无缝对接; 3.雄厚的人才储备:Java、前端、测试、运维、BI开发、UI设计等热门岗位优秀人才,弱小的IT人才储备资源库及高效的资源调度体系,可能满足企业实时需要; 4.灵便的用工计划:提供短期或长期用工反对,疾速到岗,灵便的人力外包服务模式,高度业余的IT人才和服务能力; 5.迅易科技实力保障:领有雄厚的企业实力和泛滥国内外技术资质认证,包含CMMI3级、DCMM3级、ISO9001、ISO20000等。 咱们的业务劣势迅易科技的服务底座稳了,业务能力更不能马虎。除了领有更多人才资源和服务劣势之外,咱们在业务方面的劣势也同样下足了苦功。 1、多年我的项目实践经验 深扎大数据行业近二十年,胜利服务于300余家大中小型外企、国企等,施行1000+我的项目,领有综合实力弱小的专家资源池和技术服务团队。在诸多单干案例中,不仅将客户提出的泛滥需要胜利施行落地,积攒了丰盛的实战经验,还曾为碧桂园物业、树根互联等国内多家大型企业团体等提供一站式人才服务。 2、全场景的解决方案设计 笼罩企业AI智能利用翻新、BI商业智能翻新、Cloud智能云服务、Data智能数据服务四大核心技术服务能力,助力客户疾速实现业务指标,更好的服务社会发明价值。 实际场“能打”,人才场“给力”,这就是迅易科技一站式人才服务。 如果您想要理解更多我的项目案例,欢送返回迅易科技官网;如果您想要征询更多一站式人才服务,欢送分割咱们的资深HRBP专家 Jenny 迅易科技资深HRBP专家 电话:18102716278 邮箱:Jenny.cao@xunyisoft.com

February 29, 2024 · 1 min · jiezi

关于java:社招丨华为

投递通道:https://jinshuju.net/f/o38ijj前端、后端、测试岗位此岗位长期有效 地点西安,深圳,北京,上海,南京,武汉 薪资20-55w 要求统招本科毕业(学校优良年限可放宽), 计算机相关业余 福利双休、六险一金全额缴纳、合同四年起签、加班费、大厂食堂、收费班车,加班有价值50元夜宵赠送 劣势有国内最全面的B2C IT零碎开发平台,笼罩了面向B2C行业的绝大部分IT零碎,蕴含了渠道、营销、批发、服务、供应链、财经、研发IPD、数字化经营等各类业务,视线广阔。可能参加零碎级设计工具开发以及计算设计实现等工作,对集体技术晋升很大,同时重视造就人选的复合型能力。

February 29, 2024 · 1 min · jiezi

关于java:从零开始学Spring-Boot系列返回json数据

欢送来到从零开始学Spring Boot的旅程!在Spring Boot中,返回JSON数据是很常见的需要,特地是当咱们构建RESTful API时。咱们对上一篇的Hello World进行简略的批改。 增加依赖首先,确保你的build.gradle文件中曾经蕴含了Spring Web的依赖,因为返回JSON数据通常与Web申请和响应无关。Spring Boot的starter-web曾经蕴含了所有必要的依赖,所以如果你应用Spring Initializr创立的我的项目,这一步应该曾经实现了。创立数据模型接下来,咱们须要一个数据模型来示意咱们要返回的JSON数据。先创立一个model的package来寄存java类,创立一个User的Java类来示意这个模型。 package cn.daimajiangxin.springboot.learning.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.extern.slf4j.Slf4j; @Data @Slf4j @AllArgsConstructor public class User { private String name; private int age; }创立控制器创立一个控制器来解决HTTP申请并返回JSON数据。应用@RestController和@RequestMapping注解来标记这个类,这样Spring Boot就会主动将返回的对象转换为JSON格局。@RequestMapping注解对申请解决类中的申请解决办法进行标注,@GetMapping注解用于解决HTTP GET申请,并将申请映射到具体的解决办法中。 package cn.daimajiangxin.springboot.learning.controller;import cn.daimajiangxin.springboot.learning.model.User;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/user")public class UserController { @GetMapping("/getUser") public User getUser() { // 创立一个User对象 User user = new User("Alice", 30); return user; // Spring Boot会主动将User对象转换为JSON格局 }}运行应用程序启动你的Spring Boot应用程序。如果一切顺利,当你拜访http://localhost:8080/user/getUser时,你应该能看到如下的JSON响应:自定义JSON输入有时,你可能须要自定义JSON的输入格局或者蕴含额定的信息。你能够应用@JsonInclude、@JsonProperty等注解来管制Jackson库(Spring Boot默认的JSON解决库)的序列化行为。例如,你能够应用@JsonInclude(JsonInclude.Include.NON_NULL)来防止输入null值,或者应用@JsonProperty来重命名JSON字段。 import com.fasterxml.jackson.annotation.JsonInclude;import com.fasterxml.jackson.annotation.JsonProperty;import lombok.AllArgsConstructor;import lombok.Data;import lombok.extern.slf4j.Slf4j;@Data@Slf4j@AllArgsConstructor@JsonInclude(JsonInclude.Include.NON_NULL)public class User { @JsonProperty("username") private String name; private int age;}这样,返回的JSON数据就会将name字段重命名为username,并且不会蕴含null值。 ...

February 29, 2024 · 1 min · jiezi

关于java:Java中的单元测试JUnit5实践指南

第1章:引言大家好,我是小黑,在Java里,单元测试不仅仅是查看代码是否失常运行的形式,它更是保障软件品质、促成设计优化的重要工具。JUnit,作为Java最风行的测试框架之一,曾经随同着有数Java开发者走过了好几个版本的迭代。到了JUnit5,这个框架不仅仅是做了简略的降级,而是带来了一系列革命性的扭转,让单元测试变得更加灵便、更容易应用。 对于小黑来说,JUnit5的到来意味着更多的可能性。不仅因为它的新个性让测试更加弱小,更因为它让测试过程变得更加舒心。设想一下,一个反对Lambda表达式的测试框架,加上更灵便的测试实例治理和动静测试能力,这不仅仅是技术上的提高,更是对测试哲学的一种进化。 小黑记得在应用JUnit4的时候,经常会因为一些框架的限度而不得不采取一些不那么优雅的形式来组织测试代码。然而JUnit5的设计理念,让这所有都变得不同了。它不仅让测试更加的灵便和弱小,还更加重视于开发者的应用体验。 第2章:JUnit5概览谈到JUnit5,小黑感觉有必要先给咱们搞清楚JUnit5相比于旧版本到底带来了哪些扭转。JUnit5能够说是由三大次要局部组成的:Jupiter、Vintage和Platform。 Jupiter 提供了JUnit5的新的测试引擎,用于编写测试和扩大。比方,咱们当初能够欢快地应用Lambda表达式来写测试了。Vintage 确保了对旧版本JUnit测试的兼容性。也就是说,即便咱们的我的项目中还有JUnit4的测试代码,也齐全没有问题。Platform 是在底层反对不同测试框架的一种机制。这意味着咱们能够在同一个我的项目中同时应用JUnit4和JUnit5进行测试。集成JUnit5到咱们的我的项目中也相当简略。如果咱们是用Maven,只须要在pom.xml中增加对应的依赖: <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.7.0</version> <scope>test</scope></dependency><dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.7.0</version> <scope>test</scope></dependency>或者如果咱们是用Gradle的话,能够在build.gradle文件中退出: testImplementation('org.junit.jupiter:junit-jupiter-api:5.7.0')testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.7.0')有了这些配置,就能够开始享受JUnit5带来的测试之旅了。在理论编写测试代码时,咱们会发现JUnit5让测试不仅仅是一种责任,更是一种乐趣。通过更简洁的API、更灵便的测试写法,甚至能够说JUnit5从新定义了Java的单元测试。 第3章:根本测试用例编写小黑首先想和咱们分享的是如何编写一个根本的测试用例。在JUnit5中,编写测试用例变得异样简略,但同时也更加弱小和灵便。咱们来看一个简略的例子,假如小黑当初有一个十分根底的计算器类,提供了加法和减法的性能。 首先,咱们定义一个Calculator类: public class Calculator { public int add(int a, int b) { return a + b; } public int subtract(int a, int b) { return a - b; }}接下来,咱们用JUnit5来编写测试这个类的代码。在JUnit5中,咱们用@Test注解来标记一个测试方法。而且,JUnit5对测试方法的命名没有特地的限度,咱们能够用更加描述性的名称来进步测试代码的可读性。 import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.assertEquals;class CalculatorTests { @Test void 加法后果应该正确() { Calculator calculator = new Calculator(); assertEquals(2, calculator.add(1, 1), "1 加 1 应该等于 2"); } @Test void 减法后果应该正确() { Calculator calculator = new Calculator(); assertEquals(0, calculator.subtract(1, 1), "1 减 1 应该等于 0"); }}在下面的代码中,咱们应用assertEquals办法来验证计算结果是否合乎预期。这是JUnit提供的断言办法之一,用于比拟预期值和理论值。如果两者不相等,测试将会失败。此外,咱们还能够看到,测试方法的命名采纳了中文,这齐全没有问题,JUnit5反对这样做,这样能够让测试代码更加直观易懂。 ...

February 28, 2024 · 2 min · jiezi

关于java:简单看下最近的Spring-SecruritySpring漏洞CVE202422234CVE202422243

最近的这两个cve我看国内很多情报将其评为高危,所以想着去看看原理,看完发现都比较简单,利用要求的场景也绝对无限(特地是第一个),所以就轻易看下就行了 Spring Security 用户认证绕过(CVE-2024-22234)先看下官网的布告(https://spring.io/security/cve-2024-22234) In Spring Security, versions 6.1.x prior to 6.1.7 and versions 6.2.x prior to 6.2.2, an application is vulnerable to broken access control when it directly uses the AuthenticationTrustResolver.isFullyAuthenticated(Authentication) method. Specifically, an application is vulnerable if: The application uses AuthenticationTrustResolver.isFullyAuthenticated(Authentication) directly and a null authentication parameter is passed to it resulting in an erroneous true return value.An application is not vulnerable if any of the following is true: ...

February 28, 2024 · 2 min · jiezi

关于java:深入理解Spring-Security

第1章:Spring Security简介大家好,我是小黑,在谈到网站平安的时候,Spring Security是个避不开的话题。它就像是个守门员,决定谁能进入咱们的网站,又能在网站的哪些角落里走动。简略来说,Spring Security负责两大块:认证(Authentication)和受权(Authorization)。认证是确认咱们的身份,受权则是决定咱们能做什么、不能做什么。 设想一下,小黑正在尝试进入一个只有VIP成员能力拜访的网站区域。Spring Security首先会查看小黑是不是网站的注册用户,这就是认证。一旦确认小黑的确是谁他说的那个人,接下来就要看看小黑有没有VIP的权限,这就是受权的过程了。 这套机制听起来是不是很像生存中的例子?比方,咱们进入一家公司,须要先通过门卫的身份验证,而后能力依据本人的身份证进入相应的办公区域。Spring Security就是在软件里,为应用程序提供这样一道爱护屏障。 Spring Security的弱小之处还在于它的灵活性和扩展性。不论是对于简略的集体博客,还是简单的企业零碎,它都能提供强有力的平安保障。而且,Spring Security反对多种认证形式,比方表单登录、LDAP、OAuth2等,简直能够满足所有的平安需要。 第2章:认证与受权根底谈到Spring Security,咱们不能不提它的两大外围:认证和受权。这两者听起来很简略,但要做好,细节是要害。 认证,就是确认请求者的身份。在Spring Security中,这个过程通常是通过AuthenticationManager来实现的。它会应用一系列的AuthenticationProvider,每个Provider都尝试认证用户提交的信息。如果认证胜利,用户的详情就会被保留在SecurityContextHolder中,不便后续操作应用。 import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;import org.springframework.security.core.Authentication;import org.springframework.security.core.context.SecurityContextHolder;// 创立一个用户的认证令牌Authentication request = new UsernamePasswordAuthenticationToken("小黑的用户名", "小黑的明码");// 通过AuthenticationManager验证用户的认证信息Authentication result = authenticationManager.authenticate(request);// 认证胜利后,将用户信息保留到SecurityContextHolderSecurityContextHolder.getContext().setAuthentication(result);受权,则是决定认证通过的用户能做什么。在Spring Security中,这通常是通过定义一系列的权限规定来实现的。比方,咱们能够定义某个API接口只容许领有ADMIN角色的用户拜访。 import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") // 只有ADMIN角色的用户能力拜访/admin/**门路 .anyRequest().authenticated(); // 其余所有申请都须要认证 }}通过这两段代码,咱们能够看到Spring Security在认证和受权上的根本应用。但真正的魅力在于它的灵活性和扩展性,无论是简略的身份验证,还是简单的权限管制,Spring Security都能轻松应答。 第3章:配置Spring Security配置Spring Security可能听起来有点儿头疼,但别放心,小黑来带咱们一步步搞定它。要让Spring Security为咱们的利用站岗放哨,首先得让它晓得咱们的规定。这就像是通知守门员,哪些人能够进来,哪些人须要验证,哪些区域是禁止进入的。 引入Spring Security在开始配置之前,确保咱们的我的项目中曾经退出了Spring Security的依赖。如果是用Spring Boot,那几乎不能更简略,只须要在pom.xml文件中退出上面这段: ...

February 28, 2024 · 3 min · jiezi

关于java:面试官Redis如何保证高可用

Redis 高可用(High Availability,HA)是指 Redis 通过一系列技术手段确保在面临故障的状况下也能继续提供服务的能力。 Redis 作为一个内存数据库,其数据通常存储在内存中,一旦产生故障,可能导致数据失落或服务中断,所以,为了保障 Redis 的高可用,它次要采纳了以下两种伎俩: 长久化:长久化机制可能在肯定水平上保障即便在服务器意外进行后,数据还能被复原。多机部署:将本来为单机的 Redis 服务,变为多个 Redis 节点,主节点用来解决数据的写操作,而后再把最新的数据同步给从节点,这样即便其中有一个节点宕机了,那么其余节点仍然保留了最新的数据,从而防止了 Redis 的单机故障。但长久化和多机部署又有很多种实现形式,接下来一起来看。 1.长久化长久化是指将数据从内存中存储到长久化存储介质中(如硬盘)的过程,以便在程序重启或者零碎解体等状况下,可能从长久化存储介质中复原数据。Redis 4.0 之后反对以下 3 种长久化计划: RDB(Redis DataBase)长久化:快照形式长久化,将某一个时刻的内存数据,以二进制的形式写入磁盘;AOF(Append Only File)长久化:文件追加长久化,记录所有非查问操作命令,并以文本的模式追加到文件中;混合长久化:RDB + AOF 混合形式的长久化,Redis 4.0 之后新增的形式,混合长久化是联合了 RDB 和 AOF 的长处,在写入的时候,先把以后的数据以 RDB 的模式写入文件的结尾,再将后续的操作命令以 AOF 的格局存入文件,这样既能保障 Redis 重启时的速度,又能减低数据失落的危险。 1.1 RDB 长久化RDB(Redis Database)是将某一个时刻的内存快照(Snapshot),以二进制的形式写入磁盘的长久化机制。RDB 长久化机制有以下优缺点:长处: 速度快:绝对于 AOF 长久化形式,RDB 长久化速度更快,因为它只须要在指定的工夫距离内将数据从内存中写入到磁盘上。空间占用小:RDB 长久化会将数据保留在一个压缩的二进制文件中,因而绝对于 AOF 长久化形式,它占用的磁盘空间更小。复原速度快:因为 RDB 文件是一个残缺的数据库快照,所以在 Redis 重启后,能够十分疾速地将数据恢复到内存中。可靠性高:RDB 长久化形式能够保证数据的可靠性,因为数据会在指定工夫距离内主动写入磁盘,即便 Redis 过程解体或者服务器断电,也能够通过加载最近的一次快照文件复原数据。毛病: 数据可能会失落:RDB 长久化形式只能保证数据在指定工夫距离内写入磁盘,因而如果 Redis 过程解体或者服务器断电,从最初一次快照保留到解体的工夫点之间的数据可能会失落。实时性差:因为 RDB 长久化是定期执行的,因而从最初一次快照保留到以后工夫点之间的数据可能会失落。如果须要更高的实时性,能够应用 AOF 长久化形式。所以,RDB 长久化形式适宜用于对数据可靠性要求较高,但对实时性要求不高的场景,如 Redis 中的备份和数据恢复等。 1.2 AOF 长久化AOF(Append Only File)它是将 Redis 每个非查问操作命令都追加记录到文件(appendonly.aof)中的长久化机制。AOF 长久化机制有以下优缺点:长处: ...

February 28, 2024 · 1 min · jiezi

关于java:亿级电商流量高并发下Redis与MySQL的数据一致性如何保证

前言:只有应用到缓存,无论是本地缓存还是应用Redis做缓存,那么就会存在数据同步不统一的问题。 先读取缓存,缓存数据有,则立刻返回后果如果缓存中没有数据,则从数据库中读取数据把读取到的数据同步到缓存中,提供下次读申请返回数据这样的作法是大多数人应用缓存的形式,这样能无效加重数据库压力,然而如果批改删除数据,因为缓存无奈感知到数据在数据库中的批改。 这样就会造成数据库中的数据与缓存中数据不统一。 那么该如何解决呢? 有上面4种解决方案: 先更新缓存,再更新数据库先更新数据库,再更新缓存先删除缓存,后更新数据库先更新数据库,后删除缓存上面咱们一一来看下每个计划的可行性: 最近无意间取得一份阿里大佬写的刷题笔记,一下子买通了我的任督二脉,进大厂原来没那么难。 这是大佬写的, 7701页的BAT大佬写的刷题笔记,让我offer拿到手软本文,已收录于,我的技术网站 aijiangsir.com,有大厂残缺面经,工作技术,架构师成长之路,等教训分享 注释一、先更新缓存,再更新数据库这个计划咱们个别不思考。起因是更新缓存胜利,然而更新数据库出现异常了。 会导致缓存数据与数据库数据齐全不统一,而且很难觉察,因为缓存中的数据始终都存在。 二、先更新DB,再更新缓存这个计划咱们个别也是不思考,起因跟计划1一样,数据库更新胜利了,缓存更新失败,同样会呈现数据不统一问题,且不容易被发现,因为缓存中始终存在数据。 三、先删除缓存,后更新DB这个计划再并发场景下也会出问题,具体呈现的起因如下: 两个并发申请:申请A(更新操作)和申请B(读取操作) 申请A会先删除Redis中的数据,而后去更新数据库此时申请B看到Redis中的数据是空的,回去数据库中查问该值,补充到Redis缓存中此时申请A并没有更新胜利,或者是事务还未提交(MySQL的事务隔离级别,会导致未提交的事务数据不会被另一个线程看到),申请B去数据库查问失去旧值. 这时候就会产生数据库和Redis数据不统一的问题。 因而个别也不倡议这种形式 尽管不倡议,然而如果你是采纳了这种形式,该如何解决数据不统一的问题呢? 其实最简略的方法就是延时双删的策略: 先淘汰缓存再写数据库休眠1s,再次淘汰缓存这样做,能够将1s内所造成的缓存脏数据,再次删除。 然而,然而,这个1s怎么确定的,具体该休眠多久呢? 自行评估本人的我的项目的读数据业务逻辑的耗时(这个咱们能够利用SkyWalking等监控工具评估耗时)评估写数据的休眠工夫(在读数据业务耗时的根底上,加几百ms即可)这样做的目标,就是确保读申请完结,写申请能够删除读申请造成的缓存脏数据。 延时双删就能彻底解决不统一吗?如果面试官这样问你,你千万不能答复是的。 第一,咱们评估的延时工夫(读申请耗时+几百毫秒),并不能齐全代表理论运行过程中的耗时,运行过程如果因为零碎压力过大,咱们评估的耗时就是不精确,依然会导致数据不统一的呈现 第二,延时双删尽管在保障事务提交完当前再进行删除缓存,然而如果你应用的是MySQL的读写拆散的机构,主从同步之间其实也会有时间差。 此时该如何解决呢? 解决办法有两个: 还是应用延时双删策略,只是睡眠工夫改为在主从同步的延时工夫根底上,加几百毫秒(读接口耗时+主从延迟时间+几百毫秒)对Redis进行填充数据查问(更新缓存时查询数据库),强制走主库查问,那么咱们延时双删就没必要减少主从延时工夫了(减少个主从延时工夫也会减少更大的不确定性,因为主从延时工夫也是不稳固的)如果面试官持续深刻的问你,采纳这种同步延时双删的淘汰策略,接口的吞吐量升高怎么办?(数据变更时,更新接口都要多休眠一个延时工夫) 既然同步会升高吞吐量,那就同步改异步(性能优化的罕用伎俩)。 将第二次删除的操作,异步起一个线程,异步删除,这样写的申请就不必沉睡一段时间后能力返回了。 总的来说,先删除缓存,再更新数据库的形式,还是瑕疵较多,产生数据一致性的问题和性能问题的概率更大。比方: 先删除缓存可能导致读申请因缓存缺失而大量拜访数据库(尤其是高并发场景的电商,可能一瞬间就把数据库打挂了)读申请接口的耗时和写缓存的工夫,估算不够精确,会导致提早双删中的sleep工夫不好设置上面咱们来看最初一种解决方案,这个解决形式是4个计划中产生数据不一致性的概率最低的。 四、先更新DB,后删除缓存 读的时候,先读缓存,缓存没有的话,就读数据库,而后取出数据后放入缓 存,同时返回响应。更新的时候,先更新数据库,而后再删除缓存。 这种计划下就不存在数据不一致性的问题了么? 其实是仍然存在的,尤其是在大型互联网电商,高并发零碎中,并发问题导致的数据一致性的数据量十分大。 假如两个申请,申请A和申请B,申请A做查问操作(读申请),申请B做更新操作(写申请) 当高并发场景下,会有如下情景呈现: 缓存刚好生效申请A查询数据库,失去一个旧值申请B将新值写入数据库申请B删除缓存申请A将查到的旧值写入缓存 高并发场景下,的确有可能会产生上述的状况,产生脏数据。 然而,产生这种的概率又有多少呢? 产生上述情况的一个先天性条件,就是步骤(3)的写数据库操作比步骤(2)的读数据库操作耗时更短,才有可能使得步骤(4)先于步骤(5)。可是,大家想想,数据库的读操作的速度远快于写操作的(不然做读写拆散干嘛,做读写拆散的意义就是因为读操作比拟快,耗资源少)。 因而步骤(3)耗时比步骤(2) 更短,这一情景很难呈现。 然而,如果面试官问你:如果我的业务属性要求肯定要解决怎么办?那么如何解决上述并发问题? 首先,给缓存设置过期工夫是一种无效的计划。 如果你的业务数据对实时性要求不是很高,能够承受数据的短时间数据不统一的场景,咱们此种计划就能够解决了(比方商品详情中的形容、属性等)其次,仍能够采纳异步延时删除的策略。 参考计划3中的异步延时删除策略计划,删除的计划其实还有问题,这个咱们放在前面说个别采纳这些伎俩简直就曾经把Redis缓存和数据库数据不统一的概率降到了极低。 如果非要强一致性,极低的数据不统一的概率都不能承受,那么该如何解决呢? 其实也有解决方案:那就是加锁,在读申请加一个读锁,所有的读申请不阻塞,在写申请加一个写锁,一旦有写申请,则临时阻塞读,等写申请解决完,删除完缓存再放开读。 如果你的业务并发要求不高,读多写少,且对数据一致性有很高的要求,能够采纳这种计划,然而保障强一致性的同时,就会损失一些性能,所以该不该用这种计划,大家能够依据本人业务的属性做好衡量。 计划补充(重要)3、4都属于删除缓存类,其实删除缓存类都会有一个独特的问题,那就是在删除缓存的阶段出错了怎么办?此时再读取缓存的时候每次都是谬误的数据了。 此时解决方案有两个: 一、利用音讯队列进行删除失败的弥补具体的业务逻辑如下: 申请 A 先对数据库进行更新操作在对 Redis 进行删除操作的时候发现报错,删除失败此时将 Redis 的 key 作为音讯体发送到音讯队列中零碎接管到音讯队列发送的音讯后再次对 Redis 进行删除操作 ...

February 27, 2024 · 1 min · jiezi

关于java:深入浅出高性能低延迟消息传递框架Disruptor

第1章:引言大家好,我是小黑,咱们明天来聊一聊Disruptor框架,这是一个高性能的、低提早的消息传递框架,特地适宜用在日志记录、网关,异步事件处理这样的场景。Disruptor之所以弱小,关键在于它的设计哲学和底层实现。对于Java程序员来说,理解Disruptor不仅能帮忙咱们构建更高效的零碎,还能深入对并发和零碎设计的了解。 说到高性能,咱们就不得不提一提并发编程。传统的并发队列,比方BlockingQueue,的确简略好用。然而,它在解决大量并发数据时,性能就显得有点顾此失彼了。这时候,Disruptor就闪亮退场了。它通过一种称为"Ring Buffer"的数据结构,加上独特的消费者和生产者模式,大幅度提高了并发解决的效率。 再来看看具体场景。设想一下,小黑正在开发一个高频交易系统,这外面的每一个毫秒都至关重要。如果应用传统的队列,零碎的响应工夫和吞吐量可能就成了瓶颈。然而,如果用Disruptor来解决交易事件,就能显著缩小提早,晋升处理速度。这就是Disruptor的魅力所在。 第2章:Disruptor框架概述说到Disruptor,咱们首先要理解它的外围组件:Ring Buffer。这不是个别的队列,而是一种环形的数据结构,能高效地在生产者和消费者之间传递数据。它的特点是事后调配固定数量的元素空间,这就缩小了动态内存调配带来的性能损耗。 来看一段简略的代码示例,咱们用Java来创立一个根本的Ring Buffer: import com.lmax.disruptor.RingBuffer;import com.lmax.disruptor.dsl.Disruptor;import com.lmax.disruptor.dsl.ProducerType;public class SimpleDisruptorExample { public static void main(String[] args) { // 定义事件工厂 EventFactory<LongEvent> eventFactory = new LongEventFactory(); // 指定Ring Buffer的大小,必须是2的幂次方 int bufferSize = 1024; // 构建Disruptor Disruptor<LongEvent> disruptor = new Disruptor<>( eventFactory, bufferSize, Executors.defaultThreadFactory(), ProducerType.SINGLE, new BlockingWaitStrategy() ); // 这里能够增加事件处理器 disruptor.handleEventsWith(new LongEventHandler()); // 启动Disruptor disruptor.start(); // 获取Ring Buffer RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer(); // 上面能够向Ring Buffer公布事件 // ... }} ...

February 27, 2024 · 2 min · jiezi

关于java:如何创建自己的Spring-Boot-Starter并为其编写单元测试

当咱们想要封装一些自定义性能给他人应用的时候,创立Spring Boot Starter的模式是最好的实现形式。如果您还不会构建本人的Spring Boot Starter的话,本文将带你一起创立一个本人的Spring Boot Starter。 疾速入门创立一个新的 Maven 我的项目。第三方封装的命名格局是 xxx-spring-boot-starter ,例如:didispace-spring-boot-starter。编辑pom.xml,增加spring-boot-autoconfigure和spring-boot-starter依赖<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency></dependencies>创立一个用 @Configuration 正文的配置类,在这里您能够应用@Bean来创立应用@ConditionalOnClass、@ConditionalOnMissingBean等条件正文来管制何时利用配置。@Configuration@ConditionalOnClass(MyFeature.class)@ConditionalOnProperty(prefix = "myfeature", name = "enabled", matchIfMissing = true)public class MyFeatureAutoConfiguration { @Bean @ConditionalOnMissingBean public MyFeature myFeature() { return new MyFeature(); }}在src/main/resources/META-INF目录下创立spring.factories文件,并在org.springframework.boot.autoconfigure.EnableAutoConfiguration关键字下列出您的主动配置类,比方:org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.didispace.myfeature.MyFeatureAutoConfiguration该配置的作用是让Spring Boot利用在引入您自定义Starter的时候能够主动这里的配置类。 留神:Spring Boot 2.7开始,不再举荐应用spring.factories,而是改用/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,文件内容间接放须要主动加载配置类门路即可。这个变更具体可见之前的这篇文章:《Spring Boot 2.7开始spring.factories不举荐应用了》验证测试在制作Spring Boot Starter的时候,肯定记得应用单元测试来验证和确保自动化配置类在任何条件逻辑在启动器下可能依照正确的预期运行。 创立单元测试应用@SpringBootTest加载残缺的应用程序上下文,并验证启动程序是否正确配置了 Bean 和属性。 @SpringBootTest(classes = TestApplication.class)public class MyStarterAutoConfigurationTest { @Autowired(required = false) private MyService myService; @Test public void testMyServiceAutoConfigured() { assertNotNull(myService, "MyService should be auto-configured"); }}笼罩不同的配置如果有不同的配置计划,那么还须要应用@TestPropertySource或@DynamicPropertySource笼罩属性以测试不同配置下的状况。 ...

February 27, 2024 · 1 min · jiezi

关于java:面试官说一下红锁RedLock的实现原理

RedLock 是一种分布式锁的实现算法,由 Redis 的作者 Salvatore Sanfilippo(也称为 Antirez)提出,次要用于解决在分布式系统中实现牢靠锁的问题。在 Redis 独自节点的根底上,RedLock 应用了多个独立的 Redis 实例(通常倡议是奇数个,比方 5 个),独特合作来提供更健壮的分布式锁服务。 RedLock 算法旨在解决单个 Redis 实例作为分布式锁时可能呈现的单点故障问题,通过在多个独立运行的 Redis 实例上同时获取锁的形式来进步锁服务的可用性和安全性。RedLock 具备以下次要个性: 互斥性:在任何工夫,只有一个客户端能够取得锁,确保了资源的互斥拜访。防止死锁:通过为锁设置一个较短的过期工夫,即便客户端在取得锁后因为网络故障等起因未能按时开释锁,锁也会因为过期而主动开释,防止了死锁的产生。容错性:即便一部分 Redis 节点宕机,只有大多数节点(即过半数以上的节点)仍在线,RedLock 算法就能持续提供服务,并确保锁的正确性。 1.RedLock 实现思路RedLock 是对集群的每个节点进行加锁,如果大多数节点(N/2+1)加锁胜利,则才会认为加锁胜利。 这样即便集群中有某个节点挂掉了,因为大部分集群节点都加锁胜利了,所以分布式锁还是能够持续应用的。 2.工作流程RedLock 算法的工作流程大抵如下: 客户端向多个独立的 Redis 实例尝试获取锁,设置锁的过期工夫十分短。如果客户端能在大部分节点上胜利获取锁,并且所破费的工夫小于锁的过期工夫的一半,那么认为客户端胜利获取到了分布式锁。当客户端实现对受爱护资源的操作后,它须要向所有曾获取锁的 Redis 实例开释锁。若在开释锁的过程中,客户端因故无奈实现,因为设置了锁的过期工夫,锁最终会主动过期开释,防止了死锁。 3.根本应用在 Java 开发中,能够应用 Redisson 框架很不便的实现 RedLock,具体操作代码如下: import org.redisson.Redisson;import org.redisson.api.RedisClient;import org.redisson.api.RedissonClient;import org.redisson.config.Config;import org.redisson.redisson.RedissonRedLock;public class RedLockDemo { public static void main(String[] args) { // 创立 Redisson 客户端配置 Config config = new Config(); config.useClusterServers() .addNodeAddress("redis://127.0.0.1:6379", "redis://127.0.0.1:6380", "redis://127.0.0.1:6381"); // 假如有三个 Redis 节点 // 创立 Redisson 客户端实例 RedissonClient redissonClient = Redisson.create(config); // 创立 RedLock 对象 RedissonRedLock redLock = redissonClient.getRedLock("resource"); try { // 尝试获取分布式锁,最多尝试 5 秒获取锁,并且锁的有效期为 5000 毫秒 boolean lockAcquired = redLock.tryLock(5, 5000, TimeUnit.MILLISECONDS); if (lockAcquired) { // 加锁胜利,执行业务代码... } else { System.out.println("Failed to acquire the lock!"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println("Interrupted while acquiring the lock"); } finally { // 无论是否胜利获取到锁,在业务逻辑完结后都要开释锁 if (redLock.isLocked()) { redLock.unlock(); } // 敞开 Redisson 客户端连贯 redissonClient.shutdown(); } }}4.实现原理Redisson 中的 RedLock 是基于 RedissonMultiLock(联锁)实现的。RedissonMultiLock 是 Redisson 提供的一种分布式锁类型,它能够同时操作多个锁,以达到对多个锁进行对立治理的目标。联锁的操作是原子性的,即要么全副锁住,要么全副解锁。这样能够保障多个锁的一致性。 ...

February 27, 2024 · 2 min · jiezi

关于java:Spring-Security权限控制框架使用指南

在罕用的后盾管理系统中,通常都会有拜访权限管制的需要,用于限度不同人员对于接口的拜访能力,如果用户不具备指定的权限,则不能拜访某些接口。 本文将用 waynboot-mall 我的项目举例,给大家介绍常见后管零碎如何引入权限管制框架 Spring Security。纲要如下, 一、什么是 Spring SecuritySpring Security 是一个基于 Spring 框架的开源我的项目,旨在为 Java 应用程序提供弱小和灵便的安全性解决方案。Spring Security 提供了以下个性: 认证:反对多种认证机制,如表单登录、HTTP 根本认证、OAuth2、OpenID 等。受权:反对基于角色或权限的访问控制,以及基于表达式的细粒度管制。防护:提供了多种防护措施,如避免会话固定、点击劫持、跨站申请伪造等攻打。集成:与 Spring 框架和其余第三方库和框架进行无缝集成,如 Spring MVC、Thymeleaf、Hibernate 等。二、如何引入 Spring Security在 waynboot-mall 我的项目中间接引入 spring-boot-starter-security 依赖, <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>3.1.0</version> </dependency></dependencies>三、如何配置 Spring Security在 Spring Security 3.0 中要配置 Spring Security 跟以往是有些不同的,比方不在继承 WebSecurityConfigurerAdapter。在 waynboot-mall 我的项目中,具体配置如下, @Configuration@EnableWebSecurity@AllArgsConstructor@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true)public class SecurityConfig { private UserDetailsServiceImpl userDetailsService; private AuthenticationEntryPointImpl unauthorizedHandler; private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; private LogoutSuccessHandlerImpl logoutSuccessHandler; @Bean public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { httpSecurity // cors启用 .cors(httpSecurityCorsConfigurer -> {}) .csrf(AbstractHttpConfigurer::disable) .sessionManagement(httpSecuritySessionManagementConfigurer -> { httpSecuritySessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS); }) .exceptionHandling(httpSecurityExceptionHandlingConfigurer -> { httpSecurityExceptionHandlingConfigurer.authenticationEntryPoint(unauthorizedHandler); }) // 过滤申请 .authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> { authorizationManagerRequestMatcherRegistry .requestMatchers("/favicon.ico", "/login", "/favicon.ico", "/actuator/**").anonymous() .requestMatchers("/slider/**").anonymous() .requestMatchers("/captcha/**").anonymous() .requestMatchers("/upload/**").anonymous() .requestMatchers("/common/download**").anonymous() .requestMatchers("/doc.html").anonymous() .requestMatchers("/swagger-ui/**").anonymous() .requestMatchers("/swagger-resources/**").anonymous() .requestMatchers("/webjars/**").anonymous() .requestMatchers("/*/api-docs").anonymous() .requestMatchers("/druid/**").anonymous() .requestMatchers("/elastic/**").anonymous() .requestMatchers("/message/**").anonymous() .requestMatchers("/ws/**").anonymous() // 除下面外的所有申请全副须要鉴权认证 .anyRequest().authenticated(); }) .headers(httpSecurityHeadersConfigurer -> { httpSecurityHeadersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable); }); // 解决跨域申请中的Preflight申请(cors),设置corsConfigurationSource后无需应用 // .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() // 对于登录login 验证码captchaImage 容许匿名拜访 httpSecurity.logout(httpSecurityLogoutConfigurer -> { httpSecurityLogoutConfigurer.logoutUrl("/logout"); httpSecurityLogoutConfigurer.logoutSuccessHandler(logoutSuccessHandler); }); // 增加JWT filter httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); // 认证用户时用户信息加载配置,注入springAuthUserService httpSecurity.userDetailsService(userDetailsService); return httpSecurity.build(); } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { return authenticationConfiguration.getAuthenticationManager(); } /** * 强散列哈希加密实现 */ @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); }}这里具体介绍下 SecurityConfig 配置类, ...

February 27, 2024 · 2 min · jiezi

关于java:面试官限流的实现方式有哪些

限流是指在各种利用场景中,通过技术和策略伎俩对数据流量、申请频率或资源耗费进行有打算的限度,以防止零碎负载过高、性能降落甚至解体的状况产生。限流的指标在于保护零碎的稳定性和可用性,并确保服务质量。 应用限流的益处有以下几个: 爱护零碎稳定性:过多的并发申请可能导致服务器内存耗尽、CPU 使用率饱和,从而引发零碎响应慢、无奈失常服务的问题。避免资源滥用:确保无限的服务资源被正当偏心地调配给所有用户,避免个别用户或恶意程序适度耗费资源。优化用户体验:对于网站和应用程序而言,如果任由高并发导致响应速度变慢,会影响所有用户的失常应用体验。保障平安:在网络层面,限流有助于防备 DoS/DDoS 攻打,升高零碎蒙受歹意攻打的危险。运维老本管制:正当的限流措施能够帮忙企业缩小不必要的硬件投入,节俭经营老本。在 Java 中,限流的实现形式有很多种,例如以下这些: 单机限流:应用 JUC 下的 Semaphore 限流,或一些罕用的框架,例如 Google 的 Guava 框架进行限流,但这种限流形式都是基于 JVM 层面的内存级别的单台机器限流。网关层限流:单机限流往往不适用于分布式系统,而分布式系统能够在网关层限流,如 Spring Cloud Gateway 通过 Sentinel、Hystrix 对整个集群进行限流。Nginx 限流:通常在网关层的上游,咱们会应用 Nginx 一起来配合应用,也就是用户申请会先到 Nginx(或 Nginx 集群),而后再将申请转发给网关,网关再调用其余的微服务,从而实现整个流程的申请调用,因而 Nginx 限流也是分布式系统中罕用的限流伎俩。它们限流的具体实现如下。 1.单机限流JVM 层面多线程级别的限流能够应用 JUC 下的 Semaphore,具体应用示例如下: import java.util.concurrent.Semaphore;import java.util.concurrent.TimeUnit;public class SemaphoreExample { private final Semaphore semaphore = new Semaphore(5); // 只容许5个线程同时拜访 public void accessResource() { try { semaphore.acquire(); // 获取许可,如果以后许可数有余,则会阻塞 System.out.println(Thread.currentThread().getName() + "取得了许可,正在拜访资源..."); // 模仿拜访资源的工夫耗费 Thread.sleep(2000); System.out.println(Thread.currentThread().getName() + "拜访资源完结,开释许可..."); } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); } finally { semaphore.release(); // 拜访完结后开释许可 } } public static void main(String[] args) { SemaphoreExample example = new SemaphoreExample(); for (int i = 0; i < 10; i++) { new Thread(() -> example.accessResource()).start(); } }}想要实现更平滑的单机限流,能够思考 Google 提供的 Guava 框架,它的应用示例如下。 ...

February 26, 2024 · 2 min · jiezi

关于java:分库分表如何管理不同实例中几万张分片表

大家好,我是小富~ ShardingSphere实现分库分表,如何治理散布在不同数据库实例中的成千上万张分片表? 上边的问题是之前有个小伙伴看了我的分库分表的文章,私下征询我的,看到他的发问我第一感觉就是这老铁没用过ShardingSphere,因为这个问题在ShardingSphere中曾经有了很好的解决方案,接下来看看怎么实现。 本文案例代码GitHub地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/shardingsphere101/shardingsphere-autocreate-table系列往期往期系列文章(我佛系更新,无上限拖更): (一)好好的零碎,为什么要分库分表? (二)分库分表的 21 条法令,hold 住! (三)2 种形式疾速实现分库分表,轻松拿捏! 本文是《ShardingSphere5.x分库分表原理与实战》系列的第四篇文章,在进行分库分表设计时,确认好了数据节点数量和分片策略当前,接下来要做的就是治理大量的分片表。理论施行过程中可能存在上百个分片数据库实例,每个实例中都可能有成千上万个分片表,如果仅依附人力来实现这些工作显然是不事实的。所以,想要疾速且自动化治理这些分片表,应用工具是十分必要滴。 前言ShardingSphere框架成员中的Shardingsphere-jdbc和Shardingsphere-proxy都提供了自动化治理分片表的性能auto-tables,能够对立保护大量的分片表,防止了手动编写脚本和保护分片表的繁琐工作,极大水平缩小分库分表的开发和保护老本,晋升效率和可靠性。 这里咱们先应用Shardingsphere-jdbc来实际操作一下,Shardingsphere-proxy形式后续会有独自的文章具体解说,就不在这里开展了。 筹备工作假如咱们要对t_order表进行分库分表,首先咱们要做的就是确定好分片计划,这里应用两个数据库实例db0、db1,每个实例中t_order表分成1000张分片表t_order_1 ~ t_order_1000,order_id字段作为分片键,分片算法应用取模算法order_id % n,分布式主键生成策略采纳snowflake。 t_order逻辑表的表构造如下: CREATE TABLE `t_order` ( `order_id` BIGINT ( 20 ) NOT NULL COMMENT "订单表分布式主健ID", `order_number` VARCHAR ( 255 ) NOT NULL COMMENT "订单号", `customer_id` BIGINT ( 20 ) NOT NULL COMMENT "用户ID", `order_date` date NOT NULL COMMENT "下单工夫", `total_amount` DECIMAL ( 10, 2 ) NOT NULL COMMENT "订单金额", PRIMARY KEY ( `order_id` ) USING BTREE );有了这些根底信息,能够先来进行t_order表的分片配置了,不思考其余因素,这里先Run起来! ...

February 26, 2024 · 3 min · jiezi

关于java:从零开始学Spring-Boot系列Hello-World

欢送来到从零开始学Spring Boot的旅程!在这个系列的第二篇文章中,咱们将从一个十分根底但重要的示例开始:创立一个简略的Spring Boot应用程序,并输入“Hello World”。 1. 环境筹备首先,确保你的开发环境曾经装置了以下工具: Java Development Kit (JDK) :Spring Boot须要Java来运行,所以你须要装置JDK。能够从Oracle官网下载最新版本的JDK。本文应用的是jdk-17.0.9IDE(集成开发环境) :尽管Spring Boot能够在任何文本编辑器中编写和运行,但应用IDE能够大大提高开发效率。举荐的IDE包含IntelliJ IDEA、Eclipse和Spring Tool Suite等,本文应用的是 IntelliJ IDEA 2023.3.3。Maven或Gradle :Spring Boot应用Maven或Gradle作为构建工具。这两个工具都能帮忙你治理我的项目依赖,构建和打包应用程序。本文应用的是Gradle 8.32. 创立Spring Boot我的项目本文为大家提供两种创立Spring Boot我的项目的形式。 应用官网Spring Initializr创立你能够应用Spring Initializr(https://start.spring.io/)来疾速生成一个Spring Boot我的项目的骨架。在这个网站上,你能够抉择我的项目类型(Maven或Gradle)、我的项目元数据(Group、Artifact、Name、Description等)、包构造(Java包名)、依赖项(例如Spring Web、Lombok等)等。为了这个“Hello World”示例,咱们只须要最根本的Spring Boot我的项目。抉择Gradle作为构建工具,而后增加必要的依赖。点击“Generate”按钮下载ZIP文件,解压后导入到你的IDE中应用IntelliJ IDEA创立 Spring Boot我的项目的骨架,在菜单栏File选项,抉择New Project。在页面抉择Spring Initializr,抉择我的项目类型(Maven或Gradle)、我的项目元数据(Group、Artifact、Name、Description等)、包构造(Java包名),抉择Next。抉择Spring Boot版本,依赖项(例如Spring Web、Lombok等)。点击Create。3. 编写 HelloWorldController在IntelliJ IDEA 中关上我的项目后,你会看到一个默认生成的SpringbootLearningApplication类。这个类蕴含一个main办法,它是程序的入口点。咱们创立一个HelloWorldController,在这个类中,咱们将增加一个简略的控制器来输入“Hello World”。 在HelloWorldController应用@RestController注解标记它。这个类蕴含一个名为helloWorld的办法,该办法应用@GetMapping注解标记,示意当拜访利用的根URL(/)时,将调用这个办法。该办法返回一个字符串"Hello World"。 当初,你能够运行SpringbootLearningApplication类中的main办法来启动Spring Boot应用程序。如果你的idea配置正确,你能够间接点击运行按钮来启动应用程序。当应用程序启动后,你应该能在控制台看到相似于以下的输入: 这表明Spring Boot应用程序已胜利启动。当初,你能够关上浏览器并拜访http://localhost:8080(默认端口是8080,但可能会因你的配置而异)。你应该能在浏览器中看到“Hello World”这几个字。 4. 总结在这个“Hello World”示例中,咱们创立了一个简略的Spring Boot应用程序,并输入了“Hello World”。尽管这个示例很简略,但它展现了Spring Boot的根本构造和如何应用控制器来解决HTTP申请。在后续的文章中,咱们将深入探讨Spring Boot的更多个性和性能,包含数据拜访、安全性、RESTful API等。敬请期待! 源文来自:https://daimajiangxin.cn

February 25, 2024 · 1 min · jiezi

关于java:揭秘一线大厂Redis面试高频考点3万字长文吐血整理

3万+长文揭秘一线大厂Redis面试高频考点,整顿不易,求一键三连:点赞、分享、珍藏本文,已收录于,我的技术网站 aijiangsir.com,有大厂残缺面经,工作技术,架构师成长之路,等教训分享 1、说说什么是Redis?Redis是一个开源的、基于内存的高性能键值对数据库,反对多种类型的数据结构,如字符串(strings)、列表(lists)、汇合(sets)、有序汇合(sorted sets)、哈希表(hashes)、位图(bitmaps)、超日志(hyperloglogs)和天文空间索引(geospatial indexes)。因为它的数据是寄存在内存中的,这使得Redis可能提供极高的数据读写速度,通常可能达到每秒数十万次的读写操作。Redis还反对数据的长久化,能够将内存中的数据保留到硬盘中,保证数据的安全性。Redis的次要特点包含: 性能极高:Redis可能反对超高的每秒读写操作次数,这得益于它的内存存储个性和高效的数据结构设计。丰盛的数据类型:Redis反对多种数据类型,使得它能够用于多种场景,如缓存、音讯队列、应用程序的会话状态存储等。反对数据长久化:Redis提供了两种数据长久化的形式,RDB(快照存储)和AOF(追加文件存储),能够依据须要抉择最合适的长久化策略。个性丰盛:Redis还反对事务、管道(pipelining)、公布/订阅(pub/sub)模式等高级性能。主从复制:Redis反对主从复制,即主动将数据从一个Redis服务器复制到一个或多个从服务器,用于数据备份或读写拆散。高可用和分布式:通过Redis Sentinel来实现高可用性的监控和故障转移,以及通过Redis Cluster来实现数据的主动分片和治理。 2、Redis的优缺点Redis作为一个高性能的内存键值存储系统,在泛滥场景下被广泛应用,既有其显著的长处,也存在一些限度和毛病。 Redis的长处高性能:Redis将所有数据存储在内存中,访问速度快,可能反对高达每秒数十万次的读写操作,非常适合须要疾速读写访问的场景。丰盛的数据类型:Redis不仅仅是一个简略的键值对存储系统,它反对字符串、列表、汇合、有序汇合、哈希表等数据类型,使得Redis能够很容易地解决各种简单的利用场景。数据长久化:Redis反对RDB和AOF两种长久化形式,能够将内存中的数据保留到磁盘中,确保数据的安全性。反对事务:Redis通过MULTI、EXEC、DISCARD和WATCH命令反对事务,能够执行一组命令,并保障原子性和一致性。高可用和分布式反对:通过Redis Sentinel来实现高可用的架构,以及通过Redis Cluster来实现主动分片和数据的分布式存储。公布/订阅音讯零碎:Redis反对公布/订阅模式,能够用作音讯队列零碎,进行音讯的公布和订阅。简略易用:Redis有着简洁高效的设计,易于装置和应用,同时社区提供了丰盛的客户端反对,笼罩了简直所有支流的编程语言。 ### Redis的毛病 数据集大小受限于物理内存:因为Redis是基于内存的存储系统,其数据集的大小受限于服务器的物理内存大小,对于大规模数据处理可能须要较高的老本。长久化可能影响性能:尽管Redis提供数据长久化的能力,但在某些配置下(如应用AOF的每次写入模式),长久化操作可能会对性能产生影响。单线程模型限度:Redis应用单线程模型来解决命令,尽管这简化了设计并有助于客户端以确定的程序执行命令,但也意味着在多核服务器上不能无效利用多核CPU的劣势。数据安全和隐衷问题:因为数据存储在内存中,如果服务器被侵入,数据可能会被轻易拜访。尽管Redis提供了一些平安个性(如密码保护和SSL加密),但默认配置下这些个性并未启用。内存治理挑战:在应用Redis时,开发者须要认真治理内存,比方定期删除不必的键,应用适合的数据结构等,以防止内存收缩。只管存在这些毛病,Redis凭借其杰出的性能和灵活性,依然是许多高负载利用和服务的首选解决方案。正确的应用和适当的架构设计能够帮忙最大限度地施展其劣势,同时缓解一些潜在的毛病。 3、Redis为什么这么快Redis之所以可能提供如此高速的性能,次要是因为以下几个关键因素的联合: 齐全基于内存:Redis是一个内存数据库,所有的数据读写操作都是间接对内存进行,防止了磁盘IO的提早。内存的访问速度远远快于任何模式的磁盘存储,这是Redis高性能的最根本保障。数据结构简略且高效:Redis反对的数据结构十分高效,如字符串、列表、汇合、哈希表等,都是为快速访问和操作而优化的。Redis外部对这些数据结构进行了高度优化,使得数据操作尽可能地疾速和高效。单线程模型:Redis采纳单线程模型解决命令,防止了多线程的上下文切换和竞争条件,这使得Redis在解决每个命令时简直没有任何性能损耗。尽管是单线程,但因为是基于内存操作,处理速度极快,足以应答大多数高并发场景。非阻塞IO:Redis应用非阻塞IO模型,采纳多路复用技术。这意味着Redis服务器能够同时解决多个客户端的申请,而不是一次解决一个申请,极大进步了网络通信的效率。高效的键值存储模型:Redis的键值对存储模型非常简单,使得数据的查找和拜访十分疾速。对于大多数操作,Redis可能以常数工夫复杂度进行解决,即O(1)。优化的长久化策略:Redis提供了灵便的数据长久化选项(如RDB和AOF),能够依据须要进行配置以均衡性能和数据安全性。即便在执行长久化操作时,Redis也尽量减少对性能的影响。精心设计的协定:Redis协定简洁且易于解析,客户端和服务器之间的通信十分高效,缩小了网络通信的开销。防止简单的计算:Redis设计之初就是为了高速存取数据,它防止了简单的查问和事务处理,每个操作都尽可能地简略和疾速。通过这些设计和实现上的优化,Redis可能提供极高的性能,满足高并发、低提早的利用场景需要。这也是Redis在缓存、音讯队列、实时剖析等多种场景中被宽泛应用的起因。 4、Redis那么快,为什么不必它做主数据库,只用它做缓存?Redis尽管以其高性能而闻名,特地是在解决大量数据时提供极低的提早和高吞吐量,但将其作为主数据库应用而不仅仅是缓存,须要思考以下几个方面的限度和挑战: 内存老本:Redis是基于内存的存储系统,而内存的老本相比于硬盘等其余存储介质要高得多。随着数据量的减少,依赖Redis作为主数据库的老本会迅速减少,特地是对于存储大量数据的利用来说,这可能是一个显著的老本因素。数据持久性:尽管Redis提供了数据长久化的性能,如RDB和AOF,以保障数据安全,但这些机制在产生系统故障时依然可能面临数据失落的危险,尤其是在极其状况下。对于须要严格数据一致性和完整性保障的利用,依赖于内存的数据库可能不是最佳抉择。数据安全和隐衷问题:因为Redis设计为高性能的存储系统,其平安个性可能不如专门设计用于长久存储的数据库系统。尽管能够通过配置和应用SSL等伎俩加强安全性,但对于须要高级平安保障的利用,可能须要更业余的解决方案。简单查问的限度:Redis尽管反对多种数据结构,但它不像关系数据库那样反对SQL查询语言和简单的查问操作。对于须要执行简单查问、联结操作或事务处理的利用,Redis可能不能满足需要。单线程模型的限度:Redis的单线程模型尽管简化了操作并保障了高性能,但也意味着在多核处理器上无奈充分利用硬件资源。对于计算密集型的场景,这可能成为性能的瓶颈。事务处理:Redis只反对简略的事务处理,对于简单的事务无能为力,比方跨多个键的事务处理。因而,尽管Redis以其杰出的性能和灵便的数据结构实用于许多场景,如缓存、音讯队列、会话存储等,但将其作为主数据库应用时,上述限度可能会导致它不适宜所有利用。通常,开发者会联合应用Redis和其余数据库系统(如MySQL、PostgreSQL或MongoDB等),利用各自的劣势,以实现更加全面和高效的数据管理和存储解决方案。 5、讲讲Redis的线程模型?Redis的线程模型是其性能高效的关键因素之一。传统上,Redis应用单线程模型来解决客户端的申请,但这并不意味着Redis服务器只有一个线程在运行。上面具体解释Redis的线程模型及其如何工作: 单线程架构在Redis 6之前,Redis次要应用单个线程来解决所有的命令申请,这意味着在任意时刻,只有一个命令在被执行。这种设计的长处是防止了多线程编程中常见的并发问题,如数据竞争、锁的开销等,使得Redis可能以十分高的效率执行操作。 高效的数据结构:Redis外部应用高效的数据结构,如跳跃表(用于有序汇合)和压缩列表(用于小列表和哈希),这些构造在单线程模型中体现得十分高效。事件驱动模型:Redis应用基于事件的模型,通过非阻塞IO和多路复用技术来监听和解决客户端连贯,这容许单线程高效地解决多个并发连贯。 多线程IO解决(Redis 6及以上)从Redis 6开始,引入了IO多线程模型,用于改善网络IO的解决效率。须要留神的是,这个多线程模型仅用于网络IO的读写操作,而不是命令的执行。命令执行依然是单线程的,放弃了Redis操作的原子性和一致性。 IO线程:能够配置多个IO线程来并行处理客户端申请的读写操作。这些线程次要负责将命令从网络读取到内存中,以及将响应从内存写回到网络,不波及命令的理论执行。主线程:只管引入了IO线程,Redis的命令解决逻辑依然在单个主线程中执行。这意味着数据的读取、写入、操作等都是由单个线程平安地执行,防止了并发拜访的问题。 线程模型的优化合理配置IO线程:在多核处理器上,通过合理配置IO线程的数量,能够显著进步Redis解决大量并发连贯的能力,而不影响命令执行的性能。利用异步操作:Redis反对异步操作,如异步写入(AOF重写)和异步删除(惰性删除),这些操作能够在后盾线程中实现,缩小对主线程解决能力的影响。Redis的线程模型优化了性能和并发解决能力,同时放弃了简略和高效的特点。通过将命令执行与网络IO拆散,Redis可能在保障操作安全性的同时,充分利用古代多核CPU的性能,提供高吞吐量和低提早的数据服务。 6、Redis能够用来干什么?Redis作为一个高性能的键值存储系统,因其杰出的读写速度和灵便的数据结构,被广泛应用于多种场景中。以下是Redis的一些典型利用场景: 缓存零碎:这是Redis最常见的用处之一。利用其高速的读写性能,能够将热点数据存储在Redis中,加重后端数据库的压力,放慢数据的读取速度,进步整体的零碎响应速度。会话存储(Session Store):Redis能够用来存储用户会话信息,尤其实用于分布式系统中的会话共享。因为Redis提供长久化性能,即便零碎重启,用户的会话信息也不会失落。音讯队列零碎:利用Redis的公布/订阅模式,能够实现音讯队列的性能,反对高并发的消息传递。此外,利用列表(List)数据结构,也能够实现简略的音讯队列。实时剖析:Redis的高性能读写能力使其非常适合须要实时剖析解决的场景,如计数器、实时系统监控、实时交易剖析等。排行榜/计数器:Redis的有序汇合(Sorted Set)数据结构非常适合实现排行榜零碎,能够疾速增加、删除、更新元素,并可能实时获取排名信息。天文空间数据处理:Redis的天文空间索引(Geo)性能能够用来存储地理位置信息,并进行地理位置查问,适宜开发地理位置服务,如查找左近的人或地点。分布式锁:Redis能够实现分布式锁的性能,用于多个过程或零碎之间的同步访问控制。通过SET命令的NX(Not Exists)选项,能够确保只有一个客户端可能取得锁。数据过期解决:Redis反对设置键的生命周期,能够用于须要过期解决的场景,如长期拜访令牌的存储、缓存数据的主动清理等。全页缓存(FPC):对于动态网页或者页面输入后果不常常变动的场景,能够将页面HTML存储在Redis中,实现疾速的页面加载。轻量级社交网络性能:利用Redis的数据结构和操作命令,能够实现社交网络中的某些性能,如好友关系、共享状态更新、工夫线等。 ## 7、Memcached和Redis的区别? Memcached和Redis都是高性能的分布式缓存零碎,宽泛用于晋升大型动静Web利用的速度,缩小数据库负载。只管它们在某些场景下能够调换应用,但两者之间还是存在一些要害的区别: ### 数据模型和数据类型 Memcached:提供一个简略的键值存储解决方案,次要反对字符串类型的数据。这意味着它在解决只须要缓存简略数据的场景中十分无效。Redis:反对更丰盛的数据类型,包含字符串(Strings)、列表(Lists)、汇合(Sets)、有序汇合(Sorted Sets)、哈希表(Hashes)、位图(Bitmaps)、超日志(HyperLogLogs)和天文空间索引(Geospatial Indexes)。这种多样性使得Redis可能实用于更简单的利用场景。 持久性Memcached:次要设计为一个纯缓存零碎,没有提供数据长久化性能,一旦缓存服务器重启,所有的数据都会失落。Redis:提供多种数据长久化选项,如RDB(周期性快照)和AOF(Append Only File,追加写文件)。这使得Redis既能够用作缓存零碎,也能够用作长久化的NoSQL数据库。 分布式反对Memcached:须要内部工具或客户端反对来实现分布式缓存环境,自身不提供数据分片或集群性能。Redis:自Redis 3.0起,官网反对集群模式,提供数据分片(Sharding)、主动分区和高可用性等个性。 高可用和集群Memcached:尽管能够通过一些客户端库实现简略的高可用计划,但Memcached自身不提供内建的高可用或复制个性。Redis:反对主从复制(Replication)、哨兵零碎(Sentinel)和主动分区的集群,为构建高可用的分布式缓存环境提供了更多的可能性。 原子操作Memcached和Redis都反对原子操作,但因为Redis反对更多的数据类型,因而Redis在这方面提供了更丰盛的原子操作命令。 其余个性Redis还提供了许多Memcached不具备的个性,如公布/订阅音讯零碎、Lua脚本反对、事务以及天文空间反对等。 应用场景Memcached实用于简略的缓存场景,特地是当须要疾速缓存大量数据时。Redis不仅实用于缓存场景,还能够用于须要简单数据结构和长久化需要的利用,比方音讯队列、实时剖析、天文空间数据处理等。 8、为什么要用 Redis 而不必 map/guava 做缓存?应用Redis而不是map或Guava做缓存,通常是出于以下几个思考: 1. 分布式环境反对Redis是一个独立的服务器过程,可能反对多个利用实例共享缓存数据,非常适合分布式环境。这意味着无论是扩大利用实例还是实现高可用性,Redis都可能提供统一的服务。Map/Guava缓存通常只能在单个JVM实例中应用,不适宜分布式环境,因为每个利用实例都会保护本人的缓存正本,这不仅减少了内存耗费,也使得缓存数据难以保持一致。 2. 长久化能力Redis提供了数据长久化的能力,能够将内存中的数据保留到硬盘中,这对于须要保证数据不会因为过程退出或服务器重启而失落的场景十分重要。Map/Guava缓存通常只存在于内存中,一旦利用重启,所有的缓存数据都会失落。 3. 高级数据结构和操作Redis提供了丰盛的数据结构(如列表、汇合、有序汇合等)和相应的操作,这些数据结构和操作对于实现简单的缓存策略和性能十分有用。Map/Guava缓存通常提供较为根本的数据结构和操作,可能无奈满足某些简单利用场景的需要。 4. 缓存淘汰策略Redis内置了多种缓存淘汰策略,如LRU(最近起码应用)、LFU(最不常常应用)等,这些策略能够帮忙主动治理缓存空间,移除不再须要的缓存项。Map/Guava缓存尽管也提供了一些缓存淘汰策略,但相比Redis来说可能不那么灵便或弱小。 5. 网络拜访和可伸缩性Redis作为一个网络服务,能够被应用程序通过网络拜访,这使得它能够很容易地程度扩大,满足一直增长的数据和访问量。Map/Guava缓存是在应用程序的同一过程内拜访,不反对网络拜访,限度了其在大型分布式系统中的可伸缩性。 6. 工具和社区反对Redis领有一个沉闷的社区和丰盛的工具生态,提供了大量的客户端库、监控工具和管理工具等。Map/Guava尽管也是宽泛应用的Java库,但在分布式缓存方面的工具和社区反对可能不如Redis丰盛。 9、Redis 数据类型有哪些?Redis反对多种数据类型,使其可能应答不同的数据存储需要。上面是Redis反对的次要数据类型: ...

February 24, 2024 · 3 min · jiezi

关于java:西安有哪些值得去的互联网公司最新版

接下来的一段时间,我将出一些中央上比拟值得去的公司,供 Java 程序员作为找工作和跳槽时进行筛选。 西安作为中国西部的科技和互联网产业倒退的重要城市,领有着少些出名且对 Java 程序员具备吸引力的互联网公司,接下来,咱们将分这些公司分为 3 类来介绍: 私企国企外企 0.国企、私企和外企有什么区别?私企(压力大、薪资高、节奏快、加班多):Java 程序员可能会面临较大的工作压力,因为私企通常更加重视业绩和利润,工作节奏较快。然而,私企的灵活性较高,技术更新速度也较快,Java 程序员有更多的机会接触新的技术和业务场景,这有助于他们疾速晋升本人的技术能力。此外,私企的薪酬体系通常也更加灵便,Java 程序员的薪资程度可能会更加与市场接轨。国企(稳固、事少、薪资少、根本不加班、按资排辈关系简单):在国企工作,Java 程序员可能会享有更加稳固的工作环境和福利待遇,因为国企通常更加重视员工的福利待遇和稳定性。然而,国企的降职渠道和速度可能绝对较慢,Java 程序员须要更加重视论资排辈和人际关系。此外,国企的技术更新速度可能也绝对较慢,Java 程序员须要更加重视自我学习和晋升。外企(薪资高、根本不加班、对英语水平有肯定要求):在外企工作,Java 程序员可能会接触到更加国际化的工作环境和团队,有机会与来自不同国家和文化背景的共事单干,这有助于晋升他们的跨文化交换能力。此外,外企通常也更加重视员工的培训和倒退,Java 程序员能够取得更多的职业倒退机会和培训资源。然而,外企的工作节奏和语言要求可能较高,Java 程序员须要具备较强的英语沟通能力和适应能力。 1.私企京东:京东在西安有物流核心,同时也有技术团队。官网招聘地址:https://zhaopin.jd.com/web/job/job_info_list/3华为:可能是西安地区,研发薪资最高的公司了,但也是加班最多的公司,没有之一,华为对学历和学校要求很高。官网招聘地址:https://career.huawei.com/reccampportal/portal5/social-recruitment.html腾讯云:腾讯的全资子公司,目前对西安腾讯云的褒贬不一,但薪资在西安十分有竞争力。官网招聘地址:https://careers.tencent.com/search.html海康威视:https://talent.hikvision.com/society/index奇安信:https://campus.qianxin.com/campus/jobSearch当当网:https://static.dangdang.com/topic/contents/1119/2263.shtml绿盟科技:https://app.mokahr.com/apply/nsfocus/29117/#/jobs其余的公司还有:大华、广联达、中科创达、华勤、闻泰、宇视科技等。 2.国企中兴:国资委上司企业,薪资还行,加班尚可,近几年有肯定的裁员状况产生。官网招聘地址:https://app.mokahr.com/social-recruitment/zte/47588#/jobs南瑞国电(中国电网):https://job.sgepri.sgcc.com.cn/nari-career-ui/socialrecurit招商银行:https://career.cmbchina.com/social/home西安工行:https://job.icbc.com.cn/pc/index.html#/main/social/home/struct汇丰银行:https://www.about.hsbc.com.cn/zh-cn/careers挪动西安研究院:https://wecruit.hotjob.cn/SU63171da50dcad45d81789c63/pb/social.html西安联通软件研究院:https://www.chinaunicom.com/46/menu01/529/column06大唐电信:https://www.datang.com/jrwm.html战火星空:https://www.hotjob.cn/wt/Fiberhome/web/index其余的还有航天类的研究所特地多,例如,504 所、771 所,603 所,中电 20 所、39 所,兵器工业 203 所、204 所、205 所等。 3.外企Thougtworks:https://www.thoughtworks.com/zh-cn/careers4.外包及其他中软、软通能源等都算是西安比拟大的外包公司了。 如有纰漏,欢送评论区补充欠缺。 本文已收录到我的面试小站 www.javacn.site,其中蕴含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、音讯队列等模块。

February 23, 2024 · 1 min · jiezi

关于java:Java-构造函数与修饰符详解初始化对象与控制权限

Java 构造函数Java 构造函数 是一种非凡的类办法,用于在创建对象时初始化对象的属性。它与类名雷同,并且没有返回值类型。 构造函数的作用: 为对象的属性设置初始值执行必要的初始化操作提供创建对象的多种形式构造函数的类型: 默认构造函数: 无参数的构造函数,如果用户没有明确定义构造函数,则 Java 编译器会主动创立一个默认构造函数。带参数的构造函数: 能够为构造函数增加参数,以便在创建对象时传入初始值。示例: public class Main { int x; // 默认构造函数 public Main() { x = 5; } // 带参数的构造函数 public Main(int y) { x = y; } public static void main(String[] args) { Main myObj1 = new Main(); // 调用默认构造函数 System.out.println(myObj1.x); // 输入 5 Main myObj2 = new Main(10); // 调用带参数的构造函数 System.out.println(myObj2.x); // 输入 10 }}构造函数的注意事项: 构造函数不能被重写。构造函数不能被申明为 abstract 或 final。构造函数能够抛出异样。一些额定的阐明: ...

February 22, 2024 · 2 min · jiezi

关于java:设计模式

工厂模式简略工厂简略工厂模式专门定义了一个工厂类用来创立其余类的实例,依据传入参数的不同返回不同类的实例,这些要被创立的类会有一个独特的父类。简略说,简略工厂是为了创立某一父类下不同子类实例的一种模式。毛病:每当有新的子类退出的时候,必须要批改这个工厂类,违反了开闭准则(扩大凋谢,批改敞开)。 工厂模式将多个工厂类形象为一个接口,它负责给出每个工厂类应该实现的办法。每个工厂类创立本人对应的大类的实例。每当有新的大类退出的时候,只需新增本人和本人的工厂类,遵循了开闭准则,且灵便扩大。 形象工厂在工厂模式的根底上,每个工厂类能够生产多个大类的实例,比如说一个电脑工厂既能够生产CPU,也能够生产内存,生产显卡。 单例模式

February 22, 2024 · 1 min · jiezi

关于java:Java异常处理的20个最佳实践告别系统崩溃

引言在Java编程中,异样解决是一个至关重要的环节,它不仅波及到程序的稳定性和安全性,还关系到用户体验和系统资源的正当利用。正当的异样解决可能使得程序在面对不可预知谬误时,可能优雅地复原或者给出明确的反馈,而不是简略地解体退出。文章开始前,咱们先看下思维导图相熟下有哪些异样 注释1、尽量不要捕捉 RuntimeException(Unchecked Exception)阿里巴巴Java开发手册)上这样规定: 尽量不要 catch RuntimeException,比方 NullPointerException、IndexOutOfBoundsException 等等,应该用预查看的形式来躲避。 正例if (obj != null) { //...} " + (a / b));}反例try { obj.method(); } catch (NullPointerException e) { //...}如果有些异样预查看不进去呢?比如说 NumberFormatException,尽管也属于 RuntimeException,但没方法预查看,所以还是应该用 catch 捕捉解决。2、 切勿在代码中应用异样来进行流程管制异样该当是在真正的异常情况下应用,而不是用来管制程序流程。public class Demo { public static void main(String[] args) { String input = "1,2,3,a,5"; String[] values = input.split(","); for (String value : values) { try { int num = Integer.parseInt(value); System.out.println(num); } catch (NumberFormatException e) { System.err.println(value + " is not a valid number"); } }}} ...

February 22, 2024 · 3 min · jiezi

关于java:从零开始学Spring-Boot系列前言

在数字化和信息化的时代,Java作为一种成熟、稳固且广泛应用的编程语言,曾经成为构建企业级利用的首选。而在Java生态系统中,Spring框架无疑是其中最为夺目的一颗明星。它提供了全面的编程和配置模型,用于构建企业级利用。随着Spring Boot的呈现,这一框架变得更加易于应用,使得开发者可能更疾速地构建、部署和治理生产级的Spring利用。 为什么抉择Spring Boot?简化配置:Spring Boot通过约定大于配置的理念,为开发者提供了大量的默认配置,从而缩小了繁琐的配置工作。它采纳了主动配置机制,能够自动检测和配置我的项目所需的组件和设置,大大降低了配置的难度和出错率。疾速搭建我的项目:Spring Boot提供了大量的起步依赖(Starters),这些预约义的依赖汇合蕴含了常见的库和框架,使得开发者可能疾速地增加所需的性能。通过简略的Maven或Gradle依赖治理,即可疾速地搭建起一个残缺的我的项目。内嵌服务器:Spring Boot内置了Tomcat、Jetty或Undertow等Web服务器,使得开发者无需额定部署Web服务器即可运行和测试利用。这大大简化了利用的部署流程,并且使得开发和测试更加便捷。生产就绪:Spring Boot提供了许多用于监控、治理和调优利用的工具,如健康检查、指标监控和性能剖析等。这些工具能够帮忙开发者更好地治理和保护生产环境中的利用。丰盛的插件生态:Spring Boot领有宏大的社区和丰盛的插件生态,提供了各种罕用的性能和扩大。无论是数据库拜访、音讯队列、缓存治理还是安全性等,都有相应的插件和库可供选择。易于集成:Spring Boot与其余Spring我的项目(如Spring Cloud、Spring Data等)的集成十分便捷。它提供了对立的编程模型和配置形式,使得开发者可能轻松地构建微服务架构和分布式系统。易于学习和应用:Spring Boot的文档丰盛、社区沉闷,并且提供了大量的教程和示例。这使得开发者可能更疾速地学习和把握Spring Boot的应用,升高了学习曲线。须要哪些基础知识?在学习Spring Boot之前,咱们须要确保曾经把握了一些必要的基础知识。这些基础知识包含: Java编程语言根底:相熟Java编程语言的外围概念,如变量、数据类型、条件语句、循环、异样解决、汇合、泛型等。同时,深刻了解Java的面向对象编程个性,如类、对象、继承、封装和多态。Java Web开发根底:理解Java Web开发的基本概念,如Servlet、JSP、HTTP协定、Web服务器等。这对于后续应用Spring Boot构建Web应用程序将十分有帮忙。Spring框架根底:相熟Spring框架的外围概念,如依赖注入(DI)、面向切面编程(AOP)、事务管理等。这将有助于你更好地了解Spring Boot的工作原理和扩展性。Maven或Gradle构建工具:把握Maven或Gradle的根本用法和配置,这对于治理Spring Boot我的项目的依赖、构建和打包应用程序是至关重要的。数据库根底:理解关系型数据库(如MySQL、Oracle)或非关系型数据库(如MongoDB、Redis)的基本概念和操作。这将有助于你在理论利用中解决数据库交互。Web前端根底:尽管不是必须的,但理解一些根本的Web前端技术,如HTML、CSS、JavaScript,将有助于你更好地实现前后端交互,晋升整体开发效率。当你把握了这些基础知识后,就能够更加自信地开始学习Spring Boot了。Spring Boot提供了丰盛的性能和灵便的配置选项,但只有咱们把握了其核心理念和用法,就可能轻松地构建出高效、稳固的企业级利用。 开发工具与开发环境介绍在开始Spring Boot的学习之旅前,咱们须要先筹备好适合的开发工具和开发环境。以下是一些举荐的组合: IDE(集成开发环境) IntelliJ IDEA:由JetBrains开发的弱小IDE,反对多种编程语言,包含Java。它提供了丰盛的插件生态,反对Spring Boot的一键式创立和部署,以及弱小的代码提醒和调试性能。Eclipse:Eclipse是一个风行的开源IDE,同样反对Java和Spring Boot开发。只管在Spring Boot的反对方面可能不如IntelliJ IDEA全面,但它依然是许多开发者的首选。构建工具 Maven:Maven是一个风行的Java我的项目构建和管理工具。它能够帮忙你治理我的项目的依赖关系,自动化构建过程,并提供了统一的构建输入。Spring Boot我的项目通常应用Maven作为构建工具。Gradle:Gradle是另一个风行的构建工具,与Maven相似,但具备更好的灵活性和性能。它同样实用于Spring Boot我的项目。数据库 MySQL:MySQL是一个宽泛应用的开源关系型数据库管理系统。Spring Boot提供了对MySQL的内置反对,因而它成为许多开发者的首选数据库。H2 Database:H2是一个轻量级的嵌入式数据库,罕用于开发和测试阶段。因为它不须要额定的配置和装置,因而非常适合在开发过程中应用。其余工具 Spring Initializr:Spring Initializr是一个Web利用,容许你疾速生成一个根本的Spring Boot我的项目构造。你只须要抉择所需的依赖和版本,它就会为你生成一个可运行的Maven或Gradle我的项目。Lombok:Lombok是一个Java库,它通过注解缩小了大量常见的样板代码,如getter、setter、equals、hashCode等。它能够使你的代码更加简洁和易读。如何开始?在开始编写Spring Boot代码之前,你须要确保你的开发环境曾经正确配置。这包含装置IDE、构建工具、数据库等。此外,相熟这些工具的根本用法也是十分重要的。 一旦你的开发环境准备就绪,你能够应用Spring Initializr生成一个根本的Spring Boot我的项目。而后,你能够开始摸索Spring Boot的外围个性,如主动配置、起步依赖、数据拜访等。 有多个网站能够学习Spring Boot,以下是其中一些举荐: Spring Boot官方网站:https://spring.io/projects/spring-boot。这个网站提供了SpringBoot的具体文档、指南和教程,是理解Spring Boot的最佳终点。Spring Boot中文社区:https://www.springboot.cn/ 。这个社区提供了大量的SpringBoot学习资源和教程,包含文章、视频和书籍等,适宜初学者和进阶学习者。慕课网:https://www.imooc.com/learn/topic/springboot.html 。慕课网提供了丰盛的Spring Boot在线课程,涵盖了从入门到精通的各个方面,适宜不同程度的学习者。网易云课堂:https://study.163.com/courses-search?keyword=springboot。网易云课堂也提供了多门 Spring Boot相干课程,包含实战我的项目和案例解析等,适宜实践型学习者。适宜读者这个系列文章适宜对Java和Spring框架有肯定理解的开发者。如果你是Spring Boot的老手,或者想要更深刻地理解Spring Boot,那么这个系列文章将是你现实的学习资源。 如何学习这个系列文章?我倡议读者依照文章的程序进行学习,逐渐把握Spring Boot的基础知识和外围个性。同时,我也激励读者在学习过程中多入手实际,通过理论的我的项目利用来坚固所学常识。 在这个信息爆炸的时代,常识的学习不再是难题,难的是如何无效地排汇和利用这些常识。心愿通过这个系列文章,可能帮忙读者更好地学习和利用Spring Boot,为构建更加高效、稳固的企业级利用打下松软的根底。 源文来自:https://daimajiangxin.cn

February 22, 2024 · 1 min · jiezi

关于java:趣谈虚拟线程用JDK21的虚拟线程大幅度提升程序性能

作者: John  前言 2023年9月19日,oracle 发表JDK21公布release版本,这是继JDK17之后的一个新的长期反对版本(LTS)。JDK 21 号称有数千项性能,稳定性和安全性的改良,明天我就来和大家简略说说不少Javaer翘首以盼的一项新技术:虚构线程。看看它到底是什么,以及它到底能给咱们带来什么扭转? 虚构线程是怎么回事,怎么来的?为什么会有它?想齐全理解这个问题,让咱们把时钟拨回30年前,随着个人电脑的技术倒退,咱们一起来理解下计算机技术的倒退,你就能分明为什么会有虚构线程技术了。 单过程时代 首先咱们回到了30年前,那是Dos的时代,单过程时代。下图就是你们相熟Dos零碎。 在Dos的时代,整个操作系统只能运行一个程序,如果你想让电脑一边打字,一边播放音乐,对不起不反对,一台电脑同时只能运行一个程序是不是很节约? 多过程,多线程时代 大家看到单过程的局限性,如果能把CPU充分利用起来,让多个过程一起工作,那效率就能大大提高。于是各位大神开始发力,致力让PC计算机反对多过程(当然Unix此时早就反对了)。最终2位大家相熟的选手怀才不遇,他们是:Linux 和Windows. 这时候一个操作系统终于能够同时运行多个过程了,得益于软件和硬件的飞速发展,咱们能够在电脑上一边打字,一边听音乐了。究其实质,操作系统让每个过程都应用一部分工夫片,让咱们认为所有的过程都在并发运行。 随后大家更进一步,开始了多线程的时代,多线程把一个过程内的资源分得更细,每个线程都独立运行,过程内的资源能够共享,效率更高,进步计算机系统CPU的利用率。置信各位小伙伴对它们十分相熟。高性能程序的机密: 人类如此致力地推动计算机倒退,从单过程到多过程再到多线程,目标就是取得更高的性能。更高的性能意味着能够实现更多的工作,然而你晓得高性能程序的机密是什么吗? 我感觉答案来自 “Numbers Everyone Should Know”(Jeff Dean) 请看下列一系列计算机的操作工夫: 没什么感觉?我把所有的数字乘以10亿让你有个直观的了解。 如果咱们的CPU用1秒执行了一条语句,而后开始期待一个从美国发往欧洲的数据包,它须要期待了4.8年数据包才到来。如果程序什么都不做,那么CPU就被节约了4.8年,那么一个高性能的程序会怎么做呢?高性能程序当然会在期待数据到来的4.8年里,让CPU都去干别的工作啊。高性能程序设计的实质,CPU太快,IO操作太慢,让CPU尽量地工作,而不是期待节约。 在过来的日子里,大家总结了2种高性能程序的计划,它们别离是1.asynchronous style这种计划在程序须要IO期待的时候,将流程切走,等IO操作实现后,再切回来持续操作,有很多高效而胜利的例子,比方nginx。然而它的问题是对开发人员极度不敌对。随着业务的一直简单,可怕的回调天堂就呈现了。 2.thread per request另一种计划就是大家罕用的线程模式,咱们用线程池来解决大量的申请,线程模式的益处,每个线程的解决是同步的,不存在简单的烧脑回调,对程序员敌对。然而它也有上面2个缺点: 1.线程的资源耗费,不能有限扩大。每个线程都耗费肯定资源,想开海量线程还做不到。2.线程间的切换代价太大,线程切换由操作系统染指实现的,代价很大。如果真的存在海量线程,操作系统治理起来也很艰难。 虚构线程解决方案 咱们曾经晓得目前开发高性能程序的计划和它们各自的毛病,asynchronous style 应用回调,性能高,然而对开发人员不敌对, thread per request 对开发敌对,同步编程,然而存在资源限度和切换老本。 如有一个计划能兼顾2者的长处,那不就能解决问题了? 对,虚构线程就是这样一个计划。虚构线程最大的长处就是 它放弃了同步开发模式,在产生IO的时候,又能被动切换走了CPU,获取十分高的性能。同时因为它应用的资源十分小,能够开上100万个虚构线程也齐全没问题,所以虚构线程在某些场景有远超一般线程的能力。 失常状况下一个函数运行的时候,咱们并不能将流程终止切走。运行的流程是依照右边的图进行的,而虚构线程能够按左边的工作形式运行。 举个例子,失常状况下咱们运行a() b() 2 个函数。后果是这样的。 咱们用上面的代码模仿虚构线程的工作流程。在上面的例子里,在函数a() 运行到第4行的时候,须要期待一个比拟耗时的IO操作,这时候咱们将流程切走,运行b()函数,等b()运行到第12行的当前,再切回第6行进行,这样就能够交替运行进步性能,也放弃了同步开发的模式,加重了开发者的心智累赘。最初咱们就能看到上面的运行后果,2个函数的输入内容是穿插在一起的,十分神奇。 牛刀小试 让我举个例子看看虚构线程的威力吧。在上面代码里,咱们筹备了1万个工作,每个工作内容都是休眠0.5秒,咱们别离用虚构线程,100个线程,200个线程,400个线程,800个线程来实现这1万个工作,让咱们看看差距吧。输入后果:工夫比照 从这个小小的例子里,咱们曾经能看出虚构线程的威力了,它的效率轻松超过一般的800个线程,能够说是威力不凡。 通过我的介绍,置信大家对虚构线程曾经有了初步的理解,当然虚构线程也不是万能的银弹,它特地适宜的场景是有海量IO申请的服务,如果是计算密集型的业务则不会有太多劣势。置信在当前的工作中,大家都会把它用在失当的中央,让程序的效率更高效,让开发工作更轻松。

February 22, 2024 · 1 min · jiezi

关于java:如何在java中使用-Excel-动态函数生成依赖列表

前言 在Excel 中,依赖列表或级联下拉列表示意两个或多个列表,其中一个列表的项依据另一个列表而变动。依赖列表通常用于Excel的业务报告,例如学术记分卡中的【班级-学生】列表、区域销售报告中的【区域-国家/地区】列表、人口仪表板中的【年份-区域】列表以及生产摘要报告中的【单位-行-产品】列表等等。 在本博客中,小编将为大家介绍如何借助葡萄城公司的Java API 组件GrapeCity Documents for Excel (以下简称GcExcel)和动静数组函数 UNIQUE、CHOOSECOLS 和 FILTER 以编程形式创立主列表和依赖下拉列表。 背景需要 下图是一张某公司的客户订单表原始数据: 当初为了将这些数据依照人名分类进行查阅,小编须要制作两个下拉列表(客户姓名和订单ID),同时须要满足订单ID的值是与客户姓名相干的,而后最上面显示的是依据订单ID查问进去的订单详细信息,如下图所示: 应用 GcExcel实现的步骤 步骤 1 - 工作簿初始化 应用 GcExcel API,第一步是初始化 Workbook 的实例。而后,能够依据业务需要抉择关上现有 Excel 文档或创立新工作簿。在此博客中,小编将应用带有 IWorkbook 接口的 API) 加载蕴含客户订单历史记录的现有 Excel 文档,如下所示: Workbook workbook = new Workbook();workbook.open("E:\\download\\smartdependentlist\\CustomerOrderHistory.xlsx");步骤 2 - 获取工作表 接下来,小编须要获取用于创立所需报告的工作表。应用 GcExcel,能够应用 IWorkbook 界面中的 API) 获取工作表。如下所示: IWorksheet worksheet;worksheet = workbook.getWorksheets().get(0);步骤 3 - 获取客户名称的惟一列表(用于主下拉列表) 初始化工作簿后,须要获取增加到报表中“抉择客户名称”局部的主下拉列表的惟一客户名称列表,并对所需的客户名称数据范畴应用 UNIQUE 函数。应用 GcExcel,能够应用带有 IWorksheet 接口的 API 获取单元格或单元格区域,并应用 IRange 接口的 API) 为其设置动静公式,如下所示: ...

February 22, 2024 · 1 min · jiezi

关于java:Java-安全-spring-security-源码分析

** 理解Java平安机制**Java平安机制是指Java编程语言中提供的一系列机制和技术,以确保Java应用程序在运行时的安全性。 类加载器(ClassLoader):Java应用类加载器加载类文件,并对类文件进行权限验证。类加载器能够限度来自不可信源(如网络)的类文件的加载,避免恶意代码的注入。平安沙箱(Security Manager):Java中的平安沙箱机制能够限度程序拜访底层系统资源的能力。通过平安管理器(SecurityManager)能够设置权限策略,限度程序对文件系统、网络、零碎属性等资源的拜访。安全策略文件(Policy File):Java中的安全策略文件能够定义对代码的权限限度。通过配置策略文件,能够限度程序的拜访权限,避免恶意代码的执行。平安权限模型(Permission Model):Java中的平安权限模型定义了一系列权限,用于控制程序对不同资源的拜访。通过授予或回绝权限,能够限度程序的行为,确保安全性。平安沙箱(Sandbox):Java应用程序能够在沙箱环境中运行,以限度对底层系统资源的拜访。在沙箱中运行的程序只能拜访沙箱提供的受限资源,无奈间接拜访系统资源,从而进步了安全性。平安通信(Secure Communication):Java提供了平安通信的API,能够应用平安的传输协定(如SSL/TLS)进行网络通信,确保数据的保密性和完整性。总之,Java平安机制通过类加载器、平安管理器、安全策略文件、平安权限模型、沙箱环境等技术手段,保障Java应用程序在运行时的安全性,避免恶意代码的执行和对系统资源的滥用。 学习如何应用Java的平安API应用Java的平安API能够帮忙咱们实现数据的加密、解密和数字签名等平安操作。上面是学习如何应用Java的平安API的一些倡议: 理解Java平安API的基本知识:Java提供了一套平安API,次要包含Java Cryptography Architecture(JCA)和Java Cryptography Extension(JCE)。JCA提供了根本的加密、解密和密钥治理性能,而JCE则提供了更高级的密码学性能。理解这些API的基本概念和应用办法是学习Java平安API的根底。学习对称加密和非对称加密算法:对称加密算法应用雷同的密钥进行加密和解密,而非对称加密算法应用公钥和私钥配对进行加密和解密。学习根本的对称加密算法如AES和DES,以及非对称加密算法如RSA和DSA,能够帮忙咱们了解Java平安API中的加密和解密操作。学习数字签名和证书操作:数字签名是一种用于验证数据完整性和起源的技术,它能够避免数据被篡改。学习如何应用Java平安API生成和验证数字签名,以及如何应用证书进行身份验证和密钥替换,能够减少咱们对Java平安API的利用能力。实际编写平安代码:通过实际编写应用Java平安API的代码,能够更好地了解和把握这些API的应用办法。能够尝试编写一些简略的加密解密程序、数字签名程序或者平安通信程序,从而晋升对Java平安API的熟练度。浏览相干文档和参考资料:Java提供了具体的文档和参考资料,包含官网文档、教程和示例代码等。浏览这些文档和材料能够帮忙咱们更全面地理解和学习Java平安API的应用。总之,学习如何应用Java的平安API须要把握基本概念、理解根本算法、进行实际编码,并浏览相干材料。通过一直学习和实际,能够进步咱们的Java平安编程能力。 把握常见的Java安全漏洞和防范措施Java是一种弱小而宽泛应用的编程语言,但它也存在一些常见的安全漏洞。以下是一些常见的Java安全漏洞以及相应的防范措施。 SQL注入(SQL Injection):这是一种常见的安全漏洞,攻击者通过结构歹意的SQL查问来拜访、批改或删除数据库中的数据。要避免SQL注入,能够应用参数化查问或预编译语句来过滤和本义输出。跨站脚本攻打(Cross-Site Scripting,XSS):这种攻击方式是通过在网页中注入歹意脚本来获取用户的敏感信息。为了避免XSS攻打,应该对用户的输出进行验证和本义,并应用内容安全策略(Content Security Policy)来限度脚本的执行。跨站申请伪造(Cross-Site Request Forgery,CSRF):CSRF攻打利用用户在登录状态下的身份验证信息,通过伪造申请来执行歹意操作。为了避免CSRF攻打,能够应用随机生成的令牌验证每个申请,并在敏感操作上应用双因素认证。XML内部实体注入(XML External Entity Injection,XXE):攻击者通过注入歹意的内部实体来读取本地文件或进行近程申请。为了避免XXE攻打,应该禁用内部实体解析或应用平安的XML解析器。不平安的反序列化(Insecure Deserialization):攻击者能够通过结构歹意序列化数据来执行任意代码。为了避免不平安的反序列化,能够应用白名单验证反序列化的对象,限度序列化和反序列化的权限。平安管理器绕过:Java的平安管理器能够限度代码的权限,但如果不正确地配置或实现,攻击者可能会绕过这一限度。要防止平安管理器的绕过,须要确保正确配置和测试安全策略文件。敏感数据泄露:在代码中硬编码敏感信息(如数据库明码、密钥等)可能导致泄露。为了避免敏感数据泄露,应该将敏感信息存储在平安的中央,如环境变量、密钥治理服务等。除了上述常见的安全漏洞和对策,还应该定期更新和保护依赖库、应用平安的加密算法、进行平安审计和代码审查等。同时,及时关注和理解最新的平安威逼和破绽,放弃对Java平安的敏感性和意识。 理解Spring Security框架的概述和性能Spring Security是一个用于爱护Java应用程序的开源框架,它提供了身份验证和受权性能。Spring Security能够集成到任何基于Spring的应用程序中,包含Spring MVC、Spring Boot等。 Spring Security的次要性能包含: 身份验证(Authentication):Spring Security提供了多种身份验证形式,包含基于表单的身份验证、基于LDAP的身份验证、基于记住我性能的身份验证等。它还反对自定义的身份验证形式。受权(Authorization):Spring Security能够通过基于角色、基于资源的受权形式来限度用户拜访应用程序的特定性能。它提供了受权注解和标签,能够不便地实现细粒度的受权管制。平安配置(Security Configuration):Spring Security提供了一套灵便的平安配置,能够通过Java配置或者XML配置来定义应用程序的安全策略。平安配置能够包含定义受爱护的URL、配置身份验证形式、配置记住我性能等。避免常见的安全漏洞:Spring Security还提供了多种爱护机制,能够避免常见的安全漏洞,如跨站脚本攻打(XSS)、跨站申请伪造(CSRF)、点击劫持(Clickjacking)等。总结来说,Spring Security是一个功能强大的平安框架,它能够帮忙开发人员实现身份验证和受权性能,爱护应用程序的安全性。它还提供了灵便的平安配置和避免常见安全漏洞的机制,不便开发人员构建安全可靠的应用程序。 学习如何应用Spring Security来爱护Web应用程序Spring Security是一个功能强大的框架,用于爱护Web应用程序的安全性。它提供了一系列的平安性能,包含身份认证、受权、明码加密和会话治理等。 以下是应用Spring Security来爱护Web应用程序的步骤: 增加Spring Security依赖:在我的项目的构建文件中增加Spring Security的依赖。如果应用Maven,能够在pom.xml文件中增加以下代码: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId></dependency>配置Spring Security:在应用程序的配置文件中配置Spring Security。能够创立一个名为SecurityConfig的类,并应用@Configuration和@EnableWebSecurity注解来标识它。 @Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasAnyRole("ADMIN", "USER") .anyRequest().authenticated() .and() .formLogin() .and() .logout() .logoutSuccessUrl("/") .and() .httpBasic(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("admin").password("{noop}admin123").roles("ADMIN") .and() .withUser("user").password("{noop}user123").roles("USER"); }}这个配置类继承自WebSecurityConfigurerAdapter,并重写了configure办法来配置HttpSecurity对象。在该办法中,咱们能够定义拜访规定和身份验证形式。 ...

February 21, 2024 · 1 min · jiezi

关于java:系统架构设计师第3章数据库

第2章-数据库在信息处理畛域,因为数据量宏大,如何无效组织、存储数据对实现高效率的信息处理至关重要。数据库技术是目前最无效的数据管理技术。数据库(DataBase,DB)是指长期存储在计算机内、有组织的、对立治理的相干数据的汇合。它不仅形容事物的数据自身,而且还包含相干事物之间的分割。数据库能够直观地了解为存放数据的仓库,只不过这个仓库是在计算机的存储设备上,而且数据是按肯定格局寄存的,具备较小的冗余度、较高的数据独立性和易扩展性,可为多个用户共享。 晚期数据库品种有3种,别离是档次式数据库、网络式数据库和关系型数据库。目前最常见的数据库品种是关系型数据库和非关系型数据库。依据数据库存储体系分类,还可分为关系 型数据库、键值(Key-Value)数据库、列存储数据库、文档数据库和搜索引擎数据库等类型。 关系型数据库。这种类型的数据库是最传统的数据库类型,关系型数据库模型是把简单的数据结构归结为简略的二元关系,在数据库中,对数据的操作简直全副建设在一个或多个关系表格上。在大型零碎中通常有多个表,且表之间有各种关系。理论应用就是通过对这些关联的表格进行分类、合并、连贯或选取等运算来实现数据库的治理。键值数据库。键值数据库是一种非关系型数据库,它应用简略的键值办法来存储数据。键值数据库将数据存储为键值对汇合,其中键作为惟一标识符。列存储数据库。列式存储(Column-Based)是绝对于传统关系型数据库的行式存储(Row-Basedstorage)来说的。简略来说两者的区别就是对表中数据的存储模式的差别。文档数据库。此类数据库可寄存并获取文档,能够是XML、JSON、BSON等格局,这些文档具备可述性(Self-Describing),出现分层的树状构造 (Hierarchical Tree Data Structure),能够蕴含映射表、汇合和纯量值。数据库中的文档彼此类似,但不用完全相同。文档数据库所寄存的文档,就相当于键值数据库所寄存的“值”。文档数据库可视为其值可查的键值数据库。搜索引擎数据库。搜索引擎数据库是利用在搜索引擎畛域的数据存储模式,因为搜索引擎会爬取大量的数据,并以特定的格局进行存储,这样在检索的时候能力保障性能最优。上面简要介绍罕用的关系数据库和分布式数据库。 关系数据库数据模型是数据特色的形象,它是对数据库组织形式的一种模型化示意,是数据库系统的外围与根底。它具备数据结构、数据操作和完整性约束条件三要素。关系能够了解为二维表。一个关系模型就是指用若干关系示意实体及其分割,用二维表的模式存储数据。例如,对某高校学生的选课(不同年级甚至同一年级学生所选课程能够不同) 进行治理,能够用二维表示意,如图2-4所示。用关系示意如下,其中带下画线的属性为主码,主码能惟一确定某个实体,如学号能惟一 确定某个学生。学生(学号,姓名,年龄,系别)课 程 (课程号,课程名,学分)选 课 (学 号,课程号,分数)关系数据库设计的特点及办法数据库设计是指对于一个给定的应用环境结构最优的数据库,建设数据库及其利用零碎,使之能无效地存储数据,满足各种用户的需要。数据库设计包含构造个性和行为个性的设计两 方面的内容。数据库设计的很多阶段都能够和软件工程的各阶段对应起来,数据库设计的特点有:从数据结构即数据模型开始,并以数据模型为外围开展,这是数据库设计的一个次要特点;动态结构设计与动静行为设计拆散;试探性;反复性和多步性。目前已有的数据库设计办法可分为4类,即直观设计法、标准设计法、计算机辅助设计法和自动化设计法。罕用的有基于3NF的设计办法、基于实体联(E-R)模型的数据库设计办法、基于视图概念的数据库设计办法、面向对象的关系数据库设计办法、计算机辅助数据库设计办法、麻利数据库设计办法等。关系数据库设计的根本步骤数据库设计分为需要剖析、概念结构设计、逻辑结构设计、物理结构设计、利用程序设计和运行保护6个阶段,如图2-5所示。需要分析阶段的工作是对事实世界要解决的对象(组织、部门和企业等)进行具体考察,在理解现行零碎的详情和确定新零碎性能的过程中,收集支持系统指标的根底数据及其解决方 法。需要剖析是在用户考察的根底上,通过剖析逐渐明确用户对系统的需要,包含数据需要和围绕这些数据的业务解决需要。数据库概念结构设计是在需要剖析的根底上,按照需要剖析中的信息需要,对用户信息加以分类、汇集和概括,建设信息模型,并按照选定的数据库治理系统软件,把它们转换为数据的逻辑构造,再按照软硬件环境,最终实现数据的正当存储。这一过程也称为数据建模。设计数据库概念模型的最驰名、最罕用的办法是E-R办法。采纳E-R办法的数据库概念结构设计可分为三步:设计部分E-R模型、设计全局E-R模型以及全局E-R模型的优化。逻辑结构设计是在概念结构设计根底上进行的数据模型设计,能够是档次、网状模型和关系模型。逻辑构造设计阶段的次要工作是确定数据模型,将E-R图转换为指定的数据模型,确定完整性束缚,确定用户视图。数据库在物理设施上的存储构造与存取方法称为数据库的物理构造。数据库的物理结构设计是对已确定的数据库逻辑构造,利用DBMS所提供的办法、技术,以较优的存储构造和数据 存取门路、正当的数据寄存地位以及存储调配,设计出一个高效的、可实现的数据库物理构造。数据库利用零碎开发是DBMS的二次开发,一方面是对用户信息的存储;另一方面就是对用户解决要求的实现。数据库利用程序设计要做的工作有抉择设计办法、制订开发计划、抉择零碎架构和设计安全性策略。在利用程序设计阶段,设计办法有结构化设计办法和面向对象设计办法两种。安全性策略次要是指硬件平台、操作系统、数据库系统、网络及利用零碎的平安。数据库的失常运行和优化也是数据库设计的内容之一 。在数据库运行维护阶段要做的工作次要有数据库的转储和复原,数据库的安全性和完整性管制,数据库性能的监督、剖析和革新,数据库的重组和重构等。分布式数据库分布式数据库系统(Distributed DataBase System,DDBS) 是针对天文上扩散,而治理上又须要不同水平集中管理的需要而提出的一种数据管理信息系统。满足散布性、逻辑相关性、地透明性和场地自治性的数据库系统被称为齐全分布式数据库系统。分布式数据库系统的特点是数据的集中控制性、数据独立性、数据冗余可控性、场地自治性和存取的有效性。分布式数据库体系结构我国在多年钻研与开发分布式数据库及制订《分布式数据库系统规范》中,提出了把分布式数据库形象为4层的构造模式,如图2-6所示。这种构造模式失去了国内外肯定水平的反对和认同。4层模式划分为全局外层、全局概念层、部分概念层和部分内层,在各层间还有相应的层 间映射。这种4层模式实用于同构型分布式数据库系统,也实用于异构型分布式数据库系统。分布式数据库的利用分布式数据库的应用领域有分布式计算、Internet利用、数据仓库、数据复制以及寰球联网查问等,Sybase公司的Replication Server即是一种典型的分布式数据库系统。罕用数据库管理系统计算机科学技术一直倒退,数据库管理系统也一直倒退进化,MySQLAB公司(2009年被Oracle公司收买)MySQL、Microsoft公司的Access等是小型关系数据库管理系统的代表,Oracle公司的Oracle、Microsoft公司的SQL Server、IBM公司的DB2等是功能强大的大型关系数据库管理系统的代表。OracleOracle 是一种实用于大型、中型和微型计算机的关系数据库管理系统。Oracle的构造包含数据库的内部结构、外存储构造、内存储构造和过程构造。在Oracle中,数据库不仅指物理上的数据,还包含解决这些数据的程序,即DBMS自身。Oracle应用PL/SQL(ProceduralLanguage/SQL)语言执行各种操作。Oracle除了以关系格局存储数据外,Oracle8以上的版本还反对面向对象的构造(如抽象数据类型)。Oracle产品次要包含数据库服务器、开发工具和连贯产品三类。Oracle还提供了一系列的工具产品,如逻辑备份工具Export、Import等。IBM DB2DB2是IBM的一种分布式数据库解决方案。简略地说,DB2就是IBM开发的一种大型关系型数据库平台,它反对多用户或应用程序在同一条SQL语句中查问不同Database甚至不同DBMS中的数据。DB2外围数据库的特色有反对面向对象编程,反对多媒体应用程序,反对备份和复原性能,反对存储过程和触发器,反对SQL查问,反对异构分布式数据库拜访,反对数据复制。DB2采纳多过程多线索体系结构,可运行于多种操作系统之上。IBM还提供了Visualizer、Visualage、Visualgen等开发工具。SybaseSybase是美国SYBASE公司在20世纪80年代中期推出的客户机/服务器(Client/Server,C/S)构造的关系数据库系统,也是世界上第一个真正的基于客户机/服务器构造的RDBMS产品。Sybase数据库次要由三局部组成:进行数据库治理和保护的联机关系数据库管理系统Sybase SQLServer,反对数据库利用零碎建设与开发的一组前端工具Sybase SQLToolset,可把异构环境下其余厂商的应用软件和任何类型的数据连贯在一起的接口Sybase OpenClient/OpenServer。Sybase提供了Sybase Adaptive Server Enterprise高性能企业智能型关系数据库管理系统、EAServer电子商务解决方案应用服务器、系统分析设计工具PowerDesigner和利用开发工具PowerBuilder。Microsoft SQL Server Microsoft SQL Server是一种典型的关系型数据库管理系统,可运行于多个操作系统上,它应用Transact-SQL 语言实现数据操作。源文来自:https://daimajiangxin.cn

February 21, 2024 · 1 min · jiezi

关于java:阿里面试Java开发中应如何避免OOM

Java内存治理:防止OOM的10个实用小技巧引言在Java开发中,OutOfMemoryError(OOM)谬误始终是令开发者头疼的问题,也是Java面试中呈现外围频率很高的问题。那么咱们到底怎么样才可能无效正确的治理内存,日常开发中到底要留神哪些外围技巧来防止OOM谬误。本文将带大家一起学习10个防止OOM的实用小技巧,让大家在工作中可能对症下药,防止OOM谬误的飞来横祸。 注释1、 合理配置JVM内存参数利用上线前,设置正当的JVM启动参数是防止OOM的第一步。通过调整堆内存、栈内存和Metaspace的大小,能够无效地治理内存资源。以4G内存为例,利用上线时能够参考如下配置: // 示例:设置JVM的启动参数// -Xms1024m 设置初始堆大小为1024MB// -Xmx2048m 设置最大堆大小为2048MB// -XX:NewSize=512m 设置新生代大小为512MB// -XX:MaxNewSize=1024m 设置新生代最大大小为1024MB// -XX:MetaspaceSize=256m 设置Metaspace的初始空间大小为256MB// -XX:MaxMetaspaceSize=512m 设置Metaspace的最大空间大小为512MB2、 应用轻量级对象在开发过程中,尽可能的应用轻量级对象,缩小内存耗费。例如,应用原始数据类型代替包装类,应用StringBuffer/StringBuilder代替String进行字符串操作。 // 应用原始数据类型代替包装类int i = 10;// 应用StringBuilder进行字符串拼接StringBuilder sb = new StringBuilder();sb.append("Hello");sb.append(" ");sb.append("World");String result = sb.toString();`3、 对象池技术对于频繁创立和销毁的对象,能够思考应用对象池技术,以缩小GC的压力。 // 应用Commons Pool2实现对象池// 定义一个简略的对象池工厂public class MyObjectPoolFactory extends BasePooledObjectFactory<MyObject> { @Override public MyObject create() throws Exception { return new MyObject(); } @Override public PooledObject<MyObject> wrap(MyObject obj) { return new DefaultPooledObject<>(obj); }}// 应用对象池ObjectPool<MyObject> pool = new GenericObjectPool<>(new MyObjectPoolFactory());MyObject obj = null;try { obj = pool.borrowObject(); // 应用对象...} finally { pool.returnObject(obj);} ```**4、** **优化数据结构抉择**依据利用场景正当抉择数据结构,例如,在频繁读取操作中应用ArrayList,在频繁插入删除操作中应用LinkedList。 ```java // 在频繁读取操作中应用ArrayListList<String> arrayList = new ArrayList<>();arrayList.add("Java");arrayList.add("Python");String element = arrayList.get(0);// 在频繁插入删除操作中应用LinkedListList<String> linkedList = new LinkedList<>();linkedList.add("Java");linkedList.add("Python");linkedList.remove(0);5、 防止创立不必要的对象尽量复用已有对象,防止无谓的对象创立,特地是在循环或频繁调用的办法中。 ...

February 21, 2024 · 1 min · jiezi

关于java:一张图搞懂微服务架构设计

前言以后,微服务架构在很多公司都曾经落地施行了,上面用一张图简要概述下微服务架构设计中罕用组件。不能说曾经应用微服务好几年了,后果对微服务架构没有一个整体的认知,一个只懂搬砖的程序员不是一个好码农。 流量入口Nginx在上图中能够看到,Nginx作为整个架构的流量入口,能够了解为一个内部的网关,它承当着申请的路由转发、负载平衡、动静拆散等性能。作为一个外围入口点,Nginx必定要采纳多节点部署,同时通过keepalived来实现高可用,从而保障整个平台的高可用。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice网关网关是在Nginx后的另外一个外围组件。它承当着申请鉴权,路由转发,协定转换,流量监控等一系列性能,上图中网关是采纳spring Cloud Gateway来实现业务网关的性能,在网关选型中,咱们还有其余的抉择,比方Zuul1,Zuul2,Kong等等,这些计划都有本人的劣势和局限性,咱们能够依据本人他们的特点来抉择到底选用哪一个计划。对于网关的深刻理解,能够参见之前的系列文章网关那点事,这里不做赘述。 上图中,Spring Cloud Gateway上面有jwt和OAuth2,其实这两个就是基于token的认证鉴权,个别互联网我的项目中,在登录模块都是反对微信或者qq登录,这就是用到OAuth2的受权登录。想深刻理解Oauth2相干细节,能够参考之前的Oauth2.0客户端服务端示例等系列文章。 业务组件从下面的架构图中能够看到,网关之后就是咱们的业务组件了,能够了解就是拆分之后的微服务了,比方电商平台常见的账号服务、订单服务、发票服务、收银台服务等等。服务组件之间通过Feign来进行http调用,Feign集成Ribbon来实现客户端侧负载平衡。具体的服务畛域划分,服务限界上下文的设定,这就另外的常识了,如果想做好服务划分,DDD畛域驱动设计这块能够深刻理解下。 服务注册核心不论是基于Dubbo实现的SOA,还是基于Spring Cloud拆分的微服务架构,服务注册核心都是必须的,咱们把所有的服务组件都注册到注册核心,进而实现服务的动静调用。常见能实现注册核心性能的有Zookeeper,Eureka,Nacos,Zookeeper在Dubbo中应用比拟多,目前公司服务微服务架构是基于Eureka的,Eureka如同目前不保护了。个别新的平台倡议间接集成Nacos,Nacos除了能做注册核心来应用,也能够作为分布式配置核心来应用,比Sping Cloud Config更好使。 缓存和分布式锁在图中左下角,咱们能够看到Redis组件,咱们能够把Redis作为缓存来应用,把一些查问慢,使用率高的热点数据做缓存解决,能疾速进步接口响应工夫。同时redis在微服务中的一大应用场景就是分布式锁,传统的Sychronized和显示Lock锁显然是不能解决分布式并发问题。 为了保障Redis的高可用,能够采纳哨兵部署,不是三个redis节点,一主二从,同时部署三个哨兵节点,来实现故障转移,防止单点问题,如果Redis存储的数据量很大,达到了单节点的Redis的性能瓶颈,咱们也能够用Redis集群模式来实现分布式存储。 数据长久层不论单体服务,还是微服务,数据长久层都是必须的,咱们是选用互联网我的项目常常应用的mysql作为DB,为了保障服务读写效率以及高可用性,咱们主从拆散模式,同时实现读写拆散,来保障mysql的读写性能。 随着业务量增长,单表的数据量达到性能瓶颈之后,咱们就要采纳分库分表来对数据库表进行程度拆分和垂直拆分了,具体如何进行正当的拆分,以及技术选型,这些和我的项目现有的表结构设计是非亲非故的,要思考后续的可拓展性,不能短期拆了一时爽,后续业务量增暴涨之后,服务器的性能不足以维持数据库的性能时,这时候要拆分服务器部署了。当然,个别企业的数据量级达不到那样的量级。 结构型数据存储mysql比拟善于存储关系型数据,我的项目中有须要存储结构性数据的场景,比方存储JSON字符串,这种场景通过mysql来存储显然事不适合的。个别咱们会采纳Elasticsearch或者MangoDB来进行存储,如果业务中须要检索性能,更倡议应用Elasticsearch。Elasticsearch反对DSL,有比拟丰盛查问检索性能,甚至能实现GIS空间检索性能。 消息中间件后面说到,微服务架构中,服务之间同步调用是通过Feign来实现的,那服务间的异步解耦就要通过MQ来实现了。尽管咱们能够通过多线程来实现异步调用,然而这种异步调用不反对长久化,可能会造成音讯失落,所以个别都集成RabbitMq或者RocketMq。 日志收集在微服务架构中,通过一个组件,比如说订单服务都是多节点分布式部署,每个节点的log日志都是存储在节点本地,如果要查问日志,咱们难道要登录到各个节点找到对应的日志信息?这种查看日志必定是不行的。所以个别会引入ELK来做日志收集,和可视化展现查问。 Logstash 用来做日志收集工作,通常在Logstash前会加一个Filebeat,由Filebeat来收集日志,Logstash做数据转换工作。Elasticsearch做数据存储,以及生成索引数据,便于Kibana做检索。Kibana做数据的展现,以及查问检索性能,咱们通过检索关键词就能疾速的查问到想要日志信息。任务调度核心我的项目中常常会用到定时性能,单体利用中,咱们应用sping自带的Schedule,或者应用Quartz即可,在分布式应用中,咱们就要集成分布式定时器,比方Quartz(Quartz配合数据库表也是反对分布式定时工作的),还有Elastic-Job、XXL-JOB等等。 Elastic-job 当当网基于quartz 二次开发的弹性分布式任务调度零碎,功能丰富弱小,采纳zookeeper实现分布式协调,实现工作高可用以及分片。Elastic-Job是一个散布式调度的解决方案,由当当网开源,它由两个互相独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成,应用Elastic-Job能够疾速实现分布式任务调度。 XXL-JOB 是一个分布式任务调度平台(XXL是作者徐雪里姓名拼音的首字母),其外围设计指标是开发迅速、学习简略、轻量级、易扩大。将调度行为形象造成“调度核心”公共平台,而平台本身并不承当业务逻辑,“调度核心”负责发动调度申请。将工作形象成扩散的JobHandler,交由“执行器”对立治理,“执行器”负责接管调度申请并执行对应的JobHandler中业务逻辑。因而,“调度”和“工作”两局部能够互相解耦,进步零碎整体稳定性和扩展性。 分布式对象存储我的项目中常常会有文件上传性能,比方图片,音频视频。在分布式架构中,咱们将文件存储在节点服务器上显然是不行的,这时候,咱们就须要引入分布式文件存储。常见计划有MinIo、阿里的OSS(免费),阿里FastDFS等等。 MinIO 是一款基于Go语言发开的高性能、分布式的对象存储系统。客户端反对Java、Net、Python、Javacript、Golang语言。 FastDFS是一个开源的轻量级分布式文件系统,它对文件进行治理,性能包含:文件存储、文件同步、文件拜访(文件上传、文件下载)等,解决了大容量存储和的问题。特地适宜以文件为载体的在线服务,如相册网站、视频网站等等。 起源:blog.csdn.net/qq_28165595/article/details/128169770 更多文章举荐: 1.Spring Boot 3.x 教程,太全了! 2.2,000+ 道 Java面试题及答案整顿(2024最新版) 3.收费获取 IDEA 激活码的 7 种形式(2024最新版) 感觉不错,别忘了顺手点赞+转发哦!

February 21, 2024 · 1 min · jiezi

关于java:盘点-Udemy-上最受欢迎的免费编程课程

之前给大家举荐过一些油管上的收费学习资源,如果您还没有看过的话能够点击这里返回。 明天再给大家举荐一批Udemy上超高品质并且收费的编程课程,有须要的小伙伴能够学起来了。 1. JavaScript Essentials 第一门收费课程是:JavaScript Essentials。顾名思义,本课程旨在帮忙您把握 JavaScript 的基础知识。该课程涵盖根本的 API 并以一个迷你我的项目完结。这是一个相当小的课程,您仅须要破费6小时30分钟就能够学习实现。 通过这个教程您将学习的内容包含:编程基础知识、语言基础知识及其要害概念,以及JavaScript外围性能。当然,该课程也有一些进阶内容。所以,如果您有肯定根底,但感觉根底不够扎实,那也是十分值得一看。 该课程由 Lorenz Tuton 授课,他在 Web 开发、图形设计方面经验丰富,善于 HTML 和 CSS。 从他在 Udemy 上传授的 7 门课程来看。 截至目前,有近 40 万注册人数和超过 3 万个评分, 学生给这门课程打分 4.5 星(满分 5 星),属于同类最优质的收费教程了。 传送门:https://www.udemy.com/course/javascript-essentials/ 2. React JS For Beginners 这是在 React Js 分类中排名第二的,适宜初学者的 React课程。本课程非常适合想要深刻理解 React 的初学者,它将带你摸索 React 是什么,并理解组件,函数式类型和基于类的类型等知识点。除此之外,您还将深入研究 React 中的状态治理等高级内容。 这个课程也是十分迷你,只须要大概2小时的工夫即可实现学习。如果您曾经有JavaScript根底,正筹备上手 React Js,那么该课程非常适合你。 本课程由 Ashutosh Pawar 传授。 他在 Udemy 上有他的 17 门课程。目前,React.js 初学者收费课程已有超过 27,000 名注册者,评分超过 1K。本课程的总分是 4.6 分(满分 5 分)。 ...

February 21, 2024 · 1 min · jiezi

关于java:SpEL应用实战

一、背景资金平台概述为了监控团体各业务线的资金来源和去向,资金部需每天剖析所有账户出金和入金状况。为此,咱们提供了资金治理平台,该平台领有账户收支流水和账单拉取等性能,以及现金流打标能力,为资金部提供更加精准的现金流剖析。 需要场景资金治理平台作为发起方,以账户维度申请领取零碎下载渠道账单(不同渠道传参不同),解析流水落库后做现金流打标。 零碎交互简图 抛出问题上述需要中资金平台申请领取零碎下载账单性能这一点,思考到不同渠道的账户,申请传参不同,该场景如何做功能设计? 实现计划计划 1(简写):无脑堆 if else 毛病:每新增一个渠道,都要在原有代码根底上增加参数解决逻辑,导致代码臃肿,难以保护,难以支持系统的继续演进和扩大。违反开闭准则,批改会对原有性能产生影响,减少了引入谬误的危险。 /** * 资金零碎申请领取零碎下载渠道账单 * * @param instCode 渠道名 * @param instAccountNo 账户 * @return 同步后果 */public String applyFileBill(String instCode, String instAccountNo) { // 不同渠道入参组装 FileBillReqDTO channelReq = new FileBillReqDTO(); if ("支付宝".equals(instCode)) { channelReq.setBusinessCode("ALIPAY_" + instAccountNo + "_BUSINESS"); channelReq.setPayTool(4); channelReq.setTransType(50); } else if ("微信".equals(instCode)) { channelReq.setBusinessCode("WX_" + instAccountNo); channelReq.setPayTool(3); channelReq.setTransType(13); } else if ("通联".equals(instCode)) { channelReq.setBusinessCode("TL_" + instAccountNo); channelReq.setPayTool(5); channelReq.setTransType(13); } // ... 能够持续增加其余渠道的解决逻辑 // 申请领取零碎拉取账单文件,同步返回解决中,异步MQ告诉下载后果 BaseResult<FileBillResDTO> result = cnRegionDataFetcher.applyFileBill(channelReq, "资金账单下载"); return "解决中";}计划 2:策略模式优化 ...

February 21, 2024 · 3 min · jiezi

关于java:美团面试Kafka如何处理百万级消息队列

美团面试:Kafka如何解决百万级音讯队列?在明天的大数据时代,解决海量数据已成为各行各业的标配。特地是在音讯队列畛域,Apache Kafka 作为一个分布式流解决平台,因其高吞吐量、可扩展性、容错性以及低提早的个性而广受欢迎。但当面对真正的百万级甚至更高量级的音讯解决时,如何无效地利用 Kafka,确保数据的疾速、精确传输,成为了许多开发者和架构师思考的问题。本文将深入探讨 Kafka 的高级利用,通过10个实用技巧,帮忙你把握解决百万级音讯队列的艺术。 引言在一个秒杀零碎中,刹时的流量可能达到百万级别,这对数据处理系统提出了极高的要求。Kafka 作为音讯队列的佼佼者,可能胜任这一挑战,但如何施展其最大效力,是咱们须要深入探讨的。本文不仅将分享实用的技巧,还会提供具体的代码示例,帮忙你深刻了解和利用 Kafka 来解决大规模音讯队列。 注释1、利用 Kafka 分区机制进步吞吐量Kafka 通过分区机制来进步并行度,每个分区能够被一个消费者组中的一个消费者独立生产。正当布局分区数量,是进步 Kafka 解决能力的要害。 Properties props = new Properties();props.put("bootstrap.servers", "kafka-broker1:9092,kafka-broker2:9092");props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");Producer<String, String> producer = new KafkaProducer<>(props);// 发送音讯for(int i = 0; i < 1000000; i++) { producer.send(new ProducerRecord<String, String>("my-topic", Integer.toString(i), "message-" + i)); // my-topic:指标主题 // Integer.toString(i):音讯的键(key),这里用作分区根据 // "message-" + i:音讯的值(value)}producer.close();` 2、合理配置消费者组以实现负载平衡在 Kafka 中,消费者组能够实现音讯的负载平衡。一个消费者组中的所有消费者独特生产多个分区的音讯,但每个分区只能由一个消费者生产。 Properties props = new Properties();props.put("bootstrap.servers", "kafka-broker1:9092,kafka-broker2:9092");props.put("group.id", "my-consumer-group");props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);consumer.subscribe(Arrays.asList("my-topic"));// 订阅主题while (true) { ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100)); for (ConsumerRecord<String, String> record : records) { System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value()); // 解决音讯 }}3、应用 Kafka Streams 进行实时数据处理Kafka Streams 是一个客户端库,用于构建实时应用程序和微服务,其中输出和输入数据都存储在 Kafka 中。你能够应用 Kafka Streams 来解决数据流。 ...

February 20, 2024 · 2 min · jiezi

关于java:Java-21-虚拟线程如何限流控制吞吐量

虚构线程(Virtual Threads)是 Java 21 所有新个性中最为吸引人的内容,它能够大大来简化和加强Java利用的并发性。然而,随着这些变动而来的是如何最好地治理此吞吐量的问题。本文,就让咱们看一下开发人员在应用虚构线程时,应该如何治理吞吐量。 在大多数状况下,开发人员不须要本人创立虚构线程。例如,对于 Web 应用程序,Tomcat 或 Jetty 等底层框架将为每个传入申请主动生成一个虚构线程。 如果在应用程序外部须要自行调用来提供业务并发能力时,咱们能够应用Java 21新个性:虚构线程(Virtual Threads)中介绍的办法去创立和应用,比方较为罕用的就是Executors.newVirtualThreadPerTaskExecutor()。 Runnable runnable = () -> { System.out.println("Hello, www.didispace.com");};try (ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor()) { for (int i = 0; i < 100; i++) { executorService.submit(runnable); }}咱们能够像下面开启100个虚构线程来执行工作。那么问题来了,咱们要如何对虚构线程限流管制吞吐量呢? 虚构线程的限流对于虚构线程并发管制的答案是:信号量!划重点:不要池化虚构线程,因为它们不是稀缺资源。所以,对于虚构线程并发管制的最佳计划是应用java.util.concurrent.Semaphore。 上面的代码示例演示了如何实现java.util.concurrent.Semaphore来管制虚构线程的并发数量: public class SemaphoreExample { // 定义限流并发的信号量,这里设置为:10 private static final Semaphore POOL = new Semaphore(10); public void callOldService(...) { try{ POOL.acquire(); // 尝试通过信号量获取执行许可 } catch(InterruptedException e){ // 执行许可获取失败的异样解决 } try { // 获取到执行许可,这里是应用虚构线程执行工作的逻辑 } finally { // 开释信号量 POOL.release(); } }}是不是很简略呢?明天的分享就到这里,心愿对你有所帮忙,更多对于Java新个性的学习能够关注我的收费专栏Java新个性。 ...

February 20, 2024 · 1 min · jiezi

关于java:面试官如何实现多级缓存

对于高并发零碎来说,有三个重要的机制来保障其高效运行,它们别离是:缓存、限流和熔断。而缓存是排在最后面也是高并发零碎之所以高效运行的要害伎俩,那么问题来了:缓存只应用 Redis 就够了吗? 1.冗余设计理念当然不是,不要把所有鸡蛋放到一个篮子里,成熟的零碎在要害性能实现时肯定会思考冗余设计,留神这里的冗余设计不是贬义词。 冗余设计是在零碎或设施实现工作起关键作用的中央,减少一套以上实现雷同性能的性能通道(or 零碎)、工作元件或部件,以保障当该局部呈现故障时,零碎或设施仍能失常工作,以缩小零碎或者设施的故障概率,进步系统可靠性。例如,飞机的设计,飞机失常运行只须要两个发动机,但在每台飞机的设计中可能至多会设计四个发动机,这就有冗余设计的典型应用场景,这样设计的目标是为了保障极其状况下,如果有一个或两个发动机呈现故障,不会因为某个发动机的故障而引起重大的安全事故。 2.多级缓存概述缓存性能的设计也是一样,咱们在高并发零碎中通常会应用多级缓存来保障其高效运行,其中的多级缓存就蕴含以下这些: 浏览器缓存:它的实现次要依附 HTTP 协定中的缓存机制,当浏览器第一次申请一个资源时,服务器会将该资源的相干缓存规定(如 Cache-Control、Expires 等)一起返回给客户端,浏览器会依据这些规定来判断是否须要缓存该资源以及该资源的有效期。Nginx 缓存:在 Nginx 中配置中开启缓存性能。分布式缓存:所有零碎调用的中间件都是分布式缓存,如 Redis、MemCached 等。本地缓存:JVM 层面,单零碎运行期间在内存中产生的缓存,例如 Caffeine、Google Guava 等。以下是它们的具体应用。 2.1 开启浏览器缓存在 Java Web利用中,实现浏览器缓存能够应用 HttpServletResponse 对象来设置与缓存相干的响应头,以开启浏览器的缓存性能,它的具体实现分为以下几步。 ① 配置 Cache-ControlCache-Control 是 HTTP/1.1 中用于管制缓存策略的次要形式。它能够设置多个指令,如 max-age(定义资源的最大存活工夫,单位秒)、no-cache(要求从新验证)、public(批示能够被任何缓存区缓存)、private(只能被单个用户公有缓存存储)等,设置如下: response.setHeader("Cache-Control", "max-age=3600, public"); // 缓存一小时② 配置 Expires设置一个相对的过期工夫,超过这个工夫点后浏览器将不再应用缓存的内容而向服务器申请新的资源,设置如下: response.setDateHeader("Expires", System.currentTimeMillis() + 3600 * 1000); // 缓存一小时③ 配置 ETagETag(实体标签)一种验证机制,它为每个版本的资源生成一个惟一标识符。当客户端发动申请时,会携带上先前接管到的 ETag,服务器依据 ETag 判断资源是否已更新,若未更新则返回 304 Not Modified 状态码,告诉浏览器持续应用本地缓存,设置如下: String etag = generateETagForContent(); // 依据内容生成ETagresponse.setHeader("ETag", etag);④ 配置 Last-Modified指定资源最初批改的工夫戳,浏览器下次申请时会带上 If-Modified-Since 头,服务器比照工夫戳决定是否返回新内容或发送 304 状态码,设置如下: ...

February 20, 2024 · 3 min · jiezi

关于java:多年以后PageHelper-又深深给我上了一课

多年不必PageHelper了,最近新入职的公司,采纳了此工具集成的框架,作为一个独立紧急我的项目开发的根底。我的项目开发起来,还是手到擒来的,然而没想到,最终测试的时候,深深的给我上了一课。 我的我的项目产生了哪些奇葩景象? 所有的问题都要从我承受的我的项目开始说起, 在开发这个我的项目的过程中,产生了各种奇葩的事件, 上面我简略说给你们听听: 账号反复注册?你必定在想这是什么意思? 就是字面意思,曾经注册的账号,能够再次注册胜利!!! else if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(username))||"匿名用户".equals(username)){ // 注册用户已存在 msg = "注册用户'" + username + "'失败";}如上所示: checkUserNameUnique(username)用来验证数据库是否存在用户名: <select id="checkUserNameUnique" parameterType="String" resultType="int"> select count(1) from sys_user where user_name = #{userName} limit 1</select>失常来说,是不会有问题的,那么起因咱们前面讲,接着看下一个问题。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice查问全副分类的下拉列表只能查出5条数据? 如上所示,明明有十多个后果,怎么只能返回5个?我也没有增加分页参数啊? 置信用过PageHelper的同学曾经晓得问题出在哪里了。 批改用户明码报错?当管理员在后盾界面重置用户的明码的时候,竟然报错了? 报错信息清晰的通知了我:sql语句异样,update语句不意识 “Limit 5” 到此为止,报错信息曾经通知了我,我的sql被拼接了该死的“limit”分页参数。 小结下面提到的几个只是冰山一角,在我应用的过程中,还有各种波及到sql的中央,会因为这个分页参数导致的问题,我能够分为两种: 1)间接导致报错的:明确报错起因的 比方insert、update语句等,不反对limit,会间接报错。 2)导致业务逻辑谬误,然而代码没有谬误提醒 如我下面提到的用户能够反复注册,却没有报错,理论在代码当中是有报错的,然而以后办法对异样进行了throw,最终被全局异样捕捉了。 不分页的sql被拼接了limit,导致没有报错,然而数据返回量谬误。 异样不是每次呈现,是有肯定纪律的,然而触发几率较高,起因在前面会逐步脱出。PageHelper是怎么做到下面的问题的?PageHelper应用我这里只解说我的项目基于的框架的应用形式。 代码如下: @GetMapping("/cms/cmsEssayList")public TableDataInfo cmsEssayList(CmsBlog cmsBlog) { //状态为公布 cmsBlog.setStatus("1"); startPage(); List<CmsBlog> list = cmsBlogService.selectCmsBlogList(cmsBlog); return getDataTable(list);}应用起来还是很简略的,通过 startPage()指定分页参数,通过getDataTable(list)对后果数据封装成分页的格局。 有些同学会问,这也没没传分页参数啊,并且实体类当中也没有,这就是比拟有意思的点,下一小结就来聊聊源码。 startPage()干啥了?protected void startPage(){ // 通过request去获取前端传递的分页参数,不需控制器要显示接管 PageDomain pageDomain = TableSupport.buildPageRequest(); Integer pageNum = pageDomain.getPageNum(); Integer pageSize = pageDomain.getPageSize(); if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) { String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()); Boolean reasonable = pageDomain.getReasonable(); // 真正应用pageHelper进行分页的地位 PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable); }}PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable)的参数别离是: ...

February 20, 2024 · 3 min · jiezi

关于java:Java调用FFmpeg将视频和音频合并成新视频的示例

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;public class FFmpegUtil { /** * 合并视频和音频 * @param videoPath 视频文件门路 * @param audioPath 音频文件门路 * @param outputPath 合并后的视频文件输入门路 * @throws IOException */ public static void mergeVideoAndAudio(String videoPath, String audioPath, String outputPath) throws IOException { // ffmpeg命令 List<String> command = new ArrayList<>(); command.add("ffmpeg"); command.add("-i"); command.add(videoPath); command.add("-i"); command.add(audioPath); command.add("-filter_complex"); command.add("[0:a]volume=0.5,apad[A];[1:a]volume=0.5[B];[A][B]amix=inputs=2:duration=first:dropout_transition=2"); command.add("-c:v"); command.add("copy"); command.add("-c:a"); command.add("aac"); command.add("-strict"); command.add("experimental"); command.add("-b:a"); command.add("192k"); command.add(outputPath); ProcessBuilder builder = new ProcessBuilder(); builder.command(command); builder.redirectErrorStream(true); Process process = builder.start(); // 读取命令执行后果 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } // 敞开输出流 reader.close(); // 期待命令执行实现 try { process.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } }}这里应用ProcessBuilder来调用FFmpeg命令,合并视频和音频的命令与之前的命令类似,只是在音频合并的局部减少了音量减半的参数。在命令执行实现后,将命令输入打印到控制台。您能够依据须要批改命令,例如调整音频音量、音频码率等参数。调用该办法能够通过以下代码实现: ...

February 20, 2024 · 1 min · jiezi

关于java:Java中和equals有什么区别

原文网址:Java中==和equals有什么区别_IT利刃出鞘的博客-CSDN博客 简介本文介绍java中==和equals的区别。 分享Java技术星球(自学精灵),有面试真题和架构技术等:https://learn.skyofit.com/ 区别区别是:一个是运算符,一个是办法。 ==比拟变量的值是否雷同。 如果比拟的对象是根本数据类型,则比拟数值是否相等;如果比拟的是援用数据类型,则比拟的是对象的内存地址是否相等。因为Java只有值传递,对于==来说,不论是比拟根本数据类型,还是援用数据类型的变量,其比拟的都是值,只是援用类型变量存的值是对象的地址。援用类型对象变量其实是一个援用,它们的值是指向对象所在的内存地址。 equals办法比拟对象的内容是否雷同。 equals()办法存在于Object类中,而Object类是所有类的父类。在Object类中定义了equals办法: public boolean equals(Object obj) { return (this == obj);}如果类未重写equals办法<!----> 调用equals时,会调用Object中的equals办法(理论应用的也是==操作符)<!----> 如果类重写了equals办法<!----> 调用equals时,会调用该类本人的equals办法(个别是比拟对象的内容是否雷同)。比方:<!----> String:比拟字符串内容是否雷同;Integer:比拟对应的根本数据类型int的值是否雷同。

February 20, 2024 · 1 min · jiezi

关于java:Spring-Boot整合Postgres实现轻量级全文搜索

有这样一个带有搜寻性能的用户界面需要: 搜寻流程如下所示: 这个需要波及两个实体: “评分(Rating)、用户名(Username)”数据与User实体相干“创立日期(create date)、观看次数(number of views)、题目(title)、注释(body)”与Story实体相干须要反对的性能对User实体中的评分(Rating)的频繁批改以及下列搜寻性能: 按User评分进行范畴搜寻按Story创立日期进行范畴搜寻按Story浏览量进行范畴搜寻按Story题目进行全文搜寻按Story注释进行全文搜寻Postgres中创立表构造和索引创立users表和stories表以及对应搜寻需要相干的索引,包含: 应用 btree 索引来反对按User评分搜寻应用 btree 索引来反对按Story创立日期、查看次数的搜寻应用 gin 索引来反对全文搜寻内容(同时创立全文搜寻列fulltext,类型应用tsvector以反对全文搜寻)具体创立脚本如下: --Create Users tableCREATE TABLE IF NOT EXISTS users( id bigserial NOT NULL, name character varying(100) NOT NULL,rating integer,PRIMARY KEY (id));CREATE INDEX usr_rating_idxON users USING btree(rating ASC NULLS LAST)TABLESPACE pg_default;--Create Stories tableCREATE TABLE IF NOT EXISTS stories( id bigserial NOT NULL, create_date timestamp without time zone NOT NULL, num_views bigint NOT NULL, title text NOT NULL, body text NOT NULL, fulltext tsvector, user_id bigint, PRIMARY KEY (id),CONSTRAINT user_id_fk FOREIGN KEY (user_id)REFERENCES users (id) MATCH SIMPLEON UPDATE NO ACTIONON DELETE NO ACTIONNOT VALID);CREATE INDEX str_bt_idxON stories USING btree(create_date ASC NULLS LAST,num_views ASC NULLS LAST, user_id ASC NULLS LAST);CREATE INDEX fulltext_search_idxON stories USING gin(fulltext);创立Spring Boot利用我的项目依赖关系(这里应用Gradle构建):plugins { id 'java' id 'org.springframework.boot' version '3.1.3' id 'io.spring.dependency-management' version '1.1.3'}group = 'com.example'version = '0.0.1-SNAPSHOT'java { sourceCompatibility = '17'}repositories { mavenCentral()}dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' implementation 'org.springframework.boot:spring-boot-starter-web' runtimeOnly 'org.postgresql:postgresql' testImplementation 'org.springframework.boot:spring-boot-starter-test'}tasks.named('test') { useJUnitPlatform()}application.yaml中配置数据库连贯信息spring: datasource: url: jdbc:postgresql://localhost:5432/postgres username: postgres password: postgres数据模型定义须要用到的各种数据模型: ...

February 19, 2024 · 3 min · jiezi

关于java:Docker系列网络的配置

原文网址:Docker系列--网络的配置_IT利刃出鞘的博客-CSDN博客 简介阐明 本文介绍Docker的网络的配置。 分享Java技术星球(自学精灵):learn.skyofit.com 官网网址 https://docs.docker.com/engine/reference/commandline/network/ 网络的默认设置Docker启动之后,零碎中会产生一个名为docker0的虚构网桥,会默认创立三个网络:bridge、host、none。 网络模式简介bridge为每一个容器调配、设置IP等,并将容器连贯到docker0虚构网桥,默认为该模式。host容器将不会虚构出本人的网卡,配置本人的IP等,而是应用宿主机的IP和端口。none容器有独立的Network namespace,但并没有对其进行任何网络设置,如调配 veth pair和网桥连贯,IP等。container新建的容器不会创立本人的网卡和配置本人的IP,而是和一个指定的容器共享IP、端口范畴等。指定网络模式的形式(以bridge为例) docker:--network  bridge 容器与非容器网络互通如果有两个利用:A、B。A不是用docker部署的,B是用docker部署的。网络连通有下边两种形式:  法1:A利用里指定B利用的IP和端口:docker0的ip:容器的端口。比方:172.17.0.1:8080 法2:B利用里指定A利用的IP和端口:宿主机的ip:利用的端口。比方:192.168.80.128:6379 自定义网络能够应用docker network create来创立自定义网络,自定义网络默认应用的是桥接网络bridge。 docker network create my-network能够在自定义的网络下运行两个容器实例: docker run -d -p xxx:xxx--network my-network --name c1 xxxdocker run -d -p xxx:xxx--network my-network --name c2 xxx        在两个容器 c1、c2 中相互ping(应用容器名,而不是IP),胜利连通!         自定义网络自身就保护好了主机名和ip的对应关系(ip和域名都能通)。

February 18, 2024 · 1 min · jiezi

关于java:IDEA-20241Spring支持增强GitHub-Action支持增强更新HTTP-Client等

有段时间没有更新IDEA了,早上看到 IntelliJ IDEA 2024.1 EAP 5公布的邮件提醒,瞄了一眼,发现真的是越来越强了,其中不少性能对我来说还是十分有用的。兴许这些能力对关注DD的小伙伴也有帮忙,所以搞篇博客介绍和举荐一下。 Spring、Quarkus等支流框架的反对加强Search Everywhere性能中减少Endpoints选项卡具体如下图所示: 开发者能够在这里间接搜寻通过Spring、Quarkus、Micronaut、Ktor实现的接口来找到具体的代码实现地位。这个性能十分实用,尤其是对于接手老我的项目的开发者来说,能够疾速的定位接口实现来实现开发工作或问题排查。 加强Spring Bean的主动补全和主动拆卸IntelliJ IDEA 当初为应用程序上下文中的所有 Bean 提供主动补全性能,并主动连贯它们。 如果 bean 通过构造函数具备主动拆卸依赖项,则相干字段也会通过构造函数主动拆卸。 同样,如果通过字段或 Lombok 的 @RequiredArgsConstructor 正文注入依赖项,则新 bean 会主动通过字段连贯。 加强 Spring 模型图在该版本中用户拜访Spring模型图变得更加容易,能够如下图这样点击Spring标识的行标记间接跳转: 也能够应用快捷键 ⌥⏎ (MacOS) 或 Alt+Enter(Windows)来生成和跳转。 同时,该版本还引入了新的图标,加强了 Spring 模型图的可视化内容,如:Components、Controllers、Repositories。此外,您当初能够不便地切换库中 Bean 的可见性(默认状况下是暗藏的)。 HTTP Client的改良HTTP Client当初提供更多身份验证选项,包含 PKCE 受权代码和设施授予流程。它还反对令牌和身份验证申请的额定参数。 当初它能够主动解决 code_challenge 和 passes code_verifier 的生成,以便在 PKCE 申请中检索令牌。 这个版本的HTTP Client 能够应用 Netty 作为其低级网络库。通过反对 SSL、代理和 HTTP/2,使咱们可能在 HTTP 客户端中实现 HTTP/2 的反对。 ...

February 17, 2024 · 1 min · jiezi

关于java:MyBatisPlus在xml中使用wrapper的方法

原文网址:MyBatis-Plus--在xml中应用wrapper的办法_IT利刃出鞘的博客-CSDN博客 简介本文介绍MyBatis-Plus如何在xml中应用wrapper。 分享Java技术星球(自学精灵):https://learn.skyofit.com ServiceQueryWrapper<T> wrapper = new QueryWrapper<T>();wrapper.eq("r.room_id", vo.getRoomId());wrapper.in("r.meet_date", dates);List<ReserveRoom> list = reserveRoomService.query(wrapper);MapperIPage<ReserveRoom> query(Page page, @Param("ew) Wrapper<T> wrapper);XML<select id="query" resultType="com.abc.purchase.entity.ReserveRoom"> SELECT r.* FROM reserve_room r LEFT JOIN person_info p ON r.person_id = p.id <if test="ew != null"> ${ew.customSqlSegment} </if></select>

February 17, 2024 · 1 min · jiezi

关于java:COMP26120-Lab-Exercise-5-The-01-Knapsack-Problem

IntroductionIn this section we introduce the ‘0/1 Knapsack’ problem.The 0/1 Knapsack Problem and LogisticsSuppose an airline cargo company has 1 aeroplane which it flies from the UK to the US on a daily basis to transport some cargo. In advance of a flight, it receives bids for deliveries from (many) customers.Customers state• the weight of the cargo item they would like to be delivered; • the amount they are prepared to pay.3The company must choose a subset of the packages (bids) to carry in order to make the maximum possible profit, given the total weight limit that the plane is allowed to carry.In mathematical form the problem is: Given a set of N items each with weight wi and value vi, for i = 1 to N, choose a subset of items (e.g. to carry in a knapsack, or in this case an aeroplane) so that the total value carried is maximised, and the total weight carried is less than or equal to a given carrying capacity, C. As we are maximising a value given some constraints this is an optimisation problem.This kind of problem is known as a 0/1 Knapsack problem. A Knapsack problem is any problem that involves packing things into limited space or a limited weight capacity. The problem above is “0/1” because we either do carry an item: “1”; or we don’t: “0”. Other problems allow that we can take more than 1 or less than 1 (a fraction) of an item. Below is a description of a fractional problem.See the description in Algorithm Design and Applications, p. 498. or the briefer description in Introduction to Algorithms, p. 353.An Enumeration Method for solving 0/1 KnapsackA straightforward method for solving any 0/1 Knapsack problem is to try out all possible ways of packing/leaving out the items. We can then choose the most valuable packing that is within the weight limit.For example, consider the following knapsack problem instance:Sample Input 31542 12 10385 11The first line gives the number of items; the last line gives the capacity of the knapsack; the remaining lines give the index, value and weight of each item e.g. item 2 has value 12 and weight 10. The full enumeration of possible packings would be as follows:Items Packed000001010 12 10 Yes 011 20 15 No1001011101115 4 YesValue WeightFeasible?0 0 Yes 8 5 Yes13 17 259 Yes 14 No 19 NoOPTIMALThe items packed column represents the packings as a binary string, where “1” in position i means pack item i, and 0 means do not pack it. Every combination of 0s and 1s has been tried. The one which is best is 101 (take items 1 and 3), which has weight 9 (so less than C = 11) and value 13. We can also represent a solution as an array of booleans (this approach is taken in the Java and Python stubs).4 ...

February 16, 2024 · 25 min · jiezi

关于java:Nginx系列rewrite的使用

<article class=“article fmt article-content”><p>原文网址:Nginx系列–rewrite的应用_IT利刃出鞘的博客-CSDN博客</p><h2>简介</h2><p>本文介绍Nginx中rewrite的应用。</p><p>分享Java技术星球(自学精灵):learn.skyofit.com</p><h2>语法</h2><p>rewrite regex URL [flag];</p><p><strong>flag标记位</strong></p><ul><li>last:进行解决rewrite,并对配更改后的 URI 从新进行搜寻(再从 server 走一遍匹配流程)。此时对于以后 server 或 location 上下文,不再解决 rewrite 指令。</li><li>break:进行解决rewrite</li></ul><p><!—-></p><ul><li>last 和 break 的区别:last 重写 url 后,会再从 server 走一遍匹配流程,而 break 终止重写后的匹配</li><li>last 和 break 的相同点:<strong>都能进行解决,前面的 rewrite 指令不会再执行。</strong></li></ul><p><!—-></p><ul><li>redirect:返回蕴含 302 代码的长期重定向,在替换字符串不以"http://",“https://“或”$scheme"结尾时应用.</li><li>permanent:返回蕴含 301 代码的永恒重定向。</li></ul><p><!—-></p><ul><li>permanent 是永恒重定向,浏览器会记住它,会始终重定向你设置的地址。能够通过革除浏览器缓存解决。</li></ul><p>rewrite 指令只能返回代码 301 或 302。要返回其余代码,须要在 rewrite 指令前面蕴含 return 指令。</p><h2>查看rewrite日志</h2><p>关上日志开关:rewrite_log on; 能够配置到http,server,location和if上下文中。</p><p><strong>示例</strong></p><p>配置:nginx.conf</p><pre><code>location /first { rewrite_log on; rewrite /first(.) /second$1 last;}</code></pre><p>拜访</p><pre><code>curl test1.com:8080/first/2.txt</code></pre><p>日志后果 </p><p></p><h2>示例:break和last</h2><h3>break</h3><p><strong>配置</strong></p><pre><code>server { listen 9000; server_name localhost; location /info { rewrite ^/. https://www.baidu.com permanent; } location /break { rewrite /.* /info break; proxy_pass http://127.0.0.1:9000; # 该 return 不执行 return 200 “ok”; }}</code></pre><p><strong>拜访</strong></p><pre><code>http://localhost:9000</code></pre><p><strong>后果</strong></p><p>重定向到了baidu.com</p><p><strong>剖析</strong></p><p>首先,匹配到 /break 的 location 块,执行了 rewrite 和 proxy_pass,跳过 return(因为有 break),重定向到 http://127.0.0.1:9000/info;而后,再次进行 server 块,匹配到 /info 的 location 块,最初重定向到了baidu。</p><h3>last</h3><p><strong>配置</strong></p><pre><code>server { listen 9000; server_name localhost; location /info { rewrite ^/.* https://www.baidu.com permanent; } location /break { rewrite /.* /info last; # 该 proxy_pass 不执行 proxy_pass http://127.0.0.1:9000; # 该 return 不执行 return 200 “ok”; }}</code></pre><p><strong>拜访</strong></p><pre><code>http://localhost:9000</code></pre><p><strong>后果</strong></p><p>重定向到了baidu.com</p><p><strong>剖析</strong></p><p>首先,匹配到 /break 的 location 块,执行了 rewrite,跳过 return 和 proxy_pass(因为有 last,proxy_pass 须要和 break 一起用);而后持续匹配,匹配到 /info 的 location 块,最初重定向到了baidu。</p><h2>示例:在location的外部和内部</h2><h2>break和last在location内部</h2><p><strong>根底示例</strong></p><pre><code>server{ listen 80; server_name test.com; root /data/wwwroot/test.com; rewrite /1.html /2.html; rewrite /2.html /3.html;}</code></pre><p>拜访:test.com/1.html</p><p>后果:浏览器最终重定向到test.com/3.html</p><p>剖析:申请1.html文件时,会被重定向到2.html,而后被重定向到3.html,最初返回的文件为3.html</p><p><strong>例1:rewrite后增加break</strong></p><pre><code>server{ listen 80; server_name test.com; root /data/wwwroot/test.com; rewrite /1.html /2.html break; rewrite /2.html /3.html;}</code></pre><p>拜访:test.com/1.html</p><p>后果:浏览器最终重定向到test.com/2.html</p><p>剖析:申请1.html文件时,会被重定向到2.html,遇到break,不再执行下边的rewrite。</p><p><strong>例2:break后还有location</strong></p><pre><code>server{ listen 80; server_name test.com; root /data/wwwroot/test.com; rewrite /1.html /2.html break; rewrite /2.html /3.html; location /2.html { return 403; }}</code></pre><p>拜访:test.com/1.html</p><p>后果:浏览器最终重定向到test.com/2.html</p><p>剖析:申请1.html文件时,会被重定向到2.html,遇到break,不再执行下边的rewrite。</p><h2>break和last在location外部</h2><p><strong>根底示例</strong></p><pre><code>server{ listen 80; server_name test.com; root /data/wwwroot/test.com; location / { rewrite /1.html /2.html; rewrite /2.html /3.html; } location /2.html { rewrite /2.html /a.html; } location /3.html { rewrite /3.html /b.html; }}</code></pre><p><strong>拜访:test.com/1.html</strong></p><p>后果:浏览器最终重定向到test.com/b.html</p><p>剖析:申请1.html,会通过两次重定向到3.html,3.html又刚好匹配location /3.html{},所以返回b.html。</p><p><strong>拜访:test.com/2.html</strong></p><p>后果:浏览器最终重定向到test.com/a.html</p><p>剖析:申请2.html,会通过两次重定向到2.html,2.html又刚好匹配location /2.html{},所以返回a.html。</p><p><strong>例1:rewrite后增加break</strong></p><pre><code>server{ listen 80; server_name test.com; root /data/wwwroot/test.com; location / { rewrite /1.html /2.html break; rewrite /2.html /3.html; } location /2.html { rewrite /2.html /a.html; } location /3.html { rewrite /3.html /b.html; }}</code></pre><p>拜访:test.com/1.html</p><p>后果:浏览器最终重定向到test.com/2.html</p><p>剖析:申请1.html文件时,会被重定向到2.html,遇到break,以后location{} 以及前面的location{} 的指令都不再执行。</p><p><strong>例2:break后还有location</strong></p><pre><code>server{ listen 80; server_name test.com; root /data/wwwroot/test.com; location / { rewrite /1.html /2.html last; rewrite /2.html /3.html; } location /2.html { rewrite /2.html /a.html; } location /3.html { rewrite /3.html /b.html; }}</code></pre><p>拜访:test.com/1.html</p><p>后果:浏览器最终重定向到test.com/a.html</p><p>剖析:申请1.html文件时,会被重定向到2.html,遇到break,不再执行下边的rewrite。2.html会再去匹配一次location,匹配到了location /2.html,于是返回了test.com/a.html。</p></article> ...

February 15, 2024 · 2 min · jiezi

关于java:深入理解SpringCloud之Eureka

<article class=“article fmt article-content”><p></p><p></p><h3>引言</h3><p>大家好,我是小黑,在明天的快节奏开发环境中,微服务架构曾经成为了一种支流。这就像咱们去吃自助餐,每样菜都是独自摆放,想吃什么就拿什么,互不烦扰。在这个架构里,Spring Cloud就是那个提供了各种美食(服务)的自助餐,而Eureka则是自助餐里的菜单板,通知大家每样菜在哪儿。简略来说,Eureka帮忙服务之间找到对方,就像在微小的自助餐厅中找到本人想要的食物一样。</p><p>对于咱们这些Java程序员来说,深刻了解Eureka不仅仅是为了应用它,更重要的是,通过它,咱们能更好地了解微服务架构的精华——服务的注册与发现。这就好比是,不仅晓得菜在哪儿,还要懂得怎么让本人的菜更吸引人,怎么找到最陈腐的菜。所以,让小黑带大家一起深刻摸索Eureka,看看它是如何工作的,以及它如何使咱们的服务更加强壮和灵便。</p><h3>Eureka根底</h3><p>咱们先来聊聊Eureka的根底。设想一下,每当一个新服务启动时,它会向Eureka服务器说:“嘿,我在这儿,有须要我就来找我吧。”这就是服务注册。而当其余服务想要找到这个服务时,它们就会问Eureka:“请问某某服务在哪儿?”Eureka答复之后,这些服务就能够欢快地交换了。这个过程就是服务发现。</p><p>让小黑来举个例子,假如咱们有一个叫做“订单服务”的利用,它须要从“用户服务”中获取用户信息。在Eureka里,这两个服务都会在启动时向Eureka注册本人,通知Eureka它们的地址、端口等信息。</p><p>上面是一个简略的Java代码示例,展现了如何在Spring Boot利用中引入Eureka客户端,并向Eureka服务器注册服务:</p><pre><code class=“java”>// 引入Spring Cloud Eureka客户端依赖import org.springframework.cloud.netflix.eureka.EnableEurekaClient;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication@EnableEurekaClient // 启用Eureka客户端性能public class OrderServiceApplication { public static void main(String[] args) { // 启动Spring Boot利用,并注册到Eureka SpringApplication.run(OrderServiceApplication.class, args); }}</code></pre><p>这段代码中,<code>@EnableEurekaClient</code>注解通知Spring Boot,这个利用是一个Eureka客户端,须要向Eureka服务器注册本人。当启动这个利用时,它就会把本人的信息,比方服务名、地址和端口,发送给Eureka服务器。</p><p>在<code>application.properties</code>或<code>application.yml</code>文件中,咱们还须要配置Eureka服务器的地址,以便客户端晓得向哪里注册:</p><pre><code class=“yml”>eureka: client: serviceUrl: defaultZone: http://我的Eureka服务器地址/eureka/</code></pre><p>通过这些简略的步骤,咱们的“订单服务”就能在Eureka上注册了。</p><h3>Eureka的工作原理</h3><p>设想一下,如果每个服务都是一个运动员,那么Eureka就是赛场上的裁判,它须要晓得哪些运动员在场上,他们的状态如何。</p><h4>服务注册</h4><p>当一个服务启动并向Eureka服务器发送“我在这里”的信号时,这个过程叫做服务注册。这是通过在服务的代码中退出特定的Eureka客户端依赖和配置来实现的。注册胜利后,Eureka服务器就会有这个服务的记录,包含它的地址、端口等信息。</p><pre><code class=“java”>// 在Spring Boot利用中引入Eureka客户端@EnableEurekaClient@SpringBootApplicationpublic class UserServiceApplication { public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class, args); }}</code></pre><h4>心跳机制</h4><p>一旦服务注册到Eureka,它就须要定期向Eureka发送“我还活着”的信号,这个信号就是心跳。如果Eureka一段时间内没有收到某个服务的心跳,它会认为这个服务挂了,而后从注册列表中移除它。这就像运动员须要定期报告本人的地位和状态,如果裁判一段时间内没有收到报告,就会认为运动员曾经登场了。</p><pre><code class=“java”>// Eureka客户端的配置示例eureka: instance: leaseRenewalIntervalInSeconds: 10 # 每10秒发送一次心跳</code></pre><h4>服务发现</h4><p>当其余服务或者利用须要与某个服务通信时,它们会询问Eureka:“请通知我这个服务的以后地址和端口是什么?”Eureka会查找注册列表,而后返回相干服务的信息。这样,服务之间就能够互相发现并通信了。</p><pre><code class=“java”>// 应用Eureka客户端发现服务@RestClient(“userService”) // 假如咱们要发现的服务名为userServicepublic interface UserServiceClient { @GetMapping("/user/{id}") User findUserById(@PathVariable(“id”) String id);}</code></pre><h4>自我保护模式</h4><p>Eureka有一个独特的机制叫做自我保护模式。这个机制的目标是在网络分区故障产生时爱护服务注册表中的信息。如果Eureka服务器在短时间内失落了太多服务的心跳,它会认为是网络故障而不是所有服务都挂了,于是进入自我保护模式。在这个模式下,Eureka不会从注册表中移除任何服务,即便它们的心跳曾经进行了。这就像裁判在看到很多运动员忽然隐没时,决定暂停比赛,期待状况清朗。</p><p>通过这些机制,Eureka确保了服务注册和发现的过程既牢靠又高效。这背地的原理其实不简单,但对于保护一个稳固的微服务架构来说至关重要。理解这些原理,能够帮忙咱们更好地设计和保护本人的服务。</p><h3>高可用的Eureka集群配置</h3><p>在微服务里,高可用性是大家都谋求的指标。就像在一场接力赛中,如果一棒跑得再快,但前面的接力点出了问题,那整个较量就可能受影响。对于Eureka来说,建设一个集群就像设置多个接力点,确保了即使有一个节点出问题,服务注册和发现的性能也不会受到影响。</p><h4>为什么须要Eureka集群</h4><p>如果所有的服务都只向一个Eureka服务器注册,那这个服务器就成了整个零碎的单点故障。一旦它宕机,整个零碎的服务发现机制就会瘫痪。就像如果赛道上只有一个接力点,一旦出了问题,较量就不得不进行。所以,为了进步零碎的稳定性和可用性,咱们须要搭建Eureka集群。</p><h4>配置Eureka集群</h4><p>配置Eureka集群意味着要运行多个Eureka服务器实例,它们之间互相注册,造成一个相互备份的网络。这样,即便一个服务器实例失败,其余实例还能持续提供服务。</p><p>在每个Eureka服务器的配置文件中,咱们须要指定其余Eureka服务器的地址。这样,每个实例启动时就会互相晓得对方的存在,并互相注册。</p><p>假如咱们有两个Eureka服务器实例,配置可能如下所示:</p><pre><code class=“yaml”># Eureka服务器实例1的application.yml配置eureka: instance: hostname: eureka-server1 client: registerWithEureka: true fetchRegistry: true serviceUrl: defaultZone: http://eureka-server2/eureka/</code></pre><pre><code class=“yaml”># Eureka服务器实例2的application.yml配置eureka: instance: hostname: eureka-server2 client: registerWithEureka: true fetchRegistry: true serviceUrl: defaultZone: http://eureka-server1/eureka/</code></pre><p>在这个配置中,每个Eureka服务器都会向对方注册本人,造成了一个简略的集群。这样,即便一个服务器宕机,另一个还能持续工作,保障服务的注册和发现不受影响。</p><h4>测试Eureka集群的高可用性</h4><p>一旦集群搭建实现,咱们能够通过模仿故障的形式来测试其高可用性。比方,能够尝试敞开一个Eureka服务器实例,看看服务是否还能失常注册和发现。这个测试过程就像是查看每个接力点是否都能顺利接力,确保较量能够顺利进行。</p><p>通过这样的配置和测试,咱们就能建设一个强壮的Eureka集群,大大提高了整个微服务架构的稳定性和可用性。这不仅仅是为了应答故障,更是为了让整个零碎更加灵便和弱小。</p><h3>Eureka客户端的深刻探索</h3><p>咱们曾经聊过了Eureka服务器的集群配置,当初让小黑带大家深刻理解一下Eureka客户端。毕竟,一个好的通信零碎不仅须要稳固的信号塔(服务器),还须要智能的手机(客户端)。</p><h4>客户端的工作原理</h4><p>Eureka客户端,就是咱们的服务实例,它负责向Eureka服务器注册本人,并定期发送心跳来维持注册状态。这就像是手机定期给信号塔发送信号,告知本人的地位和状态。</p><p>当客户端启动时,它会向Eureka服务器发送一个注册申请,蕴含了本人的服务ID、IP地址、端口号等信息。一旦注册胜利,客户端就会每隔一段时间(通常是30秒)发送心跳,通知服务器“我还活着”。</p><pre><code class=“java”>// Spring Cloud利用中的Eureka客户端配置示例@SpringBootApplication@EnableEurekaClient // 启用Eureka客户端public class ProductServiceApplication { public static void main(String[] args) { SpringApplication.run(ProductServiceApplication.class, args); }}</code></pre><p>在<code>application.yml</code>中,咱们还能够细化Eureka客户端的配置:</p><pre><code class=“yaml”>eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ # Eureka服务器地址 instance: leaseRenewalIntervalInSeconds: 10 # 心跳距离,每10秒一次 leaseExpirationDurationInSeconds: 30 # 如果30秒内没有心跳,服务将被登记</code></pre><h4>客户端的健康检查</h4><p>为了确保服务的衰弱和可靠性,Eureka客户端还会进行健康检查。如果服务呈现问题,客户端能够主动将本人标记为“DOWN”,这样Eureka服务器就不会将申请转发给这个服务实例。</p><p>在Spring Cloud利用中,咱们通常会联合<code>Spring Boot Actuator</code>来实现健康检查:</p><pre><code class=“java”>// 引入Spring Boot Actuator的依赖dependencies { implementation ‘org.springframework.boot:spring-boot-starter-actuator’}</code></pre><p>通过Actuator,Spring Boot利用会暴露出<code>/actuator/health</code>端点,Eureka客户端会应用这个端点来报告本人的衰弱状态。</p><h4>租约续期与登记</h4><p>客户端通过定期发送心跳来续期其在Eureka服务器上的租约。如果客户端进行发送心跳(可能是因为服务宕机或网络问题),Eureka服务器在肯定工夫后会主动登记该实例。</p><p>如果服务失常敞开,它会向Eureka服务器发送一个登记申请,立刻从注册表中移除本人。这就像是手机在关机前发送一个信号通知信号塔:“我要关机了,不必再给我发信息。”</p><pre><code class=“java”>// Spring Boot利用失常敞开时,主动登记Eureka客户端@Beanpublic EurekaInstanceConfigBean eurekaInstanceConfig(InetUtils inetUtils) { EurekaInstanceConfigBean config = new EurekaInstanceConfigBean(inetUtils); config.setPreferIpAddress(true); config.setLeaseRenewalIntervalInSeconds(10); config.setLeaseExpirationDurationInSeconds(30); return config;}</code></pre><p>通过这些机制,Eureka客户端确保了服务的衰弱、可靠性以及及时的状态更新。这就像是确保每个手机都能在最佳状态下与信号塔通信,保障信息的畅通无阻。</p><h3>Eureka的高级个性</h3><p>咱们曾经摸索了Eureka的基础知识和客户端细节,当初让小黑带大家看看Eureka的一些高级个性。这些个性能让咱们的微服务架构更加灵便和弱小,就像给一般手机加上智能助手一样,让它变得更加智能。</p><h4>区域性和区域感知的负载平衡</h4><p>在微服务架构中,服务实例可能散布在不同的天文区域。Eureka反对区域性(Zones)和区域感知的负载平衡,这意味着客户端能够优先调用同一区域内的服务实例,升高提早,提高效率。</p><p>在Eureka中配置区域性很简略。假如咱们有两个区域:东区和西区。咱们能够在Eureka客户端的配置文件中指定所属区域和服务URL:</p><pre><code class=“yaml”>eureka: instance: metadataMap: zone: 东区 # 客户端所在的区域 client: region: 区域1 # 客户端所属的大区域,能够进一步划分 serviceUrl: 东区: http://eureka-east/eureka/ 西区: http://eureka-west/eureka/ availabilityZones: 区域1: 东区,西区 # 指定区域1蕴含东区和西区</code></pre><p>这样配置后,东区的客户端会优先调用东区的服务实例,西区的客户端则优先调用西区的服务实例。</p><h4>元数据和服务间的自定义信息传递</h4><p>Eureka容许服务实例在注册时增加元数据,这些元数据能够蕴含任何自定义信息,比方服务版本、环境标签等。这些信息能够用于服务间的智能路由决策。</p><p>在服务注册到Eureka时,能够通过配置文件增加元数据:</p><pre><code class=“yaml”>eureka: instance: metadataMap: version: 1.0.0 # 服务版本 environment: 测试环境 # 服务运行的环境</code></pre><p>这样,当客户端发现服务时,就能够获取这些元数据,并据此做出智能决策,比方只调用特定版本的服务或者只在同一环境中的服务之间进行通信。</p><p>通过这些高级个性,Eureka为微服务架构提供了更多的灵活性和可扩展性。就像给手机装置了最新的操作系统,让它能更智能地适应不同的环境和需要。这些个性不仅能够帮忙咱们更好地治理服务实例,还能进步整个零碎的性能和可靠性。</p><h3>Eureka的最佳实际</h3><h4>部署策略</h4><p>在部署Eureka服务器时,最佳实际是至多部署两个实例,造成一个小型集群,这样即便一个实例宕机,另一个也能保障服务的继续可用。这就像是带两块备用电池,一块用完了还有另一块。</p><pre><code class=“yaml”># Eureka服务器实例1的application.yml配置eureka: instance: hostname: eureka-server1 client: serviceUrl: defaultZone: http://eureka-server2/eureka/</code></pre><pre><code class=“yaml”># Eureka服务器实例2的application.yml配置eureka: instance: hostname: eureka-server2 client: serviceUrl: defaultZone: http://eureka-server1/eureka/</code></pre><h4>安全性思考</h4><p>当部署Eureka服务器时,安全性是一个不能漠视的方面。咱们能够通过Spring Security增加根本的认证来爱护Eureka Dashboard和服务注册。这就像是给本人的家门加把锁,避免有人随便进入。</p><pre><code class=“java”>@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // 敞开csrf,容许Eureka客户端注册 http.csrf().disable() .authorizeRequests() .anyRequest().authenticated() .and() .httpBasic(); // 开启根本认证 }}</code></pre><p></p><h4>性能调优和监控</h4><p>对于Eureka服务器和客户端的性能调优,咱们须要关注几个要害参数,比方心跳距离、实例过期工夫等,以确保零碎的响应速度和稳定性。同时,应用Spring Boot Actuator和Spring Cloud Netflix Eureka的监控端点来监控Eureka的健康状况和性能指标。</p><p>在客户端的<code>application.yml</code>中调整心跳距离和实例过期工夫:</p><pre><code class=“yaml”>eureka: instance: leaseRenewalIntervalInSeconds: 10 # 心跳距离 leaseExpirationDurationInSeconds: 30 # 实例过期工夫</code></pre><p>通过Actuator的<code>/actuator/health</code>和<code>/actuator/info</code>端点,咱们能够监控Eureka客户端的健康状况和根本信息。</p><h3>Eureka的将来与代替计划</h3><h4>Eureka的将来</h4><p>Spring Cloud Netflix我的项目包含Eureka在内的几个组件曾经进入保护模式,这意味着它们不会增加新个性,但会持续修复bug和平安问题。不过,Eureka自身作为一个开源我的项目,依然有一个沉闷的社区,并且因为其简略和高效的设计,它依然是许多微服务架构的首选服务发现工具。</p><p>对于将来,咱们可能会看到社区或者其余组织提供的更多翻新和扩大,使得Eureka可能更好地适应新的技术趋势和需要。</p><h4>代替计划</h4><p>尽管Eureka是一个弱小的服务发现工具,但在某些场景下,其余工具可能更适宜咱们的需要。比方:</p><ul><li><strong>Consul</strong>: 提供了服务发现、健康检查、键值存储等性能。它的健康检查性能比Eureka更弱小,能够更粗疏地检测服务的状态。</li><li><strong>Zookeeper</strong>: 最后是Apache Hadoop的子项目,用于集群治理和配置保护。尽管它不是专为服务发现设计的,但能够被用作服务注册和发现的解决方案。</li><li><strong>Etcd</strong>: 由CoreOS开发,是一个高可用的键值存储,罕用于存储配置信息和服务发现。它特地适宜于构建大规模的分布式系统。</li></ul><p>每种计划都有其长处和个性,抉择哪个最终取决于咱们的具体需要和偏好。比方,如果咱们须要更简单的健康检查或者想要键值存储性能,Consul可能是更好的抉择。如果咱们的架构曾经依赖于Apache的生态系统,应用Zookeeper可能更加天然。</p><hr/><p>在以后经济和职场环境中,领有一份副业曾经成为很多人减少财务安全感和晋升集体能力的重要伎俩。通过投身于副业,你不仅能够为本人发明一个额定的支出起源,缩小对主职工作的经济依赖,还能够在这个过程中摸索本人的趣味和激情,发现新的职业路线。副业能够帮忙你学习新的技能和常识,这些在你的主职工作中兴许用不上,但它们可能为你的个人成长和职业倒退开拓新的视角和可能性。点击此处,获取100+实战教程!</p><p></p></article> ...

February 15, 2024 · 2 min · jiezi

关于java:Idea解决character-‘‘-that-cannot

<article class=“article fmt article-content”><p>原文网址:Idea–解决character ‘@‘ that cannot start any token. (Do not use @ for indentation_IT利刃出鞘的博客-CSDN博客</p><h2>简介</h2><p>本文介绍如何解决character ‘@‘ that cannot start any token. (Do not use @ for indentation这个问题。</p><p>分享Java技术星球(自学精灵),网址:learn.skyofit.com</p><h2>问题形容</h2><p>有时候,IDEA忽然运行不了我的项目了,之前是能够的,报错信息为:</p><pre><code>21:34:05.973 [main] ERROR org.springframework.boot.SpringApplication - Application run failedorg.yaml.snakeyaml.scanner.ScannerException: while scanning for the next tokenfound character ‘@’ that cannot start any token. (Do not use @ for indentation) in ‘reader’, line 5, column 13: active: @env@ ^</code></pre><h2>起因剖析</h2><p>maven没有同步。 </p><h2>办法</h2><p>做完下边四步,肯定能解决。</p><ol><li>重启IDEA</li><li>maven clean</li><li>maven compile</li><li>maven package</li></ol></article>

February 15, 2024 · 1 min · jiezi

关于java:Nginx系列转发请求的方法

原文网址:Nginx系列--转发申请的办法_IT利刃出鞘的博客-CSDN博客 简介阐明 本文介绍Nginx转发申请的办法。 分享Java技术星球(自学精灵):https://learn.skyofit.com/ 需要 用户拜访aaa.com/bbb时,理论拜访的是bbb123.com。 计划1:return办法server { listen 8080; server_name aaa.com; location /bbb { return 302 https://bbb123.com$request_uri; } }![]() 阐明浏览器会间接跳转到https://bbb123.com,相当于间接location.href = ‘https://bbb123.com’ 。 计划2:rewrite办法法1:正则匹配所有的URI再去掉结尾第一个/(反斜线)。 server { listen 80; server_name aaa.com; rewrite ^/(.*)$ https://bbb123.com/$1 permanent;}法2: $request_uri变量匹配所有的URI。 server { listen 80; server_name aaa.com; rewrite ^ https://bbb123.com$request_uri? permanent;}法3:与if联合 server { listen 80; server_name aaa.com abc.com; if ($host = 'aaa.com' ) { rewrite ^/(.*)$ https://bbb123.com/$1 permanent; }}阐明浏览器会间接跳转到https://bbb123.com,相当于间接location.href = ‘https://bbb123.com’ 。 计划3:proxy_pass办法server { listen 80; server_name aaa.com; location /aaa/ { proxy_pass https://bbb123.com; }}阐明浏览器显示的依然是aaa.com/aaa,用户是不晓得https://bbb123.com的存在的。 ...

February 14, 2024 · 1 min · jiezi

关于java:列表容器ArrayList学习基于Java8

<article class=“article fmt article-content”><h2>概述</h2><p>ArrayList是jdk提供的非线程平安的基于数组的列表容器,是最频繁应用的Java容器之一。本文次要介绍一下ArrayList的内部结构和运行机制。</p><h2>继承与实现</h2><pre><code class=“java”>public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable</code></pre><ol><li><code>ArrayList</code>继承了<code>AbstractList</code>抽象类,<code>AbstractList</code>提供了<code>get</code>,<code>set</code>,<code>add</code>,<code>remove</code>等形象的列表办法,提供给ArrayList或这LinkedList依据底层存储构造具体实现。</li><li><code>ArrayList</code>实现了<code>List</code>接口,这样就能够实例化一个<code>List</code>类型的变量,其具体实现为<code>ArrayList</code>。</li><li><code>RandomAccess</code>只是一个标记接口,没有任何办法,用于示意该类反对疾速随机拜访——能够应用工夫复杂度O(1)拜访任意元素。</li><li><code>Cloneable</code>接口,想应用<code>Object.clone()</code>办法就要实现这个接口。</li><li>Serializable接口,序列化接口。</li></ol><h2>成员变量和办法</h2><pre><code class=“java”>transient Object[] elementData;private int size;</code></pre><p><code>ArrayList</code>底层是一个Object数组,应用size示意一共保留了多少个元素(不等于elemetnData.length)。</p><h3>常见操作</h3><pre><code class=“java”> public E get(int index) { rangeCheck(index); return elementData(index); } public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[–size] = null; // clear to let GC do its work return oldValue; }</code></pre><p>因为底层是数组,增加、拜访和删除操作都比较简单。查看拜访索引或者容量,而后批改数组。</p><h3>扩容</h3><pre><code class=“java”> public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! modCount记录了汇合的批改次数 elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }</code></pre><p>对list进行扩容,<code>newCapacity = oldCapacity + (oldCapacity >> 1)</code>即新容量为原来的1.5倍。如果数组容量大于<code>ArrayList</code>最大容量,无奈再进行扩容。</p><h3>遍历</h3><p><code>Iterator</code>次要的作用是为容器提供一个遍历元素的形式并且屏蔽容器的底层实现。如果没有迭代器,遍历ArrayList就须要拜访其底层数组,遍历LinkedList就须要拜访它的节点,裸露外部细节。<code>Iterator</code>屏蔽了底层细节,其根本应用:</p><pre><code class=“java”> List list = new ArrayList(); for (Iterator i=list.iterator(); i.hasNext();) i.next();</code></pre><p>ArrayList实现了两个外部迭代器类<code>Itr</code>和<code>ListItr</code>,而后通过<code>iterator()</code>和<code>listIterator()</code>返回给用户应用。</p><pre><code class=“java”>private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such</code></pre><p><code>cursor</code>指向下一个<code>next()</code>须要返回元素的索引,<code>lastRet</code>指向曾经拜访过的上一个元素的索引,<code>lastRet== -1</code>时代表上一个元素曾经被<code>remove()</code>删除了。<code>next()</code>执行之后迭代器<code>remove()</code>才晓得删除的是什么元素。</p><p>本文是迁徙旧文浅学——ArrayList机制</p></article> ...

February 13, 2024 · 2 min · jiezi

关于java:解决jstack的报错Unable-to-open-socket-file

<article class=“article fmt article-content”><p>原文网址:解决jstack的报错:Unable to open socket file_IT利刃出鞘的博客-CSDN博客</p><h2>简介</h2><p><strong>阐明</strong></p><p>本文介绍解决jstack的报错的办法,报错信息为:Unable to open socket file。</p><p>分享Java技术星球:自学精灵 - IT技术星球</p><p>具体报错信息:</p><blockquote>过程号: Unable to open socket file: target process not responding or HotSpot VM not loaded <br/>The -F option can be used when the target process is not responding</blockquote><p><strong>概述</strong></p><p>咱们通常会用jstack、jmap等工具排查CPU占用高、内存占用低等问题。但在应用这些命令时有时会报错,如下所示:</p><p></p><h2>起因及解决方案</h2><h2>1.用户权限不正确</h2><p><strong>起因</strong></p><p>如果执行java程序的用户与执行jstack命令的用户不统一,会导致报错。</p><p><strong>解决方案</strong></p><p>切换到执行java程序的那个用户再执行jstack命令。</p><p><strong>办法</strong></p><p>第一步:查找java过程对应的用户(命令为:ps -aux | grep “过程号”)</p><p>例:</p><p></p><p>第二步:应用su命令切换到对应用户</p><pre><code>su root</code></pre><h2>2./tmp门路没有过程信息</h2><p><strong>起因</strong></p><p>java过程启动的时候,默认会在/tmp/hsperfdata_$USER上面创立一个以PID命名的文件,外面蕴含了一些信息,会被jstack、jmap命令应用到。当文件不存在时就会报上述谬误。</p><p>导致/tmp下没有相干文件的起因有:</p><ol><li>应用了docker来启动</li><li>应用了systemd来启动(systemd用于监控过程状态)</li></ol><p><strong>解决方案</strong></p><ul><li>如果是应用了docker来启动</li></ul><p><!—-></p><ul><li>解决办法:须要进入到容器中去执行jstack命令。</li></ul><p><!—-></p><ul><li>如果是应用了systemd来启动</li></ul><p><!—-></p><ul><li>解决办法:批改一项配置:PrivateTmp=true改为false</li></ul></article>

February 11, 2024 · 1 min · jiezi

关于java:jdk8在windows操作系统的安装与环境变量配置

jdk8在window操作系统的装置与环境变量配置1. 去Oracle官网下载jdk抉择Products下的java跳转到jdk的下载界面下载页面默认是最新版的jdk, 要跳转到历史版本页面, 点击后, 向下拉而后进入jdk8的下载页面,抉择最新的8U371下载到本地下载须要Oracle的用户名和明码, 自行注册登录2. 装置jdk装置jdk跟装置一般软件一样, 没什么好讲的, 装置的门路, 大多是在X:\Program Files目录下, 有个java目录, 记录找个目录 , 在配置环境变量的时候须要用到.3. 配置环境变量右键点击电脑图标, 抉择属性, 抉择高级零碎设置,而后是环境变量在零碎变量中, 创立JAVA_HOME, 而后指定装置的jdk目录双击关上path变量, 追加2行如下代码,点击确定创立CLASSPATH变量(如果有则追加)配置完结一路点击确定, 完结.4. 验证jdk是否装置胜利关上CMD窗口,输出java -version命令, 看是否输入java信息,如果输入, 则示意胜利.如果不是, 则要查看方才的操作步骤是否正确. 是否一次胜利, 就看人品了, 哈哈

September 28, 2023 · 1 min · jiezi

关于java:Java-21-新特性虚拟线程Virtual-Threads

在Java 21中,引入了虚构线程(Virtual Threads)来简化和加强并发性,这使得在Java中编程并发程序更容易、更高效。 虚构线程,也称为“用户模式线程(user-mode threads)”或“纤程(fibers)”。该性能旨在简化并发编程并提供更好的可扩展性。虚构线程是轻量级的,这意味着它们能够比传统线程创立更多数量,并且开销要少得多。这使得在本人的线程中运行独自工作或申请变得更加实用,即便在高吞吐量的程序中也是如此。 创立和应用虚构线程在Java 21中创立和应用虚构线程有多种办法: 1. 应用动态构建器办法Thread.startVirtualThread办法将可运行对象作为参数来创立,并立刻启动虚构线程,具体如下代码: Runnable runnable = () -> { System.out.println("Hello, www.didispace.com");};// 应用动态构建器办法Thread virtualThread = Thread.startVirtualThread(runnable);也能够应用Thread.ofVirtual()来创立,这里还能够设置一些属性,比方:线程名称。具体如下代码: Thread.ofVirtual() .name("didispace-virtual-thread") .start(runnable);2. 与ExecutorService联合应用从Java 5开始,就举荐开发人员应用ExecutorServices而不是间接应用Thread类了。当初,Java 21中引入了应用虚构线程,所以也有了新的ExecutorService来适配,看看上面的例子: Runnable runnable = () -> { System.out.println("Hello, www.didispace.com");};try (ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor()) { for (int i = 0; i < 100; i++) { executorService.submit(runnable); }}上述代码在try代码块中创立了一个ExecutorServices,用来为每个提交的工作创立虚构线程。 3. 应用虚构线程工厂开发者还能够创立一个生成虚构线程的工厂来治理,具体看上面的例子例子: Runnable runnable = () -> { System.out.println("Hello, www.didispace.com");};ThreadFactory virtualThreadFactory = Thread.ofVirtual() .name("didispace", 0) .factory();Thread factoryThread = virtualThreadFactory.newThread(runnable);factoryThread.start;这段代码创立了一个虚构线程工厂,每个虚构线程都会以didispace为前缀、以数字结尾(从0开始累加)的名称。 ...

September 28, 2023 · 1 min · jiezi

关于java:quarkus依赖注入之十二禁用类级别拦截器

欢送拜访我的GitHub这里分类和汇总了欣宸的全副原创(含配套源码):https://github.com/zq2599/blog_demos本篇概览本篇是《quarkus依赖注入》系列的第十二篇,持续学习拦截器的另一个高级个性:禁用类级别拦截器本篇由以下内容形成编码验证类拦截器和办法拦截器的叠加成果用注解<font color="blue">NoClassInterceptors</font>使类拦截器生效总的来说,本篇内容非常简单,就是说分明NoClassInterceptors注解用在哪里,怎么用,能够轻松愉快的浏览类拦截器和办法拦截器的叠加成果接下来进行编码,看看作用在类上和办法上的两个拦截器的叠加成果,要新建的文件清单如下TrackClass.java:定义类级别的拦截器TrackClassInterceptor.java:拦截器TrackClass的性能实现TrackMethod.java:办法级别的拦截器TrackMethodInterceptor.java:拦截器TrackMethod的性能实现ExcludeInterceptorDemo.java:一般的bean,用TrackClass润饰其类,用TrackMethod润饰其test1办法ExcludeInterceptorTest.java:单元测试类,运行ExcludeInterceptorDemo的办法,察看拦挡成果以下是每个文件的具体内容第一个拦截器<font color="blue">TrackClass</font>,用来润饰类,对类的每个办法都有拦挡成果@InterceptorBinding@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface TrackClass {}TrackClass的拦挡性能实现类TrackClassInterceptor@TrackClass@Interceptorpublic class TrackClassInterceptor { @AroundInvoke Object execute(InvocationContext context) throws Exception { Log.info("from TrackClass"); return context.proceed(); }}第二个拦截器<font color="blue">TrackMethod</font>,用来润饰办法,只对被润饰的办法有拦挡成果@InterceptorBinding@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface TrackMethod {}TrackMethod的拦挡性能实现类TrackMethodInterceptor@TrackMethod@Interceptorpublic class TrackMethodInterceptor { @AroundInvoke Object execute(InvocationContext context) throws Exception { Log.info("from TrackMethod"); return context.proceed(); }}为了演示拦截器的成果,创立一个bean,如下所示,TrackClass润饰在类下面,所以test0和test1办法都会被TrackClassInterceptor拦挡,另外,test1办法还会被TrackMethodInterceptor,也就是说两个拦截器都会拦挡test1办法@ApplicationScoped@TrackClasspublic class ExcludeInterceptorDemo { public void test0() { Log.info("from test0"); } @TrackMethod public void test1() { Log.info("from test1"); }}用单元测试类验证成果@QuarkusTestpublic class ExcludeInterceptorTest { @Inject ExcludeInterceptorDemo excludeInterceptorDemo; @Test public void test() { excludeInterceptorDemo.test0(); Log.info("*****************************"); excludeInterceptorDemo.test1(); }}运行成果如下,可见test0被类拦截器拦挡,而test1先后被类拦截器和办法拦截器拦挡 ...

September 28, 2023 · 1 min · jiezi

关于java:并发编程的优缺点

并发编程的优缺点在计算机科学和软件工程中,并发编程是一种波及同时解决多个工作的技术。它被广泛应用于各种零碎和利用中,如多线程利用、网络服务器和实时零碎等。然而,只管并发编程具备许多长处,但也有一些潜在的毛病须要审慎解决。 长处通过并发编程的模式能够将多核CPU的计算能力施展到极致,进步性能。避免阻塞,进步响应性加强可扩展性不便业务拆分,进行业务建模毛病频繁的上下文切换活跃性问题。可能会产生长时间的期待锁,甚至是死锁。性能问题。 线程的频繁调度切换会浪费资源,同步机制会导致内存缓冲区的数据有效,以及减少同步流量。工夫片是CPU调配给各个线程的工夫,因为工夫十分短,所以CPU一直通过切换线程,让咱们感觉多个线程是同时执行的,工夫片个别是几十毫秒。而每次切换时,须要保留以后的状态,以便可能进行复原先前状态,而这个切换时十分损耗性能,过于频繁反而无奈施展出多线程编程的劣势。通常缩小上下文切换能够采纳无锁并发编程,CAS算法,应用起码的线程和应用协程。 无锁并发编程:能够参照concurrentHashMap锁分段的思维,不同的线程解决不同段的数据,这样在多线程竞争的条件下,能够缩小上下文切换的工夫。 CAS算法,利用Atomic下应用CAS算法来更新数据,应用了乐观锁,能够无效的缩小一部分不必要的锁竞争带来的上下文切换 应用起码线程:防止创立不须要的线程,比方工作很少,然而创立了很多的线程,这样会造成大量的线程都处于期待状态 协程:在单线程里实现多任务的调度,并在单线程里维持多个工作间的切换因为上下文切换也是个绝对比拟耗时的操作,所以在"java并发编程的艺术"一书中有过一个试验,并发累加未必会比串行累加速度要快。 能够应用Lmbench3测量上下文切换的时长 vmstat测量上下文切换次数。 线程平安什么是线程平安如果你的代码在多线程下执行和在单线程下执行永远都能取得一样的后果,那么你的代码就是线程平安的。 线程平安产生的起因:正确性取决于多个线程的交替执行时序,产生了竞态条件。 线程安全级别1)不可变 像String、Integer、Long这些,都是final类型的类,任何一个线程都扭转不了它们的值,要扭转除非新创建一个,因而这些不可变对象不须要任何同步伎俩就能够间接在多线程环境下应用 2)相对线程平安 不论运行时环境如何,调用者都不须要额定的同步措施。要做到这一点通常须要付出许多额定的代价,Java中标注本人是线程平安的类,实际上绝大多数都不是线程平安的,不过相对线程平安的类,Java中也有,比方说CopyOnWriteArrayList、CopyOnWriteArraySet 3)绝对线程平安 绝对线程平安也就是咱们通常意义上所说的线程平安,像Vector这种,add、remove办法都是原子操作,不会被打断,但也仅限于此,如果有个线程在遍历某个Vector、有个线程同时在add这个Vector,99%的状况下都会呈现ConcurrentModificationException,也就是fail-fast机制。 4)线程非平安 这个就没什么好说的了,ArrayList、LinkedList、HashMap等都是线程非平安的类,点击这里理解为什么不平安。 多线程编程中最难以把握的就是临界区线程平安问题,略微不留神就会呈现死锁的状况,一旦产生死锁就会造成零碎性能不可用。 通常能够用如下形式防止死锁的状况: 防止一个线程同时取得多个锁;防止一个线程在锁外部占有多个资源,尽量保障每个锁只占用一个资源;尝试应用定时锁,应用lock.tryLock(timeOut),当超时期待时以后线程不会阻塞;对于数据库锁,加锁和解锁必须在一个数据库连贯里,否则会呈现解锁失败的状况易混同的概念同步VS异步同步和异步通常用来形容一次办法调用。同步办法调用一开始,调用者必须期待被调用的办法完结后,调用者前面的代码能力执行。而异步调用,指的是,调用者不必管被调用办法是否实现,都会继续执行前面的代码,当被调用的办法实现后会告诉调用者。比方,在超时购物,如果一件物品没了,你得等仓库人员跟你调货,直到仓库人员跟你把货物送过来,你能力持续去收银台付款,这就相似同步调用。而异步调用了,就像网购,你在网上付款下单后,什么事就不必管了,该干嘛就干嘛去了,当货物达到后你收到告诉去取就好。 并发与并行并发和并行是非常容易混同的概念。并发指的是多个工作交替进行,而并行则是指真正意义上的“同时进行”。实际上,如果零碎内只有一个CPU,而应用多线程时,那么实在零碎环境下不能并行,只能通过切换工夫片的形式交替进行,而成为并发执行工作。真正的并行也只能呈现在领有多个CPU的零碎中。 阻塞和非阻塞阻塞和非阻塞通常用来形容多线程间的相互影响,比方一个线程占有了临界区资源,那么其余线程须要这个资源就必须进行期待该资源的开释,会导致期待的线程挂起,这种状况就是阻塞,而非阻塞就恰好相反,它强调没有一个线程能够阻塞其余线程,所有的线程都会尝试地往前运行。 临界区临界区用来示意一种公共资源或者说是共享数据,能够被多个线程应用。然而每个线程应用时,一旦临界区资源被一个线程占有,那么其余线程必须期待。

September 27, 2023 · 1 min · jiezi

关于java:Spring-MVC-十异常处理

异样是每一个利用必须要解决的问题。 Spring MVC我的项目,如果不做任何的异样解决的话,产生异样后,异样堆栈信息会间接抛出到页面。 比方,咱们在Controller写一个异样: @GetMapping(value="/hello",produces={"text/html; charset=UTF-8"}) @ResponseBody public String hello(ModelAndView model){ int c = 100 / 0; return "<h1>User info</h1>"; }浏览器拜访: 用户体验相当不好,所以个别状况下,利用必须要想方法解决异样。 异样解决形式常见的异样解决形式,无非: 利用中对所有可能产生异样的中央,都try catch,捕捉异样后做相应的解决。集中处理异样。第一种形式显然不好,一方面是代码中须要到处都写try catch,万一某一段代码因为程序员的忽略没有写,异样就会抛出到前台,很不好。 另外,某些状况下异样是不能捕捉的,比方须要事务处理的代码,捕捉异样后会影响到事务回滚。 所以,咱们还是须要想方法用第2中形式来解决异样。n多年前已经做过一个摩托罗拉的我的项目,其中一项需要就是对一个线上零碎的异样做解决、不容许异样信息抛出到前台页面。当初那个我的项目并没有采纳相似SpringMVC的框架,所以最终提出了用filter、在filter中拦挡异样的解决计划并且被客户驳回。 其实SpringMVC的对立异样解决计划和我下面我的项目中采纳的计划十分相似。 SpringMVC的异样解决Spring MVC提供了如下异样解决选项: @ExceptionHandle@ExceptionHandle + @ControllerAdvice自定义异样处理器HandlerExceptionResolver@ExceptionHandle@ExceptionHandle能够作用在Controller中,比方,在下面产生异样的Controller中减少一个@ExceptionHandle注解的办法: @GetMapping(value="/hello",produces={"text/html; charset=UTF-8"}) @ResponseBody public String hello(ModelAndView model){ int c = 100 / 0; return "<h1>User info</h1>"; } @ExceptionHandler(Exception.class) @ResponseBody public String handle(Exception ex){ return "错了在helloworld Controller error msg is ==="; }运行: 阐明Hello办法中产生的异样,曾经被handle办法解决,前台页面不再会出现异常信息。 问题解决了! ...

September 27, 2023 · 2 min · jiezi

关于java:秋招上岸我都做对了哪些事

这两年的待业状况大家是引人注目的,特地是作为双非院校的学生,更能感觉到其中的寒意。 然而,作为学生的小张(花名),居然在国庆之前,拿到了两份 Java 研发的工作: 深服气 Java 研发岗工作,薪资 17K*15。金证科技 Java 研发岗工作,薪资预计 15K。口说无凭,间接上图:那他都作对了哪些事呢?接下来来分享一下他的秘诀。 1.提前准备口试家喻户晓,当初都是先口试再面试的,所以想要拿到 Offer 的第一步是先过口试,而口试又分为两类: 大公司得口试:大公司的口试全部都是算法题,通常有 4 道左右,个别状况下 AC 两道左右就能够过口试了。中小型公司的口试:中小型公司是选择题 + 算法题(通常是 2 道),个别状况下选择题不要错太多,算法题 AC 一道根本就过了。当然,也有非凡状况,例如东子 Java 研发岗的口试,两道算法题,只做了一道,另一道没做,而且做的那道算法题测试用例只通过了 20%,但口试也过了,如图:所以找工作海投、海笔也是有惊喜的。 失常状况下,口试须要提前 1 年就开始筹备起来了,因为算法题不能短时间晋升,每天最多也就是刷 3-5 道的样子。但如果口试过不了,那你的代码能力在牛、八股能力再高都没有展现的机会。 当然,如果你曾经应届生,错过了筹备口试的机会,那么也是有一些策略,能略微补救一下的,点赞私信我获取补救办法。2.提前准备面试和我的项目校招当初至多要做两个我的项目,并且这两个我的项目不要烂大巷,最好是微服务项目,外面应用的技术肯定要有 Redis,这是这两年的硬性要求了,如果我的项目中在有音讯队列和微服务那根本就稳了。 我的项目问题在面试的过程中占比通常是 30% 左右(不同公司、不同面试官占比也不雷同),所以我的项目实现的细节肯定要能答复上来,还有我的项目的亮点有哪些?我的项目中有什么有余?做我的项目的时候有没有遇到什么问题?你是如何解决的?为什么要做这样的我的项目?等等这些常见的问题,都要提前准备一下。 搞定我的项目之后,接下来就是筹备面试的理论知识了,简略给大家总结一下面试理论知识波及到的知识点: Java 根底汇合并发编程MySQLRedis网络SpringSpring MVCSpring BootMyBatis/MyBatis PlusLinuxJVM音讯队列中间件常见设计模式Spring Cloud 注册核心配置核心限流和熔断分布式事务分布式链路追踪开放性问题 3.踊跃投递简历做好下面的筹备之后,接下来就到了最重要的环节了:投递简历,投递简历是获取 Offer 最重要的一步了。 酒香也怕巷子深,不投递简历就没有口试的机会,没有口试的机会就没有面试的机会,没有面试的机会就没有取得 Offer 的机会,所以,所有的开始都在“投简历”上,它十分重要。 如果是秋招,倡议从 7 月初秋招提前批就开始投递简历,有没有响应不重要,重要是你要保持踊跃投递,能找到公司都要投递,找工作必须是海投策略。如果你是春招,2 月初就开始投递简历。投递简历的平台有以下这些。 校招投递简历渠道: BOSS 直播企业官网牛客社招投递简历渠道: BOSS 直聘智联招聘小结找工作要过三关:口试 + 技术面试(通常是两轮)+ HR 面试,每一轮都要提前准备才行,毛主席说过“不打无筹备的仗”,凡事预则立不预则废。心愿大家都能踊跃投递简历,好好筹备口试和面试,最终播种属于本人的大 Offer。 本文已收录到我的面试小站 www.javacn.site,其中蕴含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、音讯队列等模块。

September 27, 2023 · 1 min · jiezi

关于java:Java使用ELK搭建日志管理系统

前言最近我的项目须要记录零碎的日志,发现springcloud集成elk(elasticsearch+logstash+kibna)是个不错的计划,于是着手开始搭建环境并记录过程分享给大家。 筹备首先咱们要装置好elasticsearch+kibana以及logstash,上面是我相干文章,大家能够看看。 1、装置elasticsearch+kibana2、Helm3-装置带有ik分词的ElasticSearch3、装置logstash 4、Java-实现ElasticSearch 增删改性能 Logstash配置1、引入jar包 <dependency> <groupId>net.logstash.logback</groupId> <artifactId>logstash-logback-encoder</artifactId> <version>7.4</version></dependency>2、增加logback-spring.xml文件 如下所示: <?xml version="1.0" encoding="UTF-8"?><configuration debug="true" scan="true" scanPeriod="10 seconds"> <springProperty scope="context" name="springAppName" source="spring.application.name"/> <springProperty scope="context" name="active" source="spring.profiles.active"/> <!-- 异步发送日志--> <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"> <appender-ref ref="LOGSTASH"/> </appender> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- logstash 设置 --> <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender"> <!-- <param name="Encoding" value="UTF-8"/>--> <!-- logstash 服务器 --> <destination>xxx.xxx.xxx.xxx:xxxx</destination> <!-- encoder is required --> <encoder charset="UTF-8" class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"> <providers> <timestamp> <timeZone>UTC</timeZone> </timestamp> <pattern> <pattern> { "active": "${active}", "service": "${springAppName:-}", "timestamp": "%date{ISO8601}", "level": "%level", "thread": "%thread", "logger": "%logger", "message": "%message", "context": "%X" } </pattern> </pattern> </providers> </encoder> <!-- 临界值过滤器,过滤掉低于指定临界值的日志。当日志级别等于或高于临界值时,过滤器返回NEUTRAL;当日志级别低于临界值时,日志会被回绝,OFF>ERROR>WARN>INFO>DEBUG>TRACE>ALL --> <!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">--> <!-- <level>INFO</level>--> <!-- </filter>--> </appender> <!-- 日志输入级别 --> <root level="INFO"> <!-- 增加logstash日志输入 --> <appender-ref ref="STDOUT"/> <appender-ref ref="ASYNC"/> </root></configuration>3、运行我的项目查看logstash日志和elasticsearch日志输入 ...

September 27, 2023 · 2 min · jiezi

关于java:我们公司用了-3-年多的多账号统一登录方案万能通用稳的一批

作者:VanFan \起源:juejin.cn/post/6844904053411938311 当初简直大部分的 App 都反对应用多个第三方账号进行登录,如:微信、QQ、微博等,咱们把此称为多账号对立登陆。而这些账号的表设计,流程设计至关重要,不然后续扩展性贼差。 本文不提供任何代码实操,然而梳理一下博主依据我司账号模块的设计,提供思路,仅供参考。 一、 自建的登陆体系1.1.1 手机号登陆注册该设计的思路是每个手机号对应一个用户,手机号为必填项。流程: 首先输出手机号,而后发送到服务端。先判断该手机号是否存在账号,如果没有,就会生成随机验证码,将手机号和验证码绑定到 Redis中,并设置肯定的过期工夫(过期工夫个别是5分钟,这就是咱们个别手机验证码的有效期),最初将验证码通过短信发送给用户。用户接管到验证码后,在界面填写验证码以及明码等根底信息,而后将这些数据发送服务端。服务端收到后,先判断在 Redis外面这个手机号对应的验证码是否统一,,失败就返回错误码,胜利就给用户创立一个账号和保留明码。注册胜利后,用户即可通过本人的 手机号+明码进行登陆。问题: 用户体验差,须要实现获取验证码,填写验证码/明码/用户名等诸多的信息实现注册,而后能力应用;容易忘记明码,忘记后,只能通过遗记明码来从新设置明码。1.1.2 优化注册登陆该计划的思路是弱化明码的必填性,即无论用户是否注册过,可通过 手机号+验证码 间接进行登陆(保留 手机号+明码登录的形式)。举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice流程: 输出手机号,而后发送到服务端。服务端生成随机验证码,将手机号和验证码绑定到 Redis中,并设置肯定的过期工夫(过期工夫个别是5分钟,这就是咱们个别手机验证码的有效期),最初将验证码通过短信发送给用户。用户接管到验证码后,在界面只需填写收到的验证码,提交到服务端。服务端收到后,先判断在 Redis外面这个手机号对应的验证码是否统一,失败就返回错误码,胜利就间接登录。如果是老用户,间接拉取用户信息;如果是新用户,则提醒他能够欠缺用户信息(不强制)。用户通过 手机号+验证码登录后,也可抉择设置明码,而后就能够通过 手机号+明码的形式登录,即:明码是非必填项。用户表设计: iduser_nameuser_passworduser_mobilestatemore用户id用户名用户明码手机号码账号状态其余信息1.2 引入第三方账户计划1.2.1 微博登录进入 Web2.0 时代 ,微博凋谢了第三方网站登录, 产品说, 这个咱们得要, 加个用微博帐号就能登录咱们的 App吧,而且得和咱们本人的用户表关联。 流程: 客户端调用微博登录的界面,进行输出用户名、明码,登录胜利后,会返回 access_token,通过 access_token调取 API接口获取用户信息。服务端通过用户信息在咱们用户表创立一个账号,当前,该第三方账号即可通过该微博账号间接进行登陆。微博用户信息表设计: iduser_iduidaccess_token主键id用户id微博惟一id受权码1.2.2 噩梦降临紧接着, QQ又凋谢用户登录了, 微信凋谢用户登录了,网易开发用户登录了。。。。。。一下子要接入好多家第三方登录了, 只能依照 “微博用户信息表” 新建一个表,重写一套各个第三方登录。 二、 优化账号体系2.1 原账号体系剖析自建登陆体系:无论 手机号+明码 , 还是 手机号+验证码 , 都是一种 用户信息+明码 的验证模式;第三方登录:也是 用户信息+明码 的模式, 用户信息即第三方零碎中的 ID(第三方零碎中的惟一标识), 明码即 access_token, 只不过是一种有应用时效定期批改的明码。2.2 新的账号体系2.2.1 数据表设计用户根底信息表: ...

September 27, 2023 · 2 min · jiezi

关于java:一款免费的响应式界面调试工具

不晓得大家平时开发响应式前端代码是如何调试的?是不是也跟我一样,通过浏览器的开发者工具来切换不同的界面尺寸来看验证成果呢? 可能是因为习惯了,平时就不停的切换不同尺寸来看成果。直到TJ君看到明天要举荐的这个收费工具,我才发现之前的调试形式好傻... 应用体验上面,咱们还一起来看看明天要举荐的这款名为:Responsively的收费工具。 它能够帮忙咱们更便捷的调试响应式界面的程序,如何便捷呢? 间接看下图: 这款工具通过将不同尺寸的界面一起显示的形式,让咱们一次就能看到多个场景下的成果,是不是直观不便很多呢? 它还有很多有用的性能,比方: 元素审查: 日夜模式: 反对平台Responsively反对支流的操作系统,包含:Mac、Windows、Linux。感兴趣的小伙伴都能够试试看。 最初,老规矩,奉上地址:https://responsively.app/,感兴趣的小伙伴能够返回体验。 欢送扫描下方二维码,关注公众号:TJ君,订阅每日举荐,获取更多好用效率工具! 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

September 27, 2023 · 1 min · jiezi

关于java:简历投递无响应可能是这个问题

这两天有同学问我:为什么最近投递了简历之后没有回应? 所以这里对立和大家聊一下这个话题。 起因概述投递简历后没有回应的次要起因有以下几个: 简历问题 学校不满足要求学历不满足要求实习教训(或工作教训)不满足要求技术能力不满足要求我的项目教训不满足要求联系方式问题 邮箱写错或邮件被拦挡电话号码写错短信被拦挡投递数量不够具体内容和解决方案持续往下看。 1.简历问题1.1 学习和学历简历中的学校和学历是不可扭转的,所以如果用人单位对于学校和学历有要求的话,这个问题是无解的,它也不能通过非凡伎俩,如伪造简历来解决,因为用人单位在入职之前都有背调(背景考察),所以如果你是因为这种状况,没关系,投下一家公司就好了。以校招来说,总共有 1700 多家公司参加秋招,所以持续投递下家公司就是了,不要在一棵树上吊死。 1.2 实习教训和工作教训实习教训和工作教训也是相似的,因为有背景考察和须要提供工作证实,所以通常状况下是不能进行包装的,但也不是齐全不能,如果技术和我的项目教训不错的状况下,能够凭集体“能力”,挣扎一下。此计划尽管不举荐,但在能力能够,却没有任何机会的状况下,能够尝试解决。 1.3 技术能力和我的项目教训技术能力有余和我的项目能力有余的问题是最好解决的,只有通过短时间的学习,比方 Redis 不行就去学 Redis,RabbitMQ 不行就去学 RabbitMQ,Spring Cloud 不行就去学 Spring Cloud,只有有靠谱的教程,并且有人领导的状况下,它晋升的速度是很快的。如果你不晓得哪个视频靠谱?不晓得谁能够领导你?分割磊哥就行了:gg_stone,这个问题磊哥最善于解决了。 不晓得如何写简历?能够看我之前录的视频:https://www.bilibili.com/video/BV1K94y1y7M2/2.联系方式问题联系方式这块要做到以下几点: 仔细检查一下本人的邮箱和手机号,保障它们都是对的。定期检查一下本人的邮件垃圾箱,手机和短信有没有拦挡口试和面试信息。找同学和好友测试一下你的邮箱和短信是否可能失常接管音讯。 3.投递数量问题简历不是投递 3-5 份、10 来份就够了,而是能看到多少家就投递多少家。给你一个参考数据,双非院校本科,学校排名在 200~300 的院校,投递简历之后的口试率只有 15%~25% 之间,也就是投递 100 份简历,可能才有 15 家左右的口试邀请。 所以你想想,如果是某某某院校,那么你的口试率可能在 3%~8% 之间,所以你投递简历没有响应,可能大概率就是你投递的简历太少了。 在哪投递简历?校招投递简历渠道: BOSS 直播企业官网牛客社招投递简历渠道: BOSS 直聘智联招聘 小结投递了简历后没有回应?可能是简历问题、联系方式问题以及投递数量太少等问题,所以倡议每个人针上述问题,一一核查对照本人的信息。秋招季才刚刚开始,大家不必丧气、不必焦虑,11 月底之前都是有机会的。乾坤未定,你我皆是黑马,加油! 本文已收录到我的面试小站 www.javacn.site,其中蕴含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、音讯队列等模块。

September 26, 2023 · 1 min · jiezi

关于java:Spring-MVC-01-简单程序

1. 回顾MVC1.1、什么是MVCMVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。是将业务逻辑、数据、显示拆散的办法来组织代码。MVC次要作用是升高了视图与业务逻辑间的双向偶合。MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差别。Model(模型):数据模型,提供要展现的数据,因而蕴含数据和行为,能够认为是畛域模型或JavaBean组件(蕴含数据和行为),不过当初个别都拆散开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查问和模型数据的状态更新等性能,包含数据和业务。 View(视图):负责进行模型的展现,个别就是咱们见到的用户界面,客户想看到的货色。 Controller(控制器):接管用户申请,委托给模型进行解决(状态扭转),处理完毕后把返回的模型数据返回给视图,由视图负责展现。也就是说控制器做了个调度员的工作 1.2、Servelt编写一个Servlet类,用来解决用户的申请: package com.servlet;//实现Servlet接口public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获得参数 String method = req.getParameter("method"); if (method.equals("add")){ req.getSession().setAttribute("msg","执行了add办法"); } if (method.equals("delete")){ req.getSession().setAttribute("msg","执行了delete办法"); } //业务逻辑 //视图跳转 req.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); }}编写Hello.jsp,在WEB-INF目录下新建一个jsp的文件夹,新建hello.jsp: %@ page contentType="text/html;charset=UTF-8" language="java" %><html><head> <title>Index</title></head><body>${msg}</body></html>在web.xml中注册Servlet: <?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class>com.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/user</url-pattern> </servlet-mapping></web-app>2. Spring MVCSpring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。 ...

September 26, 2023 · 2 min · jiezi

关于java:使用Optional优雅避免空指针异常

本文已收录至GitHub,举荐浏览 Java随想录 微信公众号:Java随想录 原创不易,重视版权。转载请注明原作者和原文链接在编程世界中,「空指针异样(NullPointerException)」无疑是咱们最常遇到的"罪魁祸首"之一。它像一片荫蔽的地雷,静静地期待着咱们不小心地踏入,给咱们的代码带来潜在的威逼。这种问题尽管看似渺小,但却无奈漠视。甚至可能对整个程序的稳定性产生重大影响。 为了应答这个长久以来困扰开发者的问题,Java 8 版本引入了一个弱小的工具——Optional 类。 Optional 不仅仅是一个容器,它更是一种编程理念的转变,让咱们能够用更优雅的形式解决可能为空的状况。 在本篇博客中,我将向大家介绍 JDK Optional 类及其应用办法,帮忙你从根本上杜绝空指针异样,晋升代码品质。 Optional 介绍Optional 类是一个容器对象,它能够蕴含或不蕴含非空值。如果一个对象可能为空,那么咱们就能够应用 Optional 类来代替该对象。 Optional 类型的变量能够有两种状态:存在值和不存在值。 Optional类有两个重要的办法:of和ofNullable: of办法用于创立一个非空的Optional对象,如果传入的参数为null,则会抛出NullPointerException异样。ofNullable办法用于创立一个能够为空的Optional对象。如果传入的参数为空,则返回一个空的Optional对象。当 Optional 对象存在值时,调用 get() 办法能够返回该值,当 Optional 对象不存在值时,调用 get() 办法会抛出 NoSuchElementException 异样。上面是一个应用 Optional 类的例子: Optional<String> optional = Optional.of("Hello World");System.out.println(optional.get()); //输入 Hello World在下面的例子中,咱们首先应用 of() 办法创立了一个蕴含字符串 "Hello World" 的 Optional 对象,而后应用 get() 办法获取该对象的值并将其打印进去。 留神,如果咱们尝试创立一个 null 值的 Optional 对象,则会抛出 NullPointerException 异样。 在应用 Optional 类时,咱们应该尽量避免应用 isPresent() 和 get() 办法,因为这些办法可能会引起空指针异样。比拟举荐应用 Optional.ofNullable() 来创立一个Optional 对象。 ...

September 26, 2023 · 2 min · jiezi

关于java:解锁Java面试中的锁深入了解不同类型的锁和它们的用途

简介多线程编程在古代软件开发中扮演着至关重要的角色。它使咱们可能无效地利用多核处理器和进步应用程序的性能。然而,多线程编程也随同着一系列挑战,其中最重要的之一就是解决共享资源的线程安全性。在这个畛域,锁(Lock)是一个要害的概念,用于协调线程之间对共享资源的拜访。本文将深入探讨Java中不同类型的锁以及它们的利用。咱们将从基本概念开始,逐渐深刻,帮忙您理解不同类型的锁以及如何抉择适合的锁来解决多线程编程中的问题。 首先,让咱们对Java中常见的锁品种进行简要介绍。在多线程编程中,锁的作用是确保同一时刻只有一个线程能够访问共享资源,从而避免数据竞争和不一致性。不同的锁类型具备不同的特点和实用场景,因而理解它们的差别对于正确抉择和应用锁至关重要。 重入锁(Reentrant Lock)首先,让咱们深入研究一下重入锁,这是Java中最常见的锁之一。重入锁是一种可重入锁,这意味着同一线程能够屡次获取同一个锁,而不会造成死锁。这种个性使得重入锁在许多简单的多线程场景中十分有用。 重入锁的实现通常须要显式地锁定和解锁,这使得它更加灵便,但也须要开发人员更小心地治理锁的状态。上面是一个简略的示例,演示如何应用重入锁来实现线程平安: import java.util.concurrent.locks.ReentrantLock;public class Counter { private int count = 0; private ReentrantLock lock = new ReentrantLock(); public void increment() { lock.lock(); // 获取锁 try { count++; } finally { lock.unlock(); // 开释锁 } } public int getCount() { lock.lock(); // 获取锁 try { return count; } finally { lock.unlock(); // 开释锁 } }}在下面的示例中,咱们应用ReentrantLock来爱护count字段的拜访,确保increment和getCount办法的线程安全性。请留神,咱们在获取锁后应用try-finally块来确保在实现操作后开释锁,以避免死锁。 互斥锁和synchronized关键字除了重入锁,Java中还提供了互斥锁的概念,最常见的形式是应用synchronized关键字。synchronized关键字能够用于办法或代码块,以确保同一时刻只有一个线程能够拜访被锁定的资源。 例如,咱们能够应用synchronized来实现与下面示例雷同的Counter类: public class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; }}在这个例子中,咱们应用synchronized关键字来标记increment和getCount办法,使它们成为同步办法。这意味着同一时刻只有一个线程能够拜访这两个办法,从而确保了线程安全性。 ...

September 26, 2023 · 4 min · jiezi

关于java:GitHub-2FA开启时国家和地区没有中国只有台湾如何完成开启

最近上GitHub始终都会弹出一个黄色框框,提醒要开启2FA(two-factor authentication,即:双重身份验证)。 GitHub users are now required to enable two-factor authentication as an additional security measure. Your activity on GitHub includes you in this requirement.You will need to enable two-factor authentication on your account before October 06, 2023, or be restricted from account actions. 弹了很久,始终都没去解决,明天新血来潮想去掉这个货色。然而,很扯淡的是,第一步就卡住了,国家抉择里压根没中国: 同时,这里竟然有台湾? 看到网友有分享通过浏览器工具手工增加上面这段js来手工增加China选项来实现流程的(如果之前的确能通,成心不提供中国地区,是不是有点啥?) var option = new Option("China +86","+86");option.selected = true;document.getElementById('countrycode').options.add(option, 0);但DD当初试了一下,貌似短信都发不过去(可能之前能够吧): 最初,还是通过身份验证App来实现了。你只须要点击页面底部这里进入: 依据页面提醒,应用1Password、Authy、Microsoft Authenticator等身份验证类App(DD这里用的Microsoft Authenticator)来扫上面的二维码 扫码后,下面这些身份验证App,都会产生一个一次性明码,间接输出上图中的底部输入框,而后持续就实现了。 最近DD在连载Java新个性专栏,内容涵盖Java 8之后的新个性解读,欢送关注~ ...

September 26, 2023 · 1 min · jiezi

关于java:一个含不少免费额度和数据下载的IP地址来源查询工具

大家好,我是TJ君! 现在在国内经营的各种互联网利用都有接入IP起源显示的要求,当初相干API的供应商也很多。明天TJ刚好看到一个不错的,所以马上给大家举荐一下。 这款不错的产品名称为:IPInfo 产品个性该IP查问工具除了传统的提供地址地位之外,还有很多其余能力,具体的这里TJ君给大家整顿了一下,次要上面有这些: IP所在事实世界中的地理位置IP背地的公司信息,包含:公司名称、域名、公司类型等查找公司领有或经营的IP范畴检测暗藏用户IP的VPN、代理等IP与每个ASN相干域的详细信息IP地址上托管的域列表IP Whois信息查问检测挪动运营商的信息IP滥用信息API服务与收费额度从官网的价格页上能够看到,该工具提供了4种不同价格套餐: 不同套餐除了调用次数不同外,对于数据类型的查问范畴也不同,上面是不同套餐响应的数据丰盛水平: 能够看到该工具还提供了收费套餐,一共50000次/月的申请额度。对于很多刚起步的小产品,或者集体博客等独立产品来说,这个收费额度,基本上也够用了。刚好有这个需要的小伙伴,能够来试试。其余付费套餐,这里就不介绍了,感兴趣的小伙伴能够去价格页查看。 数据下载与收费子集另外,这块IP查问工具,不光提供API的查问形式,还提供数据库的下载,如果调用量很大的话,能够思考这个计划: 该计划会提供每日下载IP地理位置、IP范畴、运营商、公司等数据,用户能够保障拜访到最新、最精确的IP数据。 同时,对于个别用户来说,也能够下载它们的收费数据来应用: 最初,奉上该工具的官网地址:https://ipinfo.io/ ,感兴趣的小伙伴能够自行返回查看。 欢送关注公众号:TJ君,订阅每日举荐,理解更多效率工具、发现优质开源我的项目 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

September 26, 2023 · 1 min · jiezi

关于java:Java-21新特性Sequenced-Collections有序集合

在JDK 21中,Sequenced Collections的引入带来了新的接口和办法来简化汇合解决。此加强性能旨在解决拜访Java中各种汇合类型的第一个和最初一个元素须要非对立且麻烦解决场景。 上面一起通过本文来理解一下不同汇合解决示例。 Sequenced Collections接口Sequenced Collections引入了三个新接口: SequencedCollectionSequencedMapSequencedSet这些接口附带了一些新办法,以提供改良的汇合拜访和操作性能。 第一个和最初一个元素的拜访在JDK 21之前,检索Java中汇合的第一个和最初一个元素波及不同的办法和路径,具体取决于汇合类型。 上面让咱们看一下应用JDK 21之前的JDK API调用拜访第一个和最初一个元素的一些示例: | 拜访地位 | List | Deque | SortedSet || --- | --- | --- | --- | | 第一个元素 | list.get(0) | deque.getFirst() | set.first() || 最初一个元素 | list.get(list.size()-1) | deque.getLast() | set.last() | 能够看到,一个简略的操作,在不同的汇合中须要不同的编写形式,十分麻烦! 但在JDK 21之后,拜访第一个和最初一个元素就办法多了: 对于List, Deque, Set这些有序的汇合,拜访办法变得对立起来: 第一个元素:collection.getFirst()最初一个元素:collection.getLast()好了,明天的分享就到这里。如果您学习过程中如遇艰难?能够退出咱们超高品质的技术交换群,参加交换与探讨,更好的学习与提高!另外,不要走开,关注我!继续更新Java新个性专栏! 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

September 26, 2023 · 1 min · jiezi

关于java:spring源码解析IOC之自定义标签解析

概述之前咱们曾经介绍了spring中默认标签的解析,解析来咱们将剖析自定义标签的解析,咱们先回顾下自定义标签解析所应用的办法,如下图所示: 咱们看到自定义标签的解析是通过BeanDefinitionParserDelegate.parseCustomElement(ele)进行的,解析来咱们进行详细分析。 自定义标签的应用扩大 Spring 自定义标签配置个别须要以下几个步骤: 创立一个须要扩大的组件定义一个 XSD 文件,用于形容组件内容创立一个实现 AbstractSingleBeanDefinitionParser 接口的类,用来解析 XSD 文件中的定义和组件定义创立一个 Handler,继承 NamespaceHandlerSupport ,用于将组件注册到 Spring 容器编写 Spring.handlers 和 Spring.schemas 文件上面就依照下面的步骤来实现一个自定义标签组件。 创立组件该组件就是一个一般的 JavaBean,没有任何特别之处。这里我创立了两个组件,为什么是两个,前面有用到 User.java package dabin.spring01;public class User { private String id; private String userName; private String email;public void setId(String id) { this.id = id; }public void setUserName(String userName) { this.userName = userName; }public void setEmail(String email) { this.email = email; } @Override public String toString() { final StringBuilder sb = new StringBuilder("{"); sb.append("\"id\":\"") .append(id).append('\"'); sb.append(",\"userName\":\"") .append(userName).append('\"'); sb.append(",\"email\":\"") .append(email).append('\"'); sb.append('}'); return sb.toString(); }}Phone.java ...

September 25, 2023 · 6 min · jiezi

关于java:分库分表

&nbsp&nbsp&nbsp&nbsp不论是分库还是分表,都有两种切分形式:程度切分和垂直切分。上面咱们别离看看如何切分。 1、分表 (1)垂直分表&nbsp&nbsp&nbsp&nbsp表中的字段较多,个别将不罕用的、 数据较大、长度较长的拆分到“扩大表“。个别状况加表的字段可能有几百列,此时是依照字段进行数竖直切。留神垂直分是列多的状况。 (2)程度分表&nbsp&nbsp&nbsp&nbsp单表的数据量太大。依照某种规定(RANGE,HASH取模等),切分到多张表外面去。 然而这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。这种状况是不倡议应用的,因为数据量是逐步减少的,当数据量减少到肯定的水平还须要再进行切分。比拟麻烦。 2、分库 (1)垂直分库一个数据库的表太多。此时就会依照肯定业务逻辑进行垂直切,比方用户相干的表放在一个数据库里,订单相干的表放在一个数据库里。留神此时不同的数据库应该寄存在不同的服务器上,此时磁盘空间、内存、TPS等等都会失去解决。 (2)程度分库程度分库实践上切分起来是比拟麻烦的,它是指将单张表的数据切分到多个服务器下来,每个服务器具备相应的库与表,只是表中数据汇合不同。 程度分库分表可能无效的缓解单机和单库的性能瓶颈和压力,冲破IO、连接数、硬件资源等的瓶颈。 四、分库分表之后的问题1、联结查问艰难联结查问不仅艰难,而且能够说是不可能,因为两个相关联的表可能会散布在不同的数据库,不同的服务器中。 2、须要反对事务分库分表后,就须要反对分布式事务了。数据库自身为咱们提供了事务管理性能,然而分库分表之后就不实用了。如果咱们本人编程协调事务,代码方面就又开始了麻烦。 3、跨库join艰难分库分表后表之间的关联操作将受到限制,咱们无奈join位于不同分库的表,也无奈join分表粒度不同的表, 后果本来一次查问可能实现的业务,可能须要屡次查问能力实现。 咱们能够应用全局表,所有库都拷贝一份。 4、后果合并麻烦比方咱们购买了商品,订单表可能进行了拆分等等,此时后果合并就比拟艰难。

September 25, 2023 · 1 min · jiezi

关于java:那些惊为天人的变量名真是奇葩

起源:麦叔编程 \作者:小K 前言一个好的变量名能让读代码的人(包含写的人),身心舒畅,但一个“奇葩”的变量名可能会逼疯一个程序员。 明天是奇葩变量名大赏! 注释注:以下素材均采集自网络先上场的是某企业机房的门牌: 我猜这个主任可能是个胡建人。举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice第二位选手来自国内大厂-- 阿里: 正因为这个报错信息中的UnionPay,导致隔壁银联的客服电话被打爆! 但实际上,这个开发想表白的意思是合并订单领取时的报错,但因为... “合并领取”的英文是“combined payment”,呈现这个问题是因为淘宝工程师不意识combined这个单词。自带混同性能的变量名 这是什么?乱码吗? 颁布正确答案: 这又是什么?菜谱吗? public String calculateTomAndJerryHappyTogetherTotalTimeAndReturnToThePreviousLevel(){}我认为你是段冗余代码: xxxxxx = "网络操作保护核心(主任室)" # 音讯详细信息我宁愿应用中文变量名C语言选手: int deit; //deit -> dateint riqi; //riqi -> 日期求求你们,放过我吧。 lv = 0x33FF33这位来自Python的选手的变量名至多让我脱了100根头发,直到我在下文看到red = 0xFF0033,我才晓得lv是指绿色! 求求学长不要应用拼音命名了!!!鄙人早就耳闻了拼音命名法,也不过如此! let JianCeNianDu = ...;let NongTianChanLiang = ...;let DiKuaiBinaMa = ...;let FeiLiaoHanShuiLv = ...;这样也能承受吧~ let jianceniandu = ...;let nongtianchanliang = ...;let dikuaibianma = ...;let feiliaohanshuilv = ...;当看到理论的代码: ...

September 25, 2023 · 1 min · jiezi

关于java:一个含不少免费额度和数据下载的IP地址来源查询工具

大家好,我是TJ君! 现在在国内经营的各种互联网利用都有接入IP起源显示的要求,当初相干API的供应商也很多。明天TJ刚好看到一个不错的,所以马上给大家举荐一下。 这款不错的产品名称为:IPInfo 产品个性该IP查问工具除了传统的提供地址地位之外,还有很多其余能力,具体的这里TJ君给大家整顿了一下,次要上面有这些: IP所在事实世界中的地理位置IP背地的公司信息,包含:公司名称、域名、公司类型等查找公司领有或经营的IP范畴检测暗藏用户IP的VPN、代理等IP与每个ASN相干域的详细信息IP地址上托管的域列表IP Whois信息查问检测挪动运营商的信息IP滥用信息API服务与收费额度从官网的价格页上能够看到,该工具提供了4种不同价格套餐: 不同套餐除了调用次数不同外,对于数据类型的查问范畴也不同,上面是不同套餐响应的数据丰盛水平: 能够看到该工具还提供了收费套餐,一共50000次/月的申请额度。对于很多刚起步的小产品,或者集体博客等独立产品来说,这个收费额度,基本上也够用了。刚好有这个需要的小伙伴,能够来试试。其余付费套餐,这里就不介绍了,感兴趣的小伙伴能够去价格页查看。 数据下载与收费子集另外,这块IP查问工具,不光提供API的查问形式,还提供数据库的下载,如果调用量很大的话,能够思考这个计划: 该计划会提供每日下载IP地理位置、IP范畴、运营商、公司等数据,用户能够保障拜访到最新、最精确的IP数据。 同时,对于个别用户来说,也能够下载它们的收费数据来应用: 最初,奉上该工具的官网地址:https://ipinfo.io/ ,感兴趣的小伙伴能够自行返回查看。 欢送关注公众号:TJ君,订阅每日举荐,理解更多效率工具、发现优质开源我的项目 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

September 25, 2023 · 1 min · jiezi

关于java:CAS是什么

乐观锁是将资源锁住,等一个之前取得锁的线程开释锁之后,下一个线程才能够 拜访。 而乐观锁采取了一种宽泛的态度,通过某种形式不加锁来解决资源,比方 通过给记录加 version 来获取数据,性能较乐观锁有很大的进步。 CAS 是 compare and swap 的缩写,即咱们所说的比拟和替换。 cas 是一种基于锁的操作,是乐观锁的一个典型代表。 CAS 操作蕴含三个操作数 —— 内存地位(V)、预期原值(A)和新值(B)。如果内存地址外面的值和 A 的值是一样的,那么就将内存外面的值更新成 B。 CAS 是通过有限循环来获取数据的,若果在第一轮循环中,a 线程获取地址外面的值 被 b 线程批改了,那么 a 线程须要自旋,到下次循环才有可能机会执行。 CAS 的会产生什么问题? 1.ABA问题 CAS须要在操作值的时候查看内存值是否发生变化,没有发生变化才会更新内存值。然而如果内存值原来是A,起初变成了B,而后又变成了A,那么CAS进行查看时会发现值没有发生变化,然而实际上是有变动的。 ABA问题的解决思路就是在变量后面增加版本号,每次变量更新的时候都把版本号加一,这样变动过程就从“A-B-A”变成了“1A-2B-3A”。 2、循环工夫长开销大。CAS操作如果长时间不胜利,会导致其始终自旋,给CPU带来十分大的开销。

September 24, 2023 · 1 min · jiezi

关于java:Java内存模型之happensbefore原则

Happens-Before 是一种可见性模型,也就是说,在多线程环境下。 本来因为指令重排序的存在会导致数据的可见性问题,也就是 A 线程批改某个共享变量 对 B 线程不可见。 因而,JMM 通过 Happens-Before 关系向开发人员提供逾越线程的内存可见性保障。 如果一个操作的执行后果对另外一个操作可见,那么这两个操作之间必然存在 Happens-Before 关系。 其次,Happens-Before 关系只是形容后果的可见性,并不示意指令执行的先后顺序, 也就是说 只有不对后果产生影响,依然容许指令的重排序。 happens-before准则定义如下: 1. 如果一个操作happens-before另一个操作,那么第一个操作的执行后果将对第二个操作可见,而且第一个操作的执行程序排在第二个操作之前。 2. 两个操作之间存在happens-before关系,并不意味着肯定要依照happens-before准则制订的程序来执行。如果重排序之后的执行后果与依照happens-before关系来执行的后果统一,那么这种重排序并不非法。 JMM中的happens-before准则: 程序秩序规定:一个线程中的每个操作, happens-before 这个线程中的任意后续操作;这个规定只对单线程无效,在多线程环境下无奈保障正确性。监视器锁规定:一个线程对于一个锁的开释锁操作, 肯定 happens-before 于后续线程对这个锁的加锁操作;volatile变量规定:对一个 volatile 润饰的变量的写肯定 happens-before 于任意后续对这个 volatile 变量的读操作;传递规定:如果A happens-before B,且B happens-before C,那么A happens-before C。线程启动规定:如果线程 A 执行操作 ThreadB.start(),那么线程 A 的 ThreadB.start()之前的操作 happens-before 线程 B 中的任意操作;在这样一个场景中,t1 线程启动之前对于 x=10 的赋值操作,t1 线程启动当前读取 x 的值肯定是 10线程终结规定(join 规定):如果线程 A 执行操作 ThreadB.join()并胜利返回,那么线程 B 中的任意操作 happens-before 于线程 A 从 ThreadB.join()操作胜利的返回。;(假设线程A在执行的过程中,通过制订ThreadB.join()期待线程B终止,那么线程B在终止之前对共享变量的批改在线程A期待返回后可见。) ...

September 24, 2023 · 1 min · jiezi

关于java:Spring-MVC-九Context层级基于配置

Context层级的问题,后面文章应该曾经说分明了。 只不过,后面文章是以注解形式举例说明的,通过配置形式怎么体现Context层级呢?有必要也说一下,毕竟当初很多我的项目都是基于xml配置实现的。 web.xml基于配置的Spring MVC的入口就是web.xml文件,毕竟web.xml是基于web的利用的先人入口...... <?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <!--1、启动Spring的容器 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>肯定要搞清楚的是,context-param配置是用来指定的Spring容器的配置文件所在门路的。必须是和ContextLoaderListener一起配合起作用的。ContextLoaderListener读取context-param的配置来实现Spring IoC容器的初始化的。 Spring IoC容器和Spring MVC的Servlet Web ApplicationContext容器不是必须要离开的,也能够配置为同一个容器。 比方以上配置不指定(不配置Spring IoC容器),也就是去掉contextConfigLocation以及ContextLoaderListener,让Spring MVC的容器担负起Spring IoC容器的职责,也是能够的。 web.xml上面持续配置spring MVC的xml文件所在门路,DispathcerServlet初始化的时候会读取。 <!--2、springmvc的前端控制器,拦挡所有申请 --> <servlet> <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>Spring-mvc.xml名字是能够在web.xml文件中指定的,不指定的话默认就是dispatcherServlet名-dispatcher.xml(须要读一下SpringMVC源码确认)。 如果你想要Spring IoC容器和Spring MvC的web applicationContext容器离开的话,就在Spring-mvc.xml文件中指定包扫描门路仅扫描controller,否则,全扫描即可。反之,Spring Ioc容器存在的话,配置文件的扫描门路也要排除掉Controller的扫描: <context:component-scan base-package="org.example.service"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>Servlet和根容器的关系下图高深莫测的阐明了两者之间的关系: Servlet容器寄存Controller、VIewResolver、HanderMapping等DispatcherServlet的相干对象,根容器能够寄存其余Service、Repositories等对象。 一个DispatcherServlet能够对应的有一个Servlet WebApplicationContext容器,一个Web利用能够有多个DispatcherServlet(这种利用其实比拟少见),所以一个利用能够有多个Servlet WebApplicationContext容器。然而个别状况下,即便有多个Servlet容器,一个利用也心愿只有一个根容器,以便在不同的Servlet容器之间共享根容器的对象。 根容器初始化过程xml配置文件的状况下,根容器要依附ContextLoaderListener来初始化。ContextLoaderListener是Spring MVC实现的ServletContextListener接口的实现类,ServletContextListener是Java Servlet的接口。Servlet规范约定,在Servlet容器初始化的过程中,会回调ServletContextListener接口的contextInitialized办法。 所以如果咱们在web.xml文件中配置了ContextLoaderListener,那么,Tomcat在Servlet容器初始化的过程中就会回调ContextLoaderListener的contextInitialized办法: @Override public void contextInitialized(ServletContextEvent event) { initWebApplicationContext(event.getServletContext()); }该办法会调用initWebApplicationContext办法,这个办法咱们在后面文章中其实曾经剖析过了,咱们再来看一下: ...

September 24, 2023 · 3 min · jiezi

关于java:封装全局异常处理

[TOC] 1 定义错误码类 能够定义各种错误码枚举,比方业务,零碎相干的报错信息 /** * 错误代码 * 错误码 * * @author leovany * @date 2023/09/23 */public enum ErrorCode { SUCCESS(0, "success", ""), ERROR_PARAMS(40000, "申请参数谬误", ""), ERROR_NULL(40001, "申请数据为空", ""), ERROR_LOGIN(40100, "未登录", ""), ERROR_NO_AUTH(41001, "无权限", ""), ERROR_SYSTEM(50000, "零碎外部异样", "") ; /** * 错误码ID */ private final int code; /** * 错误码信息 */ private final String message; /** * 错误码形容(详情) */ private final String description; ErrorCode(int code, String message, String description) { this.code = code; this.message = message; this.description = description; } public int getCode() { return code; } public String getMessage() { return message; } public String getDescription() { return description; }}2 定义业务异样类绝对于 java 的异样类,反对更多字段 ...

September 24, 2023 · 2 min · jiezi

关于java:Lock介绍

Lock介绍Lock是juc(java.util.concurrent)包上面的一个接口类,是作者Doug Lea定义的api标准,次要接口有 api 阐明 void lock() 获取锁。如果锁不可用,则出于线程调度目标,以后线程将被禁用,并处于休眠状态,直到获取锁为止。 void lockInterruptibly() throws InterruptedException除非以后线程被中断,否则获取锁。如果锁可用,则获取锁并立刻返回。如果锁不可用,则出于线程调度目标,以后线程将被禁用,并处于休眠状态,直到产生以下两种状况之一:锁被以后线程获取; 或者其余线程中断以后线程,反对中断获取锁。如果以后线程:在进入此办法时设置其中断状态; 或者获取锁时中断,反对中断获取锁,而后抛出InterruptedException并革除以后线程的中断状态。 boolean tryLock() 仅当调用时锁闲暇时才获取锁。如果锁可用,则获取锁并立刻返回 true 值。 如果锁不可用,则此办法将立刻返回 false 值。 boolean tryLock(long time, TimeUnit unit) throws InterruptedException 如果在给定的等待时间内锁是闲暇的并且以后线程没有被中断,则获取锁。如果锁可用,此办法立刻返回 true 值。 如果锁不可用,则出于线程调度目标,以后线程将被禁用,并处于休眠状态,直到产生以下三种状况之一:锁被以后线程获取; 或者其余线程中断以后线程,反对中断获取锁; 或者指定的等待时间已过如果获取了锁,则返回 true 值。如果以后线程:在进入此办法时设置其中断状态; 或者获取锁时中断,反对中断获取锁,而后抛出InterruptedException并革除以后线程的中断状态。如果指定的等待时间已过,则返回值 false。 如果工夫小于或等于零,则该办法基本不会期待。 void unlock() 开释锁 Condition newCondition() 返回绑定到此 Lock 实例的新 Condition 实例。在期待条件之前,以后线程必须持有锁。 对 Condition.await() 的调用将在期待之前主动开释锁,并在期待返回之前从新获取锁。 Condition介绍Condition也是juc包下的一个接口类,须要在线程持有Lock的状态下操作该接口下的办法,次要接口有 api 阐明 void await() throws InterruptedException 导致以后线程期待,直到收到信号或中断。与此条件关联的锁被主动开释,以后线程出于线程调度目标而被禁用,并处于休眠状态,直到产生以下四种状况之一:其余线程调用该Condition的signal办法,并且以后线程恰好被选为要唤醒的线程; 或者其余一些线程为此条件调用 signalAll 办法; 或者其余线程中断以后线程,反对线程挂起中断; 或者产生“虚伪唤醒”。在所有状况下,在此办法返回之前,以后线程必须从新获取与此条件关联的锁。 当线程返回时,保障持有该锁。如果以后线程:在进入此办法时设置其中断状态; 或者期待时被中断,反对线程挂起中断,而后抛出InterruptedException并革除以后线程的中断状态。 在第一种状况下,没有指定是否在开释锁之前进行中断测试。 void lockInterruptibly() throws InterruptedException除非以后线程被中断,否则获取锁。如果锁可用,则获取锁并立刻返回。如果锁不可用,则出于线程调度目标,以后线程将被禁用,并处于休眠状态,直到产生以下两种状况之一:锁被以后线程获取; 或者其余线程中断以后线程,反对中断获取锁。如果以后线程:在进入此办法时设置其中断状态; 或者获取锁时中断,反对中断获取锁,而后抛出InterruptedException并革除以后线程的中断状态。 void awaitUninterruptibly() 导致以后线程期待,直到收到信号。与此条件关联的锁被主动开释,以后线程出于线程调度目标而被禁用,并处于休眠状态,直到产生以下三种状况之一:其余线程调用该Condition的signal办法,并且以后线程恰好被选为要唤醒的线程; 或者其余一些线程为此条件调用 signalAll 办法; 或者产生“虚伪唤醒”。在所有状况下,在此办法返回之前,以后线程必须从新获取与此条件关联的锁。 当线程返回时,保障持有该锁。如果以后线程在进入该办法时设置了中断状态,或者在期待时被中断,它将持续期待,直到发出信号。 当它最终从此办法返回时,其中断状态仍将被设置。 long awaitNanos(long nanosTimeout) throws InterruptedException 使以后线程期待,直到收到信号或中断,或者指定的等待时间过来。与此条件关联的锁被主动开释,以后线程出于线程调度目标而被禁用,并处于休眠状态,直到产生以下五种状况之一:其余线程调用该Condition的signal办法,并且以后线程恰好被选为要唤醒的线程; 或者其余一些线程为此条件调用 signalAll 办法; 或者其余线程中断以后线程,反对线程挂起中断; 或者规定的等待时间已过; 或者产生“虚伪唤醒”。在所有状况下,在此办法返回之前,以后线程必须从新获取与此条件关联的锁。 当线程返回时,保障持有该锁。如果以后线程:在进入此办法时设置其中断状态; 或者期待时被中断,反对线程挂起中断。 boolean await(long time, TimeUnit unit) throws InterruptedException 使以后线程期待,直到收到信号或中断,或者指定的等待时间过来。 boolean awaitUntil(Date deadline) throws InterruptedException 导致以后线程期待,直到收到信号或中断,或者指定的截止工夫过来。与此条件关联的锁被主动开释,以后线程出于线程调度目标而被禁用,并处于休眠状态,直到产生以下五种状况之一:其余线程调用该Condition的signal办法,并且以后线程恰好被选为要唤醒的线程; 或者其余一些线程为此条件调用 signalAll 办法; 或者其余线程中断以后线程,反对线程挂起中断; 或者规定的期限已过; 或者产生“虚伪唤醒”。在所有状况下,在此办法返回之前,以后线程必须从新获取与此条件关联的锁。 当线程返回时,保障持有该锁。如果以后线程:在进入此办法时设置其中断状态; 或者期待时被中断,反对线程挂起中断。 void signal() 唤醒一个期待线程。如果有任何线程在此条件下期待,则抉择一个线程来唤醒。 该线程必须在从期待返回之前从新获取锁。 void signalAll() 唤醒所有期待线程。如果任何线程正在期待这种状况,那么它们都会被唤醒。 每个线程必须从新获取锁能力从期待返回。 作用Lock通过lock,trylock和unlock接口操作,能够保障在多线程环境下的代码块的同步执行,保障执行后果的正确性.通过Condition的await和signal,signallAll操作,保障同步代码块中的条件失去满足能力被执行实现.提醒代码如下: ...

September 24, 2023 · 6 min · jiezi

关于java:通用返回结果类ResultVO

1. 定义通用返回后果类 定义ResultVO类,作返回给前端的对象构造,次要有4个字段 code : 错误码data : 内容message : 音讯description : 具体形容import lombok.Data;import java.io.Serializable;/** * 通用返回后果类 * @param <T> */@Datapublic class ResultVO<T> implements Serializable { /** * 错误码 */ private int code; /** * 内容 */ private T data; /** * 音讯 */ private String message; /** * 形容 */ private String description; public ResultVO(int code, T data, String message, String description) { this.code = code; this.data = data; this.message = message; this.description = description; } public ResultVO(int code, T data) { this(code,data,"",""); } public ResultVO(int code, T data, String message) { this(code,data,message,""); } }2 工具类/** * 通用返回响应工具类 * * @author leovany * @date 2023/09/23 */public class ResultUtils { /** * 胜利 * * @param data 数据 * @return {@link ResultVO}<{@link T}> */ public static <T> ResultVO<T> success(T data) { return new ResultVO<T>(0, data, "success"); } /** * 谬误 * * @param code 错误码 * @param message 信息 * @param description 形容 * @return {@link ResultVO} */ public static ResultVO error(int code, String message, String description) { return new ResultVO<>(code, null, message, description); }}3 应用返回值用 ResultVO<XXX>封装胜利返回:ResultUtils.success(XX);失败失败:ResultUtils.error(code,message,description);@PostMapping("/login")public ResultVO<User> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) { String userAccount = userLoginRequest.getUserAccount(); String userPassword = userLoginRequest.getUserPassword(); // 参数校验 if (StringUtils.isAnyBlank(userAccount, userPassword)) { return ResultUtils.error(40000,"参数谬误","参数不能为空"); } // 从数据库查找用户 User user = userService.doLogin(userAccount, userPassword, request); return ResultUtils.success(user);}跟之前比照,代码更加优雅 ...

September 23, 2023 · 2 min · jiezi

关于java:谈谈你对volatile的理解

缓存不一致性问题为了解决缓存不一致性问题,通常来说有以下2种解决办法: 1)通过在总线加LOCK#锁的形式 2)通过缓存一致性协定 这2种形式都是硬件层面上提供的形式。 在晚期的CPU当中,是通过在总线上加LOCK#锁的模式来解决缓存不统一的问题。因为CPU和其余部件进行通信都是通过总线来进行的,如果对总线加LOCK#锁的话,也就是说阻塞了其余CPU对其余部件拜访(如内存),从而使得只能有一个CPU能应用这个变量的内存。比方如果一个线程在执行 i = i +1,如果在执行这段代码的过程中,在总线上收回了LCOK#锁的信号,那么只有期待这段代码齐全执行结束之后,其余CPU能力从变量i所在的内存读取变量,而后进行相应的操作。这样就解决了缓存不统一的问题。 然而下面的形式会有一个问题,因为在锁住总线期间,其余CPU无法访问内存,导致效率低下。 所以就呈现了缓存一致性协定。最闻名的就是Intel 的MESI协定,MESI协定保障了每个缓存中应用的共享变量的正本是统一的。它外围的思维是:当CPU写数据时,如果发现操作的变量是共享变量,即在其余CPU中也存在该变量的正本,会发出信号告诉其余CPU将该变量的缓存行置为有效状态,因而当其余CPU须要读取这个变量时,发现自己缓存中缓存该变量的缓存行是有效的,那么它就会从内存从新读取。 volatile的内存语义volatile能够保障线程可见性且提供了肯定的有序性,然而无奈保障原子性。在JVM底层volatile是采纳“内存屏障”来实现的。 1.volatile关键字的两层语义一旦一个共享变量(类的成员变量、类的动态成员变量)被volatile润饰之后,那么就具备了两层语义: 1)保障了不同线程对这个变量进行操作时的可见性,即一个线程批改了某个变量的值,这新值对其余线程来说是立刻可见的。 2)禁止进行指令重排序。 先看一段代码,如果线程1先执行,线程2后执行: //线程1boolean stop = false;while(!stop){    doSomething();} //线程2stop = true;这段代码是很典型的一段代码,很多人在中断线程时可能都会采纳这种标记方法。然而事实上,这段代码会齐全运行正确么?即肯定会将线程中断么?不肯定,兴许在大多数时候,这个代码可能把线程中断,然而也有可能会导致无奈中断线程(尽管这个可能性很小,然而只有一旦产生这种状况就会造成死循环了)。 上面解释一下这段代码为何有可能导致无奈中断线程。在后面曾经解释过,每个线程在运行过程中都有本人的工作内存,那么线程1在运行的时候,会将stop变量的值拷贝一份放在本人的工作内存当中。 那么当线程2更改了stop变量的值之后,然而还没来得及写入主存当中,线程2转去做其余事件了,那么线程1因为不晓得线程2对stop变量的更改,因而还会始终循环上来。 然而用volatile润饰之后就变得不一样了: 第一:应用volatile关键字会强制将批改的值立刻写入主存; 第二:应用volatile关键字的话,当线程2进行批改时,会导致线程1的工作内存中缓存变量stop的缓存行有效(反映到硬件层的话,就是CPU的L1或者L2缓存中对应的缓存行有效); 第三:因为线程1的工作内存中缓存变量stop的缓存行有效,所以线程1再次读取变量stop的值时会去主存读取。 那么在线程2批改stop值时(当然这里包含2个操作,批改线程2工作内存中的值,而后将批改后的值写入内存),会使得线程1的工作内存中缓存变量stop的缓存行有效,而后线程1读取时,发现自己的缓存行有效,它会期待缓存行对应的主存地址被更新之后,而后去对应的主存读取最新的值。 那么线程1读取到的就是最新的正确的值。 察看退出volatile关键字和没有退出volatile关键字时所生成的汇编代码发现,退出volatile关键字时,会多出一个lock前缀指令。lock前缀指令其实就相当于一个内存屏障。内存屏障是一组解决指令,用来实现对内存操作的程序限度。volatile的底层就是通过内存屏障来实现的。 2. volatile能保障有序性吗?在后面提到volatile关键字能禁止指令重排序,所以volatile能在肯定水平上保障有序性。 volatile关键字禁止指令重排序有两层意思: 1)当程序执行到volatile变量的读操作或者写操作时,在其后面的操作的更改必定全副曾经进行,且后果曾经对前面的操作可见;在其前面的操作必定还没有进行; 2)在进行指令优化时,不能将在对volatile变量拜访的语句放在其前面执行,也不能把volatile变量前面的语句放到其后面执行。 举个简略的例子: //x、y为非volatile变量//flag为volatile变量 x = 2;        //语句1y = 0;        //语句2flag = true;  //语句3x = 4;         //语句4y = -1;       //语句5因为flag变量为volatile变量,那么在进行指令重排序的过程的时候,不会将语句3放到语句1、语句2后面,也不会讲语句3放到语句4、语句5前面。然而要留神语句1和语句2的程序、语句4和语句5的程序是不作任何保障的。 并且volatile关键字能保障,执行到语句3时,语句1和语句2必然是执行结束了的,且语句1和语句2的执行后果对语句3、语句4、语句5是可见的。 3.volatile的原理和实现机制后面讲述了源于volatile关键字的一些应用,上面咱们来探讨一下volatile到底如何保障可见性和禁止指令重排序的。 上面这段话摘自《深刻了解Java虚拟机》: “察看退出volatile关键字和没有退出volatile关键字时所生成的汇编代码发现,退出volatile关键字时,会多出一个lock前缀指令” lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个性能: 1)它确保指令重排序时不会把其前面的指令排到内存屏障之前的地位,也不会把后面的指令排到内存屏障的前面;即在执行到内存屏障这句指令时,在它后面的操作曾经全副实现; 2)它会强制将对缓存的批改操作立刻写入主存; 3)如果是写操作,它会导致其余CPU中对应的缓存行有效。 应用volatile关键字的场景synchronized关键字是避免多个线程同时执行一段代码,那么就会很影响程序执行效率,而volatile关键字在某些状况下性能要优于synchronized,然而要留神volatile关键字是无奈代替synchronized关键字的,因为volatile关键字无奈保障操作的原子性。通常来说,应用volatile必须具备以下2个条件: 1)对变量的写操作不依赖于以后值 2)该变量没有蕴含在具备其余变量的不变式中 实际上,这些条件表明,能够被写入 volatile 变量的这些有效值独立于任何程序的状态,包含变量的以后状态。 ...

September 23, 2023 · 1 min · jiezi

关于java:Java多线程如何正确使用循环栅栏CyclicBarrier

前言本篇文章的代码示例已放到 github 上,Git地址为:advance(记录每一个学习过程),大家把代码下载下来之后,全局搜寻一些要害代码,即可找到该文章的源码。 大家感觉有用的话,麻烦点个star再走呗!应用场景设想一个这样的场景,咱们在打王者光荣/英雄联盟的时候,都会有一个匹配机制,须要10集体都加载实现后,大家能力一起进入游戏,不然会呈现大家进入游戏的工夫不统一的状况,这个时候就能够应用CyclicBarrier来实现。 基本原理应用CyclicBarrier的线程被叫做参与方,它的外部保护了一个显式锁。参与方只须要执行await()就能够参加期待,此时这些线程会被暂停。当最初一个线程执行await()办法后,其余被暂停的线程都会被唤醒,而最初一个线程不会被暂停。 罕用办法//结构器,定义参加的线程数CyclicBarrier cyclicBarrier = new CyclicBarrier(10);//结构器,能够传入跳栅后须要执行的线程public CyclicBarrier(int parties, Runnable barrierAction);//将屏障重置为其初始状态void reset()//进行期待int await()//进行期待,同时具备超时工夫public int await(long timeout, TimeUnit unit)应用示例定义玩家运行程序 public class CyclicBarrierRunnable implements Runnable{ private CyclicBarrier cyclicBarrier; private int number; public CyclicBarrierRunnable(CyclicBarrier cyclicBarrier, int number) { this.cyclicBarrier = cyclicBarrier; this.number = number; } @Override public void run() { System.out.println("玩家" + number + "号正在加载游戏..."); try { TimeUnit.SECONDS.sleep(2); cyclicBarrier.await(); } catch (Exception e) { System.out.println("线程执行呈现问题"); } System.out.println("玩家" + number + "号加载实现。"); }}定义主程序 ...

September 23, 2023 · 1 min · jiezi

关于java:Java多线程如何正确使用倒计时协调器CountDownLatch

前言本篇文章的代码示例已放到 github 上,Git地址为:advance(记录每一个学习过程),大家把代码下载下来之后,全局搜寻一些要害代码,即可找到该文章的源码。 大家感觉有用的话,麻烦点个star再走呗!应用场景想想一个这样的场景:我要开始吃饭,须要先满足几个先决条件: 进来买菜开始做饭把做好的饭端上桌只有满足这几个条件之后,我能力真正开始吃饭。同时,这里吃饭的人可能不止我一个人,或者还有我的爸爸妈妈等。 CountDownLatch能够用来实现一个或者多个(留神能够有多个)线程,期待其余线程齐全一组特定的操作后,才开始继续执行的操作,这些特定的操作被称作先决条件。 基本原理CountDownLatch外部有一个示意未实现的先决条件的计数器。当某个线程执行CountDownLatch.await()时,如果此时的计数器不为0,那么这个线程就会被阻塞掉。 每当其余线程执行CountDownLatch.countDown()时,这个计数器就会被减为0时,其余被阻塞的线程就会被主动唤醒,执行后续的操作。 罕用办法//结构器,定义计数器的初始值public CountDownLatch(int count)://阻塞式期待public void await()//超时主动唤醒式期待public boolean await(long timeout, TimeUnit unit)//计数器减1,若此时计数器为0,则期待的那些线程会被唤醒public void countDown()//获取以后计数器的值public long getCount()应用示例定义买菜的异步线程 public class MaiCaiThread implements Runnable{ private CountDownLatch countDownLatch; public MaiCaiThread(CountDownLatch countDownLatch) { this.countDownLatch = countDownLatch; } @Override public void run() { try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("出门买菜回来了"); countDownLatch.countDown(); }}定义做饭的异步线程 public class ZuoFanThread implements Runnable{ private CountDownLatch countDownLatch; public ZuoFanThread(CountDownLatch countDownLatch) { this.countDownLatch = countDownLatch; } @Override public void run() { try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("饭做好了"); countDownLatch.countDown(); }}定义主线程 ...

September 23, 2023 · 1 min · jiezi

关于java:Java多线程如何正确使用-Conditon-条件变量

前言本篇文章的代码示例已放到 github 上,Git地址为:advance(记录每一个学习过程),大家在我的项目介绍的援用目录外面即可找到对应文章的一个代码门路。 大家有任何问题,欢送大家在评论区留言,我会在看到后一一进行回复。 大家感觉有用的话,麻烦点个star再走呗!应用背景在介绍 Condtion 的应用场景之前,咱们先来思考这样的场景: 当咱们在执行某个办法之前,咱们取得了这个办法的锁,然而在执行过程中咱们发现某个条件不满足,想让办法暂停一会儿,等条件满足后再让这个办法继续执行。 针对下面的问题,咱们能够利用Object.wait()和notify()写出上面这样的代码: public synchronized void doSomething(){ //执行办法 if(条件不满足){ //线程期待 Object.wait(); } //条件此时满足,对象被唤醒,继续执行办法}然而,因为Object.wait()和notify()过于底层,并且无奈辨别是因为期待超时后唤醒还是被其余线程唤醒的问题,引入在JDK1.5后引入了java.util.concurrent.locks.Condition接口。 应用场景Condition接口作为Object.wait()/notify()的替代品,当咱们给某个办法加锁后,发现某个条件不满足,想让办法暂停一会儿,等条件满足后再让这个办法继续执行。这种时候,咱们就能够应用Condition接口。 罕用办法创立一个condition实例 为了让这个锁更不便取得,实例代码外面我将这个锁设为动态的 //定义一个锁public static final Lock reentrantLock = new ReentrantLock();//定义属于这个锁的条件变量public static final Condition condition = reentrantLock.newCondition();线程期待 void await() throws InterruptedException;线程非阻塞期待 boolean await(long time, TimeUnit unit)唤醒某个线程 condition.signal();唤醒所有线程 condition.signalAll();应用示例定义一个全局的标记位 public class GlobalSymbol { /** * 定义全局标记位 */ public static AtomicBoolean globalFlag = new AtomicBoolean(false);}主线程 public class Main { //定义一个锁 public static final Lock reentrantLock = new ReentrantLock(); //定义属于这个锁的条件变量 public static final Condition condition = reentrantLock.newCondition(); public static void main(String[] args) { //先启动一下线程 Thread thread = new Thread(new OtherThread()); thread.start(); //先加锁 reentrantLock.lock(); try { System.out.println("线程加锁胜利,正在执行相干代码"); while (!GlobalSymbol.globalFlag.get()){ System.out.println("当初条件还不满足,先期待"); condition.await(); } System.out.println("线程被唤醒,执行后续代码"); } catch (Exception e){ System.out.println("加锁解锁逻辑出现异常"); } finally { //在finally中开释锁 reentrantLock.unlock(); } System.out.println("程序完结"); }}子线程(用于唤醒主线程) ...

September 23, 2023 · 1 min · jiezi

关于java:页面跳转的两种方式转发和重定向区别及应用场景分析

作为一名java web开发的程序员,在应用servlet/jsp的时候,咱们必须要晓得实现页面跳转的两种形式的区别和分割:即转发和重定向的区别。 1、request.getRequestDispatcher().forward()办法,只能将申请转发给同一个WEB利用中的组件;而response.sendRedirect() 办法不仅能够重定向到以后应用程序中的其余资源,还能够重定向到同一个站点上的其余应用程序中的资源,甚至是应用相对URL重定向到其余站点的资源。 如果传递给response.sendRedirect()办法的绝对URL以“/”结尾,它是绝对于整个WEB站点的根目录;如果创立request.getRequestDispatcher()对象时指定的绝对URL以“/”结尾,它是绝对于以后WEB应用程序的根目录。 2、重定向拜访过程完结后,浏览器地址栏中显示的URL会产生扭转,由初始的URL地址变成重定向的指标URL;申请转发过程完结后,浏览器地址栏放弃初始的URL地址不变。 3、HttpServletResponse.sendRedirect办法对浏览器的申请间接作出响应,响应的后果就是通知浏览器去从新收回对另外一个URL的拜访申请,这个过程好比有个绰号叫“浏览器”的人写信找张三借钱,张三回信说没有钱,让“浏览器”去找李四借,并将李四当初的通信地址通知给了“浏览器”。于是,“浏览器”又按张三提供通信地址给李四写信借钱,李四收到信后就把钱汇给了“浏览器”。 由此可见,重定向的时候,“浏览器”一共收回了两封信和收到了两次回复,“浏览器”也晓得他借到的钱出自李四之手。 request.getRequestDispatcher().forward()办法在服务器端外部将申请转发给另外一个资源,浏览器只晓得收回了申请并失去了响应后果,并不知道在服务器程序外部产生了转发行为。这个过程好比绰号叫“浏览器”的人写信找张三借钱,张三没有钱,于是张三找李四借了一些钱,甚至还能够加上本人的一些钱,而后再将这些钱汇给了“浏览器”。 由此可见,转发的时候,“浏览器”只发 出了一封信和收到了一次回复,他只晓得从张三那里借到了钱,并不知道有一部分钱出自李四之手。 4、request.getRequestDispatcher().forward()办法的调用者与被调用者之间共享雷同的request对象和response对象,它们属于同一个拜访申请和响应过程; 而response.sendRedirect()办法调用者与被调用者应用各自的request对象和response对象,它们属于两个独立的拜访申请和响应过程。对于同一个WEB应用程序的外部资源之间的跳转,特地是跳转之前要对申请进行一些后期预处理,并要应用HttpServletRequest.setAttribute办法传递预处理后果,那就应该应用request.getRequestDispatcher().forward()办法。不同WEB应用程序之间的重定向,特地是要重定向到另外一个WEB站点上的资源的状况,都应该应用response.sendRedirect()办法。 5、无论是request.getRequestDispatcher().forward()办法,还是response.sendRedirect()办法,在调用它们之前,都不能有内容曾经被理论输入到了客户端。如果缓冲区中曾经有了一些内容,这些内容将被从缓冲区中。 转发和重定向的图解两种跳转取得对象的形式 //取得转发对象getRequestDispatcher()HttpServletRequest(httpServletRequest).getRequestDispatcherServletContext.getRequestDispatcher(); //取得重定向对象sendRedirect()HttpServletResponse(httpServletResponse).sendRedirect(); 转发和跳转的小结 1、转发应用的是getRequestDispatcher()办法;重定向应用的是sendRedirect(); 2、转发:浏览器URL的地址栏不变。重定向:浏览器URL的地址栏扭转; 3、转发是服务器行为,重定向是客户端行为; 4、转发是浏览器只做了一次拜访申请。重定向是浏览器做了至多两次的拜访申请; 5、转发2次跳转之间传输的信息不会失落,重定向2次跳转之间传输的信息会失落(request范畴)。转发和重定向的抉择 1、重定向的速度比转发慢,因为浏览器还得收回一个新的申请,如果在应用转发和重定向都无所谓的时候倡议应用转发。 2、因为转发只能拜访以后WEB的应用程序,所以不同WEB应用程序之间的拜访,特地是要拜访到另外一个WEB站点上的资源的状况,这个时候就只能应用重定向了。转发和重定向的利用场景 在下面我曾经提到了,转发是要比重定向快,因为重定向须要通过客户端,而转发没有。有时候,采纳重定向会更好,若须要重定向到另外一个内部网站,则无奈应用转发。另外,重定向还有一个利用场景:防止在用户从新加载页面时两次调用雷同的动作。 例如,当提交产品表单的时候,执行保留的办法将会被调用,并执行相应的动作;这在一个实在的应用程序中,很有可能将表单中的所有产品信息退出到数据库中。然而如果在提交表单后,从新加载页面,执行保留的办法就很有可能再次被调用。同样的产品信息就将可能再次被增加,为了防止这种状况,提交表单后,你能够将用户重定向到一个不同的页面,这样的话,这个网页任意从新加载都没有副作用; 然而,应用重定向不太不便的中央是,应用它无奈将值轻松地传递给指标页面。而采纳转发,则能够简略地将属性增加到Model,使得指标视图能够轻松拜访。因为重定向通过客户端,所以Model中的所有都会在重定向时失落。但侥幸的是,在Spring3.1版本当前,咱们能够通过Flash属性,解决重定向时传值失落的问题。 要应用Flash属性,必须在Spring MVC的配置文件中增加一个<annotation-driven/>。而后,还必须再办法上增加一个新的参数类型:org.springframework.web.servlet.mvc.support.RedirectAttributes。 如下所示: @RequestMapping(value="saveProduct",method=RequestMethod.POST)public String saveProduct(ProductForm productForm,RedirectAttributes redirectAttributes){ //执行产品保留的业务逻辑等 //传递参数 redirectAttributes.addFlashAttribute("message","The product is saved successfully"); //执行重定向 return "redirect:/……";} 版权申明:本文内容由互联网用户自发奉献,该文观点仅代表作者自己。本站仅提供信息存储空间服务,不领有所有权,不承当相干法律责任。如发现本站有涉嫌侵权/守法违规的内容, 请发送邮件至 举报,一经查实,本站将立即删除。

September 22, 2023 · 1 min · jiezi

关于java:Java线程的生命周期状态

Java线程的状态能够应用监控工具查看,也能够通过Thread.getState()调用获取。Thread.getState()的返回值类型是一个枚举类型(Enum)。Thread.State所定义的线程状态包含以下几种。 NEW:一个已创立未启动的线程处于该状态。因为一个线程实例只可能被启动一次,因而,一个线程只可能有一次处于该状态。RUNNABLE:该状态能够被看成一个复合状态。它包含两个子状态:READY和RUNNING。前者示意处于该状态的线程能够被线程调度器(Scheduler)进行调度而使之处于RUNNING状态。后者示意处于该状态的线程正在运行,即相应线程对象的run办法所对应的指令正在由处理器执行。执行Thread.yield()的线程,其状态可能会由RUNNING状态转换为READY。处于READY子状态的线程也被称为沉闷线程。BLOCKED:一个线程发动一个阻塞式I/O(Blocking I/O)操作后,或者申请一个由其余线程持有的独占资源(比方锁)时,相应的线程会处于该状态。处于BLOCKED状态的线程并不会占用处理器资源。当阻塞式I/O操作实现后,或者该线程取得了其申请的资源,该线程的状态又能够转换成RUNNABLE。WAITING:一个线程执行了某些特定办法后就会处于这种期待其余线程执行另外一些特定操作的状态。可能使其执行线程变更为WAITING状态的办法包含:Object.wait()、Thread.join()和LockSupport.park(Object)。可能使相应线程从WAITING变更为RUNNABLE的相应办法包含:Object.notify()/notifyAll()和LockSupport.unpark(Object)。TIMED_WAITING:该状态和WAITING状态相似,差异在于处于该状态的线程并非无限度地期待其余线程执行特定操作,而是处于带有工夫限度的期待状态。当其余线程没有在指定工夫内执行该线程所冀望的特定操作时,该线程的状态主动转换为RUNNABLE。TIERMINATED:曾经执行完结的线程处于该状态。因为一个线程实例只可能被启动一次,因而一个线程也只可能有一次处于该状态。Thread.run()失常返回或者因为抛出异样而提前终止都会导致相应线程处于该状态。

September 22, 2023 · 1 min · jiezi

关于java:如何提升Java项目质量代码是关键

对于编程,代码品质是一个极其重要的因素。无论是初学者还是资深开发者,都深知高质量代码的重要性,除了能够进步程序的可维护性,还能缩小谬误和问题的呈现。尤其在像Java这样受欢迎但难度较高的编程语言中,代码品质显得尤为突出。 要想写出高质量的Java代码,并不是一件容易的事件。你可能会遇到以下这些问题: • 代码格调不对立,导致可读性差• 代码逻辑不清晰,导致可维护性差• 代码没有正文或文档,导致可了解性差• 代码没有通过测试或审查,导致可靠性差 解决这些问题兴许看起来很难,但实际上有一些简略而实用的办法能够帮忙你成为Java代码的专家。有两种办法能够晋升Java代码的品质:一种是应用内部工具,另一种是造就外在的技巧。 外在工具外在工具指的是那些能够帮忙你查看、格式化、优化、测试、审查,甚至是间接生成Java函数级代码的工具或平台。这些工具能够让你省去很多反复繁琐的工作,进步开发效率和代码品质。例如: 动态代码剖析工具:例如FindBugs、PMD、Checkstyle等,能够查看代码中的潜在问题,例如未应用的变量、未解决的异样等。代码格式化工具:例如Google Java Format,能够主动将代码依照肯定的规定格式化,使其更易于浏览和保护。代码优化工具:例如JProfiler、VisualVM等,能够对Java代码进行性能剖析和优化,进步代码的效率和性能。单元测试框架:例如JUnit、TestNG等,能够编写和运行单元测试,确保代码的正确性和稳定性。代码审查工具:例如SonarQube、Crucible等,能够对代码进行审查和治理,确保代码的品质和规范性。你能够依据本人的需要和爱好抉择适宜本人的工具包,或者甚至本人开发一些工具包。而随着人工智能技术的倒退,市场上也曾经呈现了可能间接生成高质量Java函数的工具。 专一生成Java函数的AI生成器:FuncGPT(慧函数)作为全栈全自动软件开发工具飞算SoFlu软件机器人的一个重要组成部分反对所有类型函数创立。通过自然语言形容Java函数需要,实时生成高质量、高可读性的Java函数代码。生成代码可间接复制到IDEA,或一键导入Java全自动开发工具函数库。 在FuncGPT(慧函数)输出“冒泡算法”,失去的代码示例如下: package com.feisuanyz.function;import com.feisuanyz.flow.core.cmpt.annotation.function.MethodDesc;import com.feisuanyz.flow.core.cmpt.annotation.function.ParamDesc;public class BubbleSort { @MethodDesc(desc = "应用冒泡排序算法对给定的整数数组进行排序",params = {@ParamDesc(name = "nums", desc = "给定的整数数组"),})public static int[] bubbleSort(int[] nums) { if (nums == null) { // 查看数组是否为null throw new IllegalArgumentException("Array cannot be null"); // 抛出异样,数组不能为空 } int n = nums.length; for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { if (nums[j] > nums[j + 1]) { // 如果前一个元素大于后一个元素,则替换两个元素的地位 int temp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = temp; } } } return nums; // 返回排序后的数组 }}代码的品质如何?咱们将从代码组织、正文、异样解决、算法实现四个方面进行剖析,不难发现: ...

September 22, 2023 · 1 min · jiezi

关于java:Java集合练习斗地主发牌

思路创立一个HashMap汇合用于记录54张牌 {0=♥2, 1=♦2, 2=♣2, 3=♠2, 4=♥3, 5=♦3, ... , 50=♣A, 51=♠A, 52=大王, 53=小王}HashMap汇合的key值记录54张牌的程序创立一个一般ArrayList汇合用于记录54个数字,对应HashMap的54个Key值打乱整个ArrayList汇合(洗牌)创立四个TreeSet汇合(三个玩家汇合和底牌汇合),依照一人一张的程序别离将张牌的Key值存入三个玩家汇合中,最初三张非凡解决存入底牌汇合。 应用TreeSet汇合存牌的起因是因为TreeSet汇合自带排序功能。依据四个TreeSet汇合记录的Key值获取HashM汇合中映射的value值代码package com.collection;import java.util.*;public class PokerTest { public static void main(String[] args) { String decor[] = {"♥", "♦", "♣", "♠"}; String number[] = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}; HashMap<Integer, String> cards = new HashMap<Integer, String>(); int num = 0; for (int j = 0; j < number.length; j++) { for (int i = 0; i < decor.length; i++) { cards.put(num++, decor[i] + number[j]); } } cards.put(52, "大王"); cards.put(53, "小王"); ArrayList<Integer> cards_index = new ArrayList<>(); for (int i = 0; i < 54; i++) { cards_index.add(i); } Collections.shuffle(cards_index); TreeSet<Integer> player1 = new TreeSet<Integer>(); TreeSet<Integer> player2 = new TreeSet<Integer>(); TreeSet<Integer> player3 = new TreeSet<Integer>(); TreeSet<Integer> hole_cards = new TreeSet<Integer>(); for (int i = 0; i < cards_index.size(); i++) { if (i >= 51) { hole_cards.add(cards_index.get(i)); } else if (i % 3 == 0) { player1.add(cards_index.get(i)); } else if (i % 3 == 1) { player2.add(cards_index.get(i)); } else if (i % 3 == 2) { player3.add(cards_index.get(i)); } } System.out.println("Player1--------"); for (Integer i1 : player1) { System.out.print(cards.get(i1) + "\t"); } System.out.println("\nPlayer2--------"); for (Integer i2 : player2) { System.out.print(cards.get(i2) + "\t"); } System.out.println("\nPlayer3--------"); for (Integer i3 : player3) { System.out.print(cards.get(i3) + "\t"); } System.out.println("\nHole Cards--------"); for (Integer i4 : hole_cards) { System.out.print(cards.get(i4) + "\t"); } }}/* Player1-------- ♠2 ♣3 ♥4 ♣6 ♣7 ♠7 ♥8 ♠8 ♣9 ♥10 ♣10 ♣J ♥Q ♦Q ♥K ♥A ♦A Player2-------- ♦3 ♣4 ♦5 ♣5 ♥6 ♦6 ♠6 ♦7 ♣8 ♥9 ♦9 ♥J ♠J ♣K ♠A 大王 小王 Player3-------- ♥2 ♣2 ♥3 ♠3 ♦4 ♠4 ♥5 ♦8 ♠9 ♦10 ♠10 ♦J ♣Q ♠Q ♦K ♠K ♣A Hole Cards-------- ♦2 ♠5 ♥7 */

September 22, 2023 · 2 min · jiezi

关于java:深入探讨Java面试中内存泄漏如何识别预防和解决

引言在编写和保护Java应用程序时,内存透露是一个重要的问题,可能导致性能降落和不稳定性。本文将介绍内存透露的概念,为什么它在Java应用程序中如此重要,并明确本文的指标,即辨认、预防和解决内存透露问题。 内存透露的概念内存透露是指应用程序中调配的内存(通常是堆内存)在不再须要时未能正确开释。这些未开释的内存块会积攒,最终导致应用程序耗费过多的内存资源,甚至可能导致应用程序解体或变得十分迟缓。内存透露通常是因为不正确的对象援用治理或资源未正确开释而导致的。 为什么内存透露重要内存透露对Java应用程序的重要性不容忽视,因为它可能导致以下问题: 性能降落: 内存透露会导致应用程序占用更多内存,因而可能会导致性能降落,尤其是在长时间运行的应用程序中。不稳定性: 内存透露可能会导致内存耗尽,从而导致应用程序解体或变得不稳固。资源节约: 未开释的内存块是资源的节约,这些资源本应该可供其余局部或其余应用程序应用。难以调试: 内存透露通常难以追踪和调试,因为它们不会引发显著的谬误或异样,而是在应用程序长时间运行后才变得显著。辨认内存透露在本节中,咱们将探讨如何辨认内存透露的迹象和常见的内存透露模式。理解这些迹象和模式能够帮忙您更早地发现潜在的内存透露问题,从而缩小其影响。 内存透露的迹象以下是一些可能表明应用程序存在内存透露的迹象: 内存占用一直减少: 察看应用程序的内存占用状况。如果内存占用继续减少而不开释,可能存在内存透露。长时间运行后性能降落: 如果应用程序在运行一段时间后变得十分迟缓,这可能是内存透露的迹象。频繁的垃圾回收: 如果垃圾回收产生得十分频繁,尤其是Full GC,这可能表明内存透露正在导致过多的对象被保留。常见的内存透露模式以下是一些常见的内存透露模式,这些模式可能会导致内存透露问题: 对象援用未开释: 对象援用被保留在内存中,即便它们不再须要。这可能是因为汇合、缓存或动态变量等起因。资源未开释: 资源,如文件句柄、数据库连贯或网络连接,未正确敞开和开释。匿名外部类: 匿名外部类可能会隐式持有对外部类的援用,导致外部类的对象无奈被垃圾回收。监听器注册: 注册的事件监听器未正确登记,导致被监听对象无奈开释。线程透露: 启动的线程未正确敞开或治理,导致线程透露。监督工具和分析方法为了帮忙辨认内存透露问题,您能够应用以下监督工具和分析方法: 内存分析器: 应用Java内存分析器工具,如MAT(Eclipse Memory Analyzer Tool)或VisualVM,来查看堆内存中的对象和援用关系。这些工具能够帮忙您找到潜在的内存透露。日志记录: 在应用程序中增加具体的日志记录,以便跟踪对象的创立和销毁。剖析日志能够帮忙您理解对象的生命周期。性能监控工具: 使用性能监控工具来察看内存占用、垃圾回收频率和应用程序性能。这些工具能够帮忙您及早发现内存透露问题。预防内存透露预防内存透露是最佳策略,因为一旦内存透露产生,就须要破费更多的工夫来辨认和解决问题。以下是一些预防内存透露的最佳实际,包含良好的对象援用治理和资源开释。 1. 良好的对象援用治理内存透露通常与对象援用的不正确治理无关。以下是一些良好的对象援用治理实际: 弱援用和软援用: 对于临时性的对象援用,能够思考应用Java中的弱援用(Weak Reference)或软援用(Soft Reference)。这些援用类型会在内存不足时被垃圾回收器更容易地回收。及时清理援用: 当对象不再须要时,确保清理对该对象的援用,以便垃圾回收器能够正确回收它们。防止动态汇合: 防止在动态变量中存储对象援用,因为它们在整个应用程序的生命周期内都不会开释。应用局部变量: 在办法外部应用局部变量来存储长期对象援用,办法完结时,这些援用会主动被销毁。2. 资源开释另一个常见的内存透露起因是未正确开释资源,如文件句柄、数据库连贯或网络连接。以下是一些资源开释的最佳实际: 应用try-with-resources: 如果您应用Java 7或更高版本,能够应用try-with-resources语句来确保资源在应用后被正确敞开。例如,应用try-with-resources来管理文件IO:try (FileInputStream fis = new FileInputStream("file.txt")) { // 解决文件内容} catch (IOException e) { // 解决异样}手动敞开资源: 对于不反对try-with-resources的资源,如数据库连贯,请确保在不再须要时手动敞开它们,通常在finally块中进行。Connection connection = null;try { connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password"); // 应用连贯执行数据库操作} catch (SQLException e) { // 解决异样} finally { if (connection != null) { try { connection.close(); } catch (SQLException e) { // 解决异样 } }}3. 垃圾回收器的帮忙Java的垃圾回收器负责回收不再应用的内存。尽管它们通常可能正确处理内存治理,但在某些状况下,您能够利用垃圾回收器的帮忙来缩小内存透露的危险。例如,应用弱援用和软援用能够让垃圾回收器更容易地回收这些对象。 ...

September 22, 2023 · 2 min · jiezi

关于java:Java-21的StringBuilder和StringBuffer新增了一个repeat方法

发现Java 21的StringBuilder和StringBuffer中多了repeat办法: /** * @throws IllegalArgumentException {@inheritDoc} * * @since 21 */ @Override public StringBuilder repeat(int codePoint, int count) { super.repeat(codePoint, count); return this; } /** * @throws IllegalArgumentException {@inheritDoc} * * @since 21 */ @Override public StringBuilder repeat(CharSequence cs, int count) { super.repeat(cs, count); return this; }依据名字猜猜是干嘛的?试试上面的代码: var sb = new StringBuilder().repeat("*", 10);System.out.println(sb);最初会输入: **********另一个repeat办法第一个参数是codePoint,指得应该是UniCode字符集中的codePoint,所以这个办法的repeat是针对UniCode字符的。一时间仿佛想不到什么特地大的用户,就想到能够用来快捷的构建一些文本类的分隔符?你感觉还有其余什么妙用吗?一起聊聊~ 如果您学习过程中如遇艰难?能够退出咱们超高品质的技术交换群,参加交换与探讨,更好的学习与提高!另外,不要走开,关注我!继续更新Java新个性专栏! 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

September 22, 2023 · 1 min · jiezi