关于java:支付宝一面多线程事务怎么回滚说用-Transactional-可以回去等通知了

背景介绍1,最近有一个大数据量插入的操作入库的业务场景,须要先做一些其余批改操作,而后在执行插入操作,因为插入数据可能会很多,用到多线程去拆分数据并行处理来进步响应工夫,如果有一个线程执行失败,则全副回滚。 2,在spring中能够应用@Transactional注解去管制事务,使出现异常时会进行回滚,在多线程中,这个注解则不会失效,如果主线程须要先执行一些批改数据库的操作,当子线程在进行解决出现异常时,主线程批改的数据则不会回滚,导致数据谬误。 3,上面用一个简略示例演示多线程事务。 专用的类和办法/** * 均匀拆分list办法. * @param source * @param n * @param <T> * @return */public static <T> List<List<T>> averageAssign(List<T> source,int n){ List<List<T>> result=new ArrayList<List<T>>(); int remaider=source.size()%n; int number=source.size()/n; int offset=0;//偏移量 for(int i=0;i<n;i++){ List<T> value=null; if(remaider>0){ value=source.subList(i*number+offset, (i+1)*number+offset+1); remaider--; offset++; }else{ value=source.subList(i*number+offset, (i+1)*number+offset); } result.add(value); } return result;}/** 线程池配置 * @version V1.0 */public class ExecutorConfig { private static int maxPoolSize = Runtime.getRuntime().availableProcessors(); private volatile static ExecutorService executorService; public static ExecutorService getThreadPool() { if (executorService == null){ synchronized (ExecutorConfig.class){ if (executorService == null){ executorService = newThreadPool(); } } } return executorService; } private static ExecutorService newThreadPool(){ int queueSize = 500; int corePool = Math.min(5, maxPoolSize); return new ThreadPoolExecutor(corePool, maxPoolSize, 10000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(queueSize),new ThreadPoolExecutor.AbortPolicy()); } private ExecutorConfig(){}}/** 获取sqlSession * @author 86182 * @version V1.0 */@Componentpublic class SqlContext { @Resource private SqlSessionTemplate sqlSessionTemplate; public SqlSession getSqlSession(){ SqlSessionFactory sqlSessionFactory = sqlSessionTemplate.getSqlSessionFactory(); return sqlSessionFactory.openSession(); }}举荐一个 Spring Boot 基础教程及实战示例:https://github.com/javastacks/spring-boot-best-practice ...

September 22, 2023 · 3 min · jiezi

关于java:redis缓存击穿

缓存击穿是指在应用缓存的零碎中,当某个热门的数据过期(或被移除),而此时有大量的申请同时拜访该数据,导致这些申请都须要去数据库或其余数据源中从新获取数据,从而导致数据库负载剧增,零碎性能降落。Redis缓存击穿是指这种问题产生在Redis缓存中。 特色:数据热度高:某些数据被频繁拜访,但缓存过期后须要从新生成。大量申请同时达到:在数据过期的霎时,有大量申请同时拜访这个数据。数据库负载激增:大量的申请导致数据库查问负载急剧回升。解决办法: 1、应用互斥锁:在缓存生效的霎时,只容许一个申请去从新加载数据,其余申请期待加载实现。这能够防止大量申请同时击穿缓存。 2、 设置短暂的随机过期工夫:在设置缓存数据的过期工夫时,能够引入一些随机性,使得不同申请的缓存过期工夫略有差别,这样能够防止大量的申请在同一时刻拜访数据库。 3、事后加载热门数据:在系统启动时或定期工作中,事后加载一些热门数据到缓存,防止冷启动时的缓存击穿问题。 4、应用缓存穿透爱护策略:在缓存生效时,能够设置一个空值或占位符到缓存中,这样能够防止对数据库的不必要查问。 5、应用备份缓存:如果主缓存(比方Redis)呈现击穿问题,能够思考应用备份缓存(如内存数据库或本地缓存)来存储热门数据,以升高数据库负载。 6、 数据预热:定期或在低峰期,事后加载一些热门数据到缓存中,以确保这些数据不会因为过期而导致缓存击穿。 7、应用CDN或缓存层:对于动态资源或频繁申请的数据,能够应用CDN或其余缓存层,将申请在凑近用户的地位缓存,加重后端服务器的压力。 缓存击穿是一个常见的性能问题,因而在设计缓存零碎时须要思考这种状况,并采取相应的预防和解决措施,以确保零碎的稳定性和性能。不同的利用场景可能须要不同的解决方案,具体的办法能够依据理论状况进行抉择和组合。

September 21, 2023 · 1 min · jiezi

关于java:如何出色的进行自我介绍

细节决定成败,面试实质上是“自我采购”的过程。如何在短短的几十分钟内感动面试官,素来都不是一个简略的问题。 所以怎么收场?怎么让面试官对我产生趣味?十分要害。 所以,接下来,咱们就来聊聊,如何进行自我介绍?如果一收场就让面试官对你印象粗浅。 先说论断好的自我介绍,肯定要讲明确以下 4 点: 你是谁?你会啥?你做过啥?为什么要你? 1.你是谁?自我介绍的第一步肯定是自报家门,例如,我是张三,2015 年毕业于西安电子科技大学,毕业之后始终从事 Java 开发的工作,做过 XXX 公司的高级研发工程师,也很快乐加入贵公司的面试。 校招版本:我是李四,24 届学生,目前就读于西安电子科技大学,硕士学历,就读的业余是软件工程(非软件相干业余就不要介绍你的业余了),很荣幸加入贵公司的面试。2.你会啥?技术岗位,最看重的就是你的技术能力,所以这一步肯定要好好筹备,并具体的介绍你会的技能。 要做好这一步,在面试前肯定要查阅应聘公司的岗位要求和应用的技术栈,这样你就能针对性的进行技能介绍了。而当面试官看到一个应聘者的技术栈,和本人公司的技术栈齐全匹配的时候,你的面试成功率就大幅晋升了。 例如,你能够这样介绍。我会的技能是并发编程、MySQL、Redis、Spring、Spring MVC、Spring Boot、Spring Cloud Alibaba Nacos、Sentinel、Seata、Spring Cloud Gateway、Skywalking、RabbitMQ 等技术栈。 3.你做过啥?学以致用很重要,尤其是校招,你下面说你会,那么怎么证实你真的会你说的哪些技术呢? 你能够这样介绍,我应用 Spring Cloud Alibaba 全家桶 + Spring Cloud Gateway + MySQL + Redis + RabbitMQ 总共做过 3 个我的项目,其中有两个我的项目我曾经写在简历上了,等会您有任何对于我的项目或技能点的问题都能够问我。 4.为什么要你?后面三点是陈说,而最初这点就要升华了,这也是你进行“自我吹嘘”最初的机会,也是感动面试官最要害的时刻,“峰终定律”就是讲这个事。 为什么要你?就是你要介绍本人的成就和长处。 例如,你取得过和工作岗位相干的奖项,比方 ACM 二等奖,国赛三等奖,蓝桥杯省一等相干奖项都能够说。 如果切实没有奖项能够说,那就介绍你的长处,例如(但不限)以下这些: 我做事比拟专一:例如,去图书馆看书,常常遗记吃中午饭,等到肚子饿的不行了,低头一看表曾经下午 3 点了。我自学能力比拟强:例如,整个微服务,像 Spring Cloud Alibaba 整个技术栈,我只用了 2 周的工夫就全副学会了,并且能用它开发一个 Java 我的项目,期间遇到的所有问题,我都能自行解决。我喜爱编程:例如,您能够看我的 GitHub 我每天都有练习和提交代码。小结自我介绍,看似简略,实则须要用心筹备。面试实质上是“自我采购”,如何在短短的几十分钟内感动面试官,并不是一个简略的问题,因而你须要做好充沛的筹备。而好的自我介绍,须要讲清楚四个点:你是谁?你会啥?你做过啥?为什么是你? 本文已收录到我的面试小站 www.javacn.site,其中蕴含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、音讯队列等模块。

September 21, 2023 · 1 min · jiezi

关于java:Java-集合练习

汇合提供一种存储空间可变的存储模型,存储的数据容量能够依据需要产生扭转 Collect接口Collection汇合,首先是一个接口。是Java中所有汇合的总接口。一个 Collection接口代表一组 Object类,即 Collection接口的元素。Java不提供间接继承自Collection接口的类,只提供继承于的子接口(如List接口和set接口)。Collection接口存储一组不惟一,无序的对象。List 接口List接口是一个有序的Collection接口,应用此接口可能准确的管制每个元素插入的地位,可能通过索引(元素在List中地位,相似于数组的下标)来拜访List中的元素,第一个元素的索引为 0,而且容许有雷同的元素。List 接口存储一组不惟一,有序(插入程序)的对象。实现类ArrayListArrayList汇合的底层逻辑是数组。该类也是实现了List接口,实现了可变大小的数组,随机拜访和遍历元素时,提供更好的性能。该类也是非同步的,在多线程的状况下不要应用。ArrayList 增长以后长度的50%,插入删除效率低。 代码package com.collection;import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class Collection { public static void main(String[] args) { //ArrayList<E> 一般的可变长的数组 元素有序,可反复 List arrayList = new ArrayList(); arrayList.add(true); arrayList.add(123); arrayList.add(123.456); arrayList.add("String"); arrayList.add(true); arrayList.add(123); arrayList.add(123.456); arrayList.add("String"); //汇合间接打印 System.out.print("----ArrayList汇合间接打印----" + "\n" + arrayList + "\t"); //一般for循环打印 System.out.println("\n----ArrayList汇合一般for循环打印----"); for (int i = 0; i < arrayList.size(); i++) { System.out.print(arrayList.get(i)+"\t"); } //迭代器打印 Iterator iterator = arrayList.iterator(); System.out.println("\n----ArrayList汇合迭代器打印----"); while (iterator.hasNext()) { System.out.print(iterator.next() + "\t"); } //for-each循环打印 System.out.println("\n----ArrayList汇合for-each循环打印----"); for (Object i : arrayList) { System.out.print(i+"\t"); } /* ----ArrayList汇合间接打印---- [true, 123, 123.456, String, true, 123, 123.456, String] ----ArrayList汇合一般for循环打印---- true 123 123.456 String true 123 123.456 String ----ArrayList汇合迭代器打印---- true 123 123.456 String true 123 123.456 String ----ArrayList汇合for-each循环打印---- true 123 123.456 String true 123 123.456 String */ }}办法形容add()将元素插入到指定地位的 arraylist 中addAll()增加汇合中的所有元素到 arraylist 中clear()删除 arraylist 中的所有元素clone()复制一份 arraylistcontains()判断元素是否在 arraylistget()通过索引值获取 arraylist 中的元素indexOf()返回 arraylist 中元素的索引值removeAll()删除存在于指定汇合中的 arraylist 里的所有元素remove()删除 arraylist 里的单个元素LinkedList该类实现了List接口,容许有null(空)元素。次要用于创立链表数据结构,LinkedList 查找效率低。该类没有同步办法,如果多个线程同时拜访一个List,则必须本人实现拜访同步,解决办法就是在创立List时候结构一个同步的List。例如: ...

September 21, 2023 · 7 min · jiezi

关于java:手把手教你5种方法实现Java判断字符串是否为数字

办法一:用JAVA自带的函数 public static boolean isNumeric(String str){for (int i = str.length();--i>=0;){if (!Character.isDigit(str.charAt(i))){return false;}}return true;}办法一通过遍历字符串的每一个字符,并应用Character.isDigit()函数查看每一个字符是否是数字。如果字符串中所有字符都是数字,那么这个办法就会返回true。然而,如果字符串中含有非数字字符,它就会立刻返回false。这种办法简洁明了,但可能过于严格,因为它认为像"123 "这样的字符串(开端蕴含空格)不是数字。 办法二: /** 判断是否为整数* @param str 传入的字符串* @return 是整数返回true,否则返回false*/public static boolean isInteger(String str) {Pattern pattern = Pattern.compile("^[-\+]?[\d]*$");return pattern.matcher(str).matches();}办法二通过正则表达式查看字符串是否只蕴含数字。它匹配所有以正则表达式["^[-+]?[\d]*$"]开始的字符串,这个正则表达式示意字符串的开始能够是正负号,前面追随任意数量的数字。然而,它认为像"123 "这样的字符串是整数,而实际上" "不是数字的一部分。 办法三: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 StringNumberChecker { @MethodDesc(desc = "判断字符串是否为数字",params = {@ParamDesc(name = "str", desc = "要判断的字符串"),})public static boolean isNumeric(String str) { if (str == null || str.isEmpty()) { // 查看字符串是否为空 return false; } try { Double.parseDouble(str); // 应用Double.parseDouble()办法尝试将字符串转换为double return true; // 转换胜利,字符串是数字 } catch (NumberFormatException e) { return false; // 转换失败,字符串不是数字 } }}办法三应用Double.parseDouble()办法尝试将字符串转换为双精度浮点数。转换胜利,阐明字符串是数字,返回true;转换失败,阐明字符串不是数字,返回false。 ...

September 21, 2023 · 1 min · jiezi

关于java:Java-21-新特性Record-Patterns

Record Patterns 第一次公布预览是在JDK 19、随后又在JDK 20中进行了欠缺。当初,Java 21开始正式推出该个性优化。上面咱们通过一个例子来了解这个新个性。 record Point(int x, int y) {}static void printSum(Object obj) { if (obj instanceof Point p) { int x = p.x(); int y = p.y(); System.out.println(x+y); }}上述代码中定义了一个名为Point的record类(Java 16中的新个性),如果咱们想要获取、操作或者打印Point中的x和y的话。就不得不先实现类型判断和类型转换。所以,这里为了实现x+y总共须要4行代码。而在Java 21之后,只须要2行代码就能实现: static void printSum(Object obj) { if (obj instanceof Point(int x, int y)) { System.out.println(x+y); }}能够看到,类型判断、类型转换、record值的构造都零打碎敲了,所以代码量失去了简化。 嵌套record的解构假如有上面一组嵌套的record构造(WindowFrame中蕴含了Point和Size): record Size(int width, int height) { }record Point(int x, int y) { }record WindowFrame(Point origin, Size size) { }这个时候,如果想要拜访WindowFrame中Size的height,依据之前案例的了解,咱们能够这样写: ...

September 21, 2023 · 1 min · jiezi

关于java:Java内存模型CPU和缓存一致性问题

CPU和缓存一致性咱们应该都晓得,计算机在执行程序的时候,每条指令都是在CPU中执行的,而执行的时候,又免不了要和数据打交道。而计算机下面的数据,是寄存在主存当中的,也就是计算机的物理内存。 刚开始,还相安无事的,然而随着CPU技术的倒退,CPU的执行速度越来越快。而因为内存的技术并没有太大的变动,所以从内存中读取和写入数据的过程和CPU的执行速度比起来差距就会越来越大,这就导致CPU每次操作内存都要消耗很多等待时间。 可是,不能因为内存的读写速度慢,就不倒退CPU技术了吧,总不能让内存成为计算机解决的瓶颈吧。 所以,人们想进去了一个好的方法,就是在CPU和内存之间减少高速缓存。缓存的概念大家都晓得,就是保留一份数据拷贝。他的特点是速度快,内存小,并且低廉。 那么,程序的执行过程就变成了: 当程序在运行过程中,会将运算须要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就能够间接从它的高速缓存读取数据和向其中写入数据,当运算完结之后,再将高速缓存中的数据刷新到主存当中。 而随着CPU能力的一直晋升,一层缓存就缓缓的无奈满足要求了,就逐步的衍生出多级缓存。 依照数据读取程序和与CPU联合的严密水平,CPU缓存能够分为一级缓存(L1),二级缓存(L2),局部高端CPU还具备三级缓存(L3),每一级缓存中所贮存的全副数据都是下一级缓存的一部分。 这三种缓存的技术难度和制作老本是绝对递加的,所以其容量也是绝对递增的。 那么,在有了多级缓存之后,程序的执行就变成了: 当CPU要读取一个数据时,首先从一级缓存中查找,如果没有找到再从二级缓存中查找,如果还是没有就从三级缓存或内存中查找。 单核CPU只含有一套L1,L2,L3缓存; 如果CPU含有多个外围,即多核CPU,则每个外围都含有一套L1(甚至和L2)缓存,而共享L3(或者和L2)缓存。 随着计算机能力一直晋升,开始反对多线程。那么问题就来了。咱们别离来剖析下单线程、多线程在单核CPU、多核CPU中的影响。 单线程。cpu外围的缓存只被一个线程拜访。缓存独占,不会呈现拜访抵触等问题。 单核CPU,多线程。过程中的多个线程会同时拜访过程中的共享数据,CPU将某块内存加载到缓存后,不同线程在拜访雷同的物理地址的时候,都会映射到雷同的缓存地位,这样即便产生线程的切换,缓存依然不会生效。但因为任何时刻只能有一个线程在执行,因而不会呈现缓存拜访抵触。 多核CPU,多线程。每个核都至多有一个L1 缓存。多个线程拜访过程中的某个共享内存,且这多个线程别离在不同的外围上执行,则每个外围都会在各自的caehe中保留一份共享内存的缓冲。因为多核是能够并行的,可能会呈现多个线程同时写各自的缓存的状况,而各自的cache之间的数据就有可能不同。 在CPU和主存之间减少缓存,在多线程场景下就可能存在缓存一致性问题,也就是说,在多核CPU中,每个核的本人的缓存中,对于同一个数据的缓存内容可能不统一。 处理器优化和指令重排下面提到在在CPU和主存之间减少缓存,在多线程场景下会存在缓存一致性问题。除了这种状况,还有一种硬件问题也比拟重要。那就是为了使处理器外部的运算单元可能尽量的被充分利用,处理器可能会对输出代码进行乱序执行解决。这就是处理器优化。 除了当初很多风行的处理器会对代码进行优化乱序解决,很多编程语言的编译器也会有相似的优化,比方Java虚拟机的即时编译器(JIT)也会做指令重排。 可想而知,如果任由处理器优化和编译器对指令重排的话,就可能导致各种各样的问题。 并发编程的问题原子性是指在一个操作中就是cpu不能够在中途暂停而后再调度,既不被中断操作,要么执行实现,要么就不执行。 可见性是指当多个线程拜访同一个变量时,一个线程批改了这个变量的值,其余线程可能立刻看失去批改的值。 有序性即程序执行的程序依照代码的先后顺序执行。 缓存一致性问题其实就是可见性问题。而处理器优化是能够导致原子性问题的。指令重排即会导致有序性问题。

September 20, 2023 · 1 min · jiezi

关于java:Java21的新特性

Java语言个性系列Java5的新个性Java6的新个性Java7的新个性Java8的新个性Java9的新个性Java10的新个性Java11的新个性Java12的新个性Java13的新个性Java14的新个性Java15的新个性Java16的新个性Java17的新个性Java18的新个性Java19的新个性Java20的新个性Java21的新个性Java22的新个性序本文次要讲述一下Java21的新个性 版本号java -versionopenjdk version "21" 2023-09-19OpenJDK Runtime Environment (build 21+35-2513)OpenJDK 64-Bit Server VM (build 21+35-2513, mixed mode, sharing)从version信息能够看出是build 21+35个性列表JEP 430: String Templates (Preview)在java21之前,字符串拼接或者字符串与表达式组合次要是用StringBuilder、String::format、java.text.MessageFormat,不过可读性都不是太好,java21引入了StringTemplate(java.lang.StringTemplate)来解决这个问题。 @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)public interface StringTemplate { List<String> fragments(); List<Object> values(); default String interpolate() { return StringTemplate.interpolate(fragments(), values()); } default <R, E extends Throwable> R process(Processor<? extends R, ? extends E> processor) throws E { Objects.requireNonNull(processor, "processor should not be null"); return processor.process(this); } static String interpolate(List<String> fragments, List<?> values) { Objects.requireNonNull(fragments, "fragments must not be null"); Objects.requireNonNull(values, "values must not be null"); int fragmentsSize = fragments.size(); int valuesSize = values.size(); if (fragmentsSize != valuesSize + 1) { throw new IllegalArgumentException("fragments must have one more element than values"); } JavaTemplateAccess JTA = SharedSecrets.getJavaTemplateAccess(); return JTA.interpolate(fragments, values); } Processor<String, RuntimeException> STR = StringTemplate::interpolate; Processor<StringTemplate, RuntimeException> RAW = st -> st; @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) @FunctionalInterface public interface Processor<R, E extends Throwable> { R process(StringTemplate stringTemplate) throws E; static <T> Processor<T, RuntimeException> of(Function<? super StringTemplate, ? extends T> process) { return process::apply; } @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) public sealed interface Linkage permits FormatProcessor { MethodHandle linkage(List<String> fragments, MethodType type); } }}StringTemplate是个接口,它定义了fragments、values、interpolate、process办法,同时提供了interpolate、process办法的默认实现;同时内置了两个processor,别离是STR和RAW,他们的区别在于RAW能够获取到StringTemplate类型,STR则是StringTemplate执行了interpolate办法之后的后果,取得到的是最终后果String;其根本语法就是用\{}来蕴含变量或者表达式 ...

September 20, 2023 · 13 min · jiezi

关于java:延迟队列技术的选择

在咱们日常生活中,咱们能够发现:在淘宝、京东等购物平台高低单,超过肯定工夫未付款,订单会主动勾销。打车的时候,在规定工夫没有车主接单,平台会勾销你的单并揭示你临时没有车主接单。点外卖的时候,如果商家在10分钟还没接单,就会主动勾销订单。收快递的时候,如果咱们没有点确认收货,在一段时间后程序会主动实现订单。在平台实现订单后,如果咱们没有在规定工夫评论商品,会主动默认买家不评论。.......这时,咱们能够想想为什么要这样做?因为这样能够保障商品的库存能够开释给其他人购买,你能够不必始终期待打车却得不到回复,你能够及时换一家店点到外卖。那么这些状况都是如何实现的呢?这时咱们能够看看这个图,来看看音讯提早是如何解决的:当用户发送一个音讯申请给服务器后盾的时候,服务器会检测这条音讯是否须要进行延时解决,如果须要就放入到延时队列中,由延时工作检测器进行检测和解决,对于不须要进行延时解决的工作,服务器会立马对音讯进行解决,并把解决后的后果返会给用户。对于在延时工作检测器外部的话,有查问提早工作和执行延时工作两个职能,工作检测器会先去延时工作队列进行队列中信息读取,判断以后队列中哪些工作曾经工夫到期并将曾经到期的工作输入执行(设置一个定时工作)。这时,咱们能够想一想在Redis的数据结构中有哪些能进行工夫设置标记的命令?是不是想到的 zset 这个命令,具备去重有序(分数排序)的性能。没错,你想对了呀!咱们能够应用 zset(sortedset)这个命令,用设置好的工夫戳作为score进行排序,应用 zadd score1 value1 ....命令就能够始终往内存中生产音讯。再利用 zrangebysocre 查问符合条件的所有待处理的工作,通过循环执行队列工作即可。也能够通过 zrangebyscore key min max withscores limit 0 1 查问最早的一条工作,来进行生产。总的来说,你能够通过以下两种形式来实现((^▽^)如果你想到其余办法,也能够通知我下呀~):应用zrangebyscore来查问以后延时队列中所有工作,找出所有须要进行解决的延时工作,在顺次进行操作。查找以后最早的一条工作,通过score值来判断工作执行的时候是否大于了以后零碎的时候,比如说:最早的工作执行工夫在3点,零碎工夫在2点58分),示意这个应该须要立马被执行啦,工夫快到了(冲冲冲,他来了他来了,他带着死神的步调来了)。咱们能够想一想Redis来实现延时队列有何劣势呢?其实,Redis用来进行实现延时队列是具备这些劣势的:Redis zset反对高性能的 score 排序。Redis是在内存上进行操作的,速度十分快。Redis能够搭建集群,当音讯很多时候,咱们能够用集群来进步音讯解决的速度,进步可用性。Redis具备长久化机制,当呈现故障的时候,能够通过AOF和RDB形式来对数据进行复原,保障了数据的可靠性这时候,会有小伙伴问了还有没有其余实现延时队列的形式呀!emmm....当然有的,只有想不到的没有做不到。搜寻Java知音,回复“后端面试”,送你一份面试宝典.pdf办法一:在MQ中咱们能够对Queue设置 x-expires 过期工夫或者对 Message设置超时工夫x-message-ttl。(这里要留神下:延时雷同的音讯咱们要扔到同一个队列中,对于每一个延时要建设一个与之对应的队列—这是因为MQ的过期检测是惰性检测的。)办法二:咱们能够用RabbitMQ的插件rabbitmq-delayed-message-exchange插件来实现延时队列。达到可投递工夫时并将其通过 x-delayed-type 类型标记的交换机类型投递至指标队列。rocketmq在发送延时音讯时,是先把音讯依照延迟时间段发送到指定的队列中(把延时时间段雷同的音讯放到同一个队列中,保障了音讯解决的程序性,能够让同一个队列中音讯延时工夫是雷同的,整个RocketMQ中延时音讯时依照递增程序排序,保障信息处理的先后顺序性。)。之后,通过一个定时器来轮询解决这些队列里的信息,判断是否到期。对于到期的音讯会发送到相应的解决队列中,进行解决。留神 :目前RocketMQ只反对特定的延时时间段,1s,5s,10s,...2h,不能反对任意时间段的延时设置。有趣味的小伙伴能够去理解下它是相干常识呀~Kafka基于工夫轮自定义了一个用于实现提早性能的定时器(SystemTimer),Kafka中的工夫轮(TimingWheel)是一个存储定时工作的环形队列,能够进行相干的延时队列设置。Netty也有基于工夫轮算法来实现延时队列。Netty在构建延时队列次要用HashedWheelTimer,HashedWheelTimer底层数据结构是应用DelayedQueue,采纳工夫轮的算法来实现。Java中有自带的DelayQueue数据类型,咱们能够用这个来实现延时队列。DelayQueue是封装了一个PriorityQueue(优先队列),在向DelayQueue队列中增加元素时,会给元素一个Delay(延迟时间)作为排序条件,队列中最小的元素会优先放在队首,对于队列中的元素只有到了Delay工夫才容许从队列中取出。这种实现形式是数据保留在内存中,可能面临数据失落的状况,同时它是无奈反对分布式系统的。

September 20, 2023 · 1 min · jiezi

关于java:一键实现冒泡排序算法代码质量有保障

近年来,深度学习和神经语言模型作为进步开发人员生产力的伎俩, 尤其是2022年11月30日,ChatGPT这一景象级热点得出横空出世,在寰球范畴内造成了热烈的探讨,其中对于自动化代码生成和其它软件工程方面受到了极大的关注。 软件开发过程涵盖了各种代码生成工作,包含代码主动生成、代码翻译和程序交融。受到预训练神经语言模型在不同自然语言解决(NLP)工作中的杰出体现的启发,这些预训练技术最近曾经被利用于大规模代码语料库中,用以自动化代码生成工作。 只管预训练代码生成模型获得了很大停顿,它们仍受自然语言解决的自监督掩码语言建模(MLM)的影响,往往难以确保所生成代码的语法和性能的正确性。之前的钻研曾经表明,这些模型生成的代码中高达70%可能是无奈编译的。早前有钻研表明, ChatGPT在 对 517 个 Stack Overflow 网站上的问题的答复中 52% 的答复是谬误的,77% 是简短的。 那么代码生成,除了ChatGPT,开发人员是否还有其余抉择?为了解决开发人员对高质量代码的需要,本文将以国产的函数AI生成器FuncGPT(慧函数)为例,通过“冒泡排序算法”为大家展现一个秒级生“拿来即用”代码的诞生,以帮忙开发人员进步开发效率。 以下是通过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 20, 2023 · 1 min · jiezi

关于java:末流院校24届秋招逆袭之路

几年前,我在看新三国时,有一段记忆粗浅的话,司马懿获胜之后说:“我挥剑只有一次,却磨了十几年”。但万万没想到的是,这句话在几年后的明天,在我的师傅身上应验了。 事件是这样的,我师傅是往年 24 届的学生,他在往年 7.4 号找到我,说本人马上就要秋招找工作了,但当初技术还没学好,并发编程、JVM 根本不怎么会,而且框架也不是很纯熟,本人十分的焦虑不晓得该怎么办。 并且他还有一个致命的问题,他的学校十分好,是某某某学院,全国 800 所高校排名里,每年都没有他们学校的身影。所以他放心本人,一是没有机会,二是有机会了,本人也把握不住,所以十分的焦虑。 事件的转折于是,我就给他做了一对一的学习打算和辅导,依据他目前的状况,划分每个阶段的学习工作,再把每个阶段的工作划分成以天为单位的小工作,让他每天学完给我打卡,每个阶段学完之后再去做评测,评测实现之后查漏补缺,再开始下一阶段的学习。 就这样日复一日,周而复始,他每天也十分认真的实现学习工作,甚至每天都能超预期的实现工作,给你看看他学习打卡的截图:之后的日子,他跟着我学完体系课、之后又上了我的面试突击课,而后到了该投递简历的时候,我给他辅导简历,激励他多投简历。 他也很杰出,每次给他说的事件他都能保质保量超预期的实现,而后投了一段时间之后,忽然有一天来了一个面试的机会。 首次面试前的缓和 充分准备后的释怀因为所有面试题我都给他讲过,所以面着面着自信就上来了: 复试之后的焦虑 最终拿到 Offer 的欣慰圆满成功,秋招只面试了一家,就顺利的拿到了意向书,签订了正式的 Offer,天然是无比开心的: 小结人生没有白走的路,每一步都算数!即便学校不好,即便后期学的不好,只有你有信心、只有你肯致力、只有你能遇到真心帮你的人,所有都还来得及,所有都还有心愿。 人生是一场漫长的马拉松,拼的不是终点,而是保持和耐力,只有不轻言放弃,生存处处有惊喜。 加油吧,铁子们。 本文已收录到我的面试小站 www.javacn.site,其中蕴含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、音讯队列等模块。

September 20, 2023 · 1 min · jiezi

关于java:Spring-Boot虚拟线程与Webflux在JWT验证和MySQL查询上的性能比较

早上看到一篇对于Spring Boot虚构线程和Webflux性能比照的文章,感觉还不错。内容较长,我就不翻译了,抓重点给大家介绍一下这篇文章的核心内容,不便大家疾速浏览。 测试场景作者采纳了一个尽可能贴近事实操作的场景: 从受权头信息中提取JWT验证JWT并从中提取用户的Email应用用户的Email去MySQL里执行查问返回用户记录测试技术这里要比照的两个核心技术点是: 带有虚构线程的Spring Boot:这不是一个跑在传统物理线程上的Spring Boot利用,而是跑在虚构线程上的。这些轻量级线程简化了开发、保护和调试高吞吐量并发应用程序的简单工作。尽管虚构线程依然在底层操作系统线程上运行,但它们带来了显着的效率改良。当虚构线程遇到阻塞 I/O 操作时,Java 运行时会临时挂起它,从而开释关联的操作系统线程来为其余虚构线程提供服务。这个优雅的解决方案优化了资源分配并加强了整体应用程序响应能力。Spring Boot Webflux:Spring Boot WebFlux是Spring生态系统中的反应式编程框架,它利用Project Reactor库来实现非阻塞、事件驱动的编程。所以,它特地适宜须要高并发和低提早的应用程序。依附反应式办法,它容许开发人员无效地解决大量并发申请,同时依然提供与各种数据源和通信协议集成的灵活性。不论是Webflux还是虚构线程,这两个都是为了提供程序的高并发能力而生,那么谁更胜一筹呢?上面一起看看具体的测试。 测试环境运行环境与工具 一台16G内存的MacBook Pro M1Java 20Spring Boot 3.1.3启用预览模式,以取得虚构线程的弱小能力依赖的第三方库:jjwt、mysql-connector-java测试工具:Bombardier数据库:MySQL数据筹备 在Bombardier中筹备100000个JWT列表,用来从中随机选取JWT,并将其放入HTTP申请的受权信息中。在MySQL中创立一个users表,表构造如下:mysql> desc users;+--------+--------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+--------+--------------+------+-----+---------+-------+| email | varchar(255) | NO | PRI | NULL | || first | varchar(255) | YES | | NULL | || last | varchar(255) | YES | | NULL | || city | varchar(255) | YES | | NULL | || county | varchar(255) | YES | | NULL | || age | int | YES | | NULL | |+--------+--------------+------+-----+---------+-------+6 rows in set (0.00 sec)为users表筹备100000条用户数据测试代码带虚构线程的Spring Boot程序application.properties配置文件: ...

September 20, 2023 · 2 min · jiezi

关于java:Java-21-新特性switch的模式匹配

在之前的Java 17新个性中,咱们介绍过对于JEP 406: switch的模式匹配,但过后还只是对于此内容的首个预览版本。之后在JDK 18、JDK 19、JDK 20中又都进行了更新和欠缺。现在,在JDK 21中,该个性失去了最终确定!上面,咱们就再正式学习一下该性能! 在以往的switch语句中,对于case中的类型匹配限度是很多的。比方上面这个例子中的Map中可能存储了不同类型的对象,咱们要判断的时候,就只能依附if-else来实现。 Map<String, Object> data = new HashMap<>();data.put("key1", "aaa");data.put("key2", 111);if (data.get("key1") instanceof String s) { log.info(s);}if (data.get("key") instanceof String s) { log.info(s);} else if (data.get("key") instanceof Double s) { log.info(s);} else if (data.get("key") instanceof Integer s) { log.info(s);}当初开始,这样的类型判断关系,就能够简化为如下的switch代码: switch (data.get("key1")) { case String s -> log.info(s); case Double d -> log.info(d.toString()); case Integer i -> log.info(i.toString()); default -> log.info("");}这个性能还是十分有用的,尤其是存在一些形象封装的时候,可能存在一些父子、兄弟等关系类的时候,为了判断是什么类型,就不必写很多if来解决了,代码简洁度能够失去进一步的优化。 对于下面的例子,还没有降级到Java 17的用户,还波及两个两头知识点,倡议能够补充学习一下:第一个是Java 16中的instance of加强;第二个是switch中应用Lambda的加强。如果您学习过程中如遇艰难?能够退出咱们超高品质的技术交换群,参加交换与探讨,更好的学习与提高! ...

September 20, 2023 · 1 min · jiezi

关于java:Spring-Boot虚拟线程与Webflux在JWT验证和MySQL查询上的性能比较

早上看到一篇对于Spring Boot虚构线程和Webflux性能比照的文章,感觉还不错。内容较长,我就不翻译了,抓重点给大家介绍一下这篇文章的核心内容,不便大家疾速浏览。 测试场景作者采纳了一个尽可能贴近事实操作的场景: 从受权头信息中提取JWT验证JWT并从中提取用户的Email应用用户的Email去MySQL里执行查问返回用户记录测试技术这里要比照的两个核心技术点是: 带有虚构线程的Spring Boot:这不是一个跑在传统物理线程上的Spring Boot利用,而是跑在虚构线程上的。这些轻量级线程简化了开发、保护和调试高吞吐量并发应用程序的简单工作。尽管虚构线程依然在底层操作系统线程上运行,但它们带来了显着的效率改良。当虚构线程遇到阻塞 I/O 操作时,Java 运行时会临时挂起它,从而开释关联的操作系统线程来为其余虚构线程提供服务。这个优雅的解决方案优化了资源分配并加强了整体应用程序响应能力。Spring Boot Webflux:Spring Boot WebFlux是Spring生态系统中的反应式编程框架,它利用Project Reactor库来实现非阻塞、事件驱动的编程。所以,它特地适宜须要高并发和低提早的应用程序。依附反应式办法,它容许开发人员无效地解决大量并发申请,同时依然提供与各种数据源和通信协议集成的灵活性。不论是Webflux还是虚构线程,这两个都是为了提供程序的高并发能力而生,那么谁更胜一筹呢?上面一起看看具体的测试。 测试环境运行环境与工具 一台16G内存的MacBook Pro M1Java 20Spring Boot 3.1.3启用预览模式,以取得虚构线程的弱小能力依赖的第三方库:jjwt、mysql-connector-java测试工具:Bombardier数据库:MySQL数据筹备 在Bombardier中筹备100000个JWT列表,用来从中随机选取JWT,并将其放入HTTP申请的受权信息中。在MySQL中创立一个users表,表构造如下:mysql> desc users;+--------+--------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+--------+--------------+------+-----+---------+-------+| email | varchar(255) | NO | PRI | NULL | || first | varchar(255) | YES | | NULL | || last | varchar(255) | YES | | NULL | || city | varchar(255) | YES | | NULL | || county | varchar(255) | YES | | NULL | || age | int | YES | | NULL | |+--------+--------------+------+-----+---------+-------+6 rows in set (0.00 sec)为users表筹备100000条用户数据测试代码带虚构线程的Spring Boot程序application.properties配置文件: ...

September 20, 2023 · 2 min · jiezi

关于java:ArraysasList使用指南

Arrays.asList() 是一个 Java 的静态方法,它能够把一个数组或者多个参数转换成一个 List 汇合。这个办法能够作为数组和汇合之间的桥梁,不便咱们应用汇合的一些办法和个性。本文将介绍 Arrays.asList() 的语法、利用场景、坑点和总结。 语法利用场景坑点总结语法Arrays.asList() 的语法格局如下: public static <T> List<T> asList(T... a)这个办法承受一个泛型参数 T,示意数组或者参数的类型。T 必须是一个援用类型,不能是一个根本类型,例如 int, double, char 等。如果传入一个根本类型的数组,Arrays.asList() 会把它当作一个 Object 类型的元素,而不是把它的每个元素当作 Object 类型。这样就会导致返回的 List 只有一个元素,就是原始数组自身。 Arrays.asList() 返回的 List 是一个 Arrays 类的外部类,它持有一个对原始数组的援用。这意味着对 List 的批改会反映到数组上,反之亦然。然而,这个 List 的大小是固定的,不能进行减少或者删除的操作,否则会抛出 UnsupportedOperationException 异样。 Arrays.asList() 返回的 List 是可序列化的,并且实现了 RandomAccess 接口,示意它反对随机拜访。 利用场景Arrays.asList() 能够用在以下几种场景中: 当咱们须要创立一个不须要扭转大小或者内容的 List 汇合时,咱们能够应用 Arrays.asList() 来疾速地初始化一些元素。例如:// 应用 Arrays.asList() 创立一个不可变的 ListList<String> list = Arrays.asList("a", "b", "c");System.out.println(list); // [a, b, c]当咱们须要创立一个空的或者单元素的 List 汇合时,咱们能够应用 Arrays.asList() 来简化代码。例如:// 应用 Arrays.asList() 创立一个不可变的空 ListList<String> emptyList = Arrays.asList();System.out.println(emptyList); // []// 应用 Arrays.asList() 创立一个不可变的单元素 ListList<String> singletonList = Arrays.asList("a");System.out.println(singletonList); // [a]当咱们须要从一个数组或者其余汇合类创立一个不可变的 List 汇合时,咱们能够应用 Arrays.asList() 来不便地转换。例如:// 应用 Arrays.asList() 从数组创立一个不可变的 ListString[] array = {"a", "b", "c"};List<String> listFromArray = Arrays.asList(array);System.out.println(listFromArray); // [a, b, c]// 应用 Arrays.asList() 从其余汇合类创立一个不可变的 ListSet<String> set = new HashSet<>();set.add("a");set.add("b");set.add("c");List<String> listFromSet = Arrays.asList(set.toArray(new String[0]));System.out.println(listFromSet); // [a, b, c]当咱们须要应用一些汇合类的办法或者个性时,咱们能够应用 Arrays.asList() 来把数组转换成汇合。例如:// 应用 Arrays.asList() 把数组转换成汇合,并应用 Collections 类的办法String[] array = {"a", "b", "c"};List<String> list = Arrays.asList(array);Collections.sort(list); // 对汇合进行排序System.out.println(list); // [a, b, c]Collections.reverse(list); // 对汇合进行反转System.out.println(list); // [c, b, a]Collections.shuffle(list); // 对汇合进行随机打乱System.out.println(list); // [b, a, c] 或者其余随机程序// 应用 Arrays.asList() 把数组转换成汇合,并应用 Stream APIString[] array = {"a", "b", "c"};List<String> list = Arrays.asList(array);list.stream().forEach(System.out::println); // 对汇合进行遍历并打印每个元素list.stream().map(String::toUpperCase).forEach(System.out::println); // 对汇合进行映射并打印每个元素的大写模式list.stream().filter(s -> s.startsWith("a")).forEach(System.out::println); // 对汇合进行过滤并打印以 a 结尾的元素坑点Arrays.asList() 也有一些坑点,须要留神以下几点: ...

September 19, 2023 · 2 min · jiezi

关于java:亚马逊-CodeWhisperer-初体验

1、CodeWhisperer 介绍CodeWhisperer 是亚马逊出品的一款基于机器学习的通用代码生成器,可实时提供代码倡议。相似 Cursor 和 Github Copilot 编码工具。 官网:https://aws.amazon.com/cn/codewhisperer/?trk=cndc-detail 在编写代码时,它会主动依据您现有的代码和正文生成倡议。从单行代码倡议到残缺的函数,它可为您提供各种大小和范畴的个性化倡议。CodeWhisperer 还能够扫描您的代码以突出显示和定义平安问题。 亚马逊云科技开发者社区为开发者们提供寰球的开发技术资源。这里有技术文档、开发案例、技术专栏、培训视频、流动与比赛等。帮忙中国开发者对接世界最前沿技术,观点,和我的项目,并将中国优良开发者或技术举荐给寰球云社区。如果你还没有关注/珍藏,看到这里请肯定不要匆匆划过,点这里让它成为你的技术宝库!CodeWhisperer 目前已反对近15种变种语言:Python、Java、JavaScript、TypeScript、C#、Go、Rust、PHP、Ruby、 Kotlin、C、C++、Shell 脚本、SQL 和 Scala,以及支流的 IDE 开发工具:包含 VS Code、IntelliJ IDEA 和 Amazon Cloud9。 CodeWhisperer 仅针对个人用户收费,企业用户须要订阅应用。除了不限量的代码倡议以外,还提供了每月 50 次的代码平安扫描,比方你写了破绽,它能主动帮你发现。 2、CodeWhisperer 装置我是用的 IDEA,所以以 IDEA2022 装置为例: 在 IDEA 中关上配置窗口,抉择 Plugins,搜寻"Amazon Toolkit",点击Install,点击 OK 按钮装置完之后重启 IDEA关上 Amazon Toolkit 视图(菜单 View/Tool Windows/Amazon Toolkit),点击"Developer Tools"tab 页面,抉择“CodeWhisperer/Start"弹出的窗口中抉择“Use a personal email to sign up and sign in with Amazon Builder ID",点击“Connect”按钮在弹出的窗口中,抉择“Open and Copy Code”此时会在浏览器中关上⼀个页面,按 ctrl-v 粘贴 code 值,点击“Next“输⼊邮箱地址,点击"Next",输⼊名字,点击“Next”,CodeWhisperer会向邮箱中发送⼀个验证码关上邮箱,能够看到验证码,复制验证码,粘贴到输入框,点击“Verify”按钮设置明码,点击“Create Amazon Builder ID“在最初⼀个页面中点击“Allow”按钮呈现如下提醒后,即示意注册 Amazon builder ID 胜利 ...

September 19, 2023 · 1 min · jiezi

关于java:spring配置

什么是 JavaConfig? Spring JavaConfig 是 Spring 社区的产品,它提供了配置 Spring IoC 容器的纯 Java 办法。因而它有助于防止应用 XML 配置。应用 JavaConfig 的长处在于:(1)面向对象的配置。因为配置被定义为 JavaConfig 中的类,因而用户能够充分利用 Java 中的面向对象性能。一个配置类能够继承另一个,重写它的@Bean 办法等。(2)缩小或打消 XML 配置。基于依赖注入准则的外化配置的益处已被证实。但是,许多开发人员不心愿在 XML 和 Java 之间来回切换。JavaConfig 为开发人员提供了一种纯 Java 办法来配置与 XML 配置概念类似的 Spring 容器。从技术角度来讲,只应用 JavaConfig 配置类来配置容器是可行的,但实际上很多人认为将 JavaConfig 与 XML 混合匹配是现实的。(3)类型平安和重构敌对。JavaConfig 提供了一种类型平安的办法来配置Spring 容器。因为 Java 5.0 对泛型的反对,当初能够按类型而不是按名称检索bean,不须要任何强制转换或基于字符串的查找。Spring Boot 主动配置原理是什么? 注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是主动配置的外围,@EnableAutoConfiguration 给容器导入 META-INF/spring.factories 里定义的主动配置类。筛选无效的主动配置类。每一个主动配置类联合对应的 xxxProperties.java 读取配置文件进行主动配置性能你如何了解 Spring Boot 配置加载程序? 在 Spring Boot 外面,能够应用以下几种形式来加载配置。1)properties 文件;2)YAML 文件;3)零碎环境变量;4)命令行参数;等等……什么是 YAML? YAML 是一种人类可读的数据序列化语言。它通常用于配置文件。与属性文件相比,如果咱们想要在配置文件中增加简单的属性,YAML 文件就更加结构化,而且更少混同。能够看出 YAML 具备分层配置数据。YAML 配置的劣势在哪里 ? YAML 当初能够算是十分风行的一种配置文件格式了,无论是前端还是后端,都能够见到 YAML 配置。那么 YAML 配置和传统的 properties 配置相比到底有哪些劣势呢? ...

September 19, 2023 · 1 min · jiezi

关于java:Spring-Boot-Disruptor-实现消息队列告诉你什么叫快什么叫高效

01、背景工作中遇到我的项目应用Disruptor做音讯队列,对你没看错,不是Kafka,也不是rabbitmq;Disruptor有个最大的长处就是快,还有一点它是开源的哦,上面做个简略的记录. 02、Disruptor介绍Disruptor 是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的提早问题(在性能测试中发现居然与I/O操作处于同样的数量级)。基于 Disruptor 开发的零碎单线程能撑持每秒 600 万订单,2010 年在 QCon 演讲后,取得了业界关注。Disruptor是一个开源的Java框架,它被设计用于在生产者—消费者(producer-consumer problem,简称PCP)问题上取得尽量高的吞吐量(TPS)和尽量低的提早。从性能上来看,Disruptor 是实现了“队列”的性能,而且是一个有界队列。那么它的利用场景天然就是“生产者-消费者”模型的利用场合了。Disruptor是LMAX在线交易平台的要害组成部分,LMAX平台应用该框架对订单处理速度能达到600万TPS,除金融畛域之外,其余个别的利用中都能够用到Disruptor,它能够带来显著的性能晋升。其实Disruptor与其说是一个框架,不如说是一种设计思路,这个设计思路对于存在“并发、缓冲区、生产者—消费者模型、事务处理”这些元素的程序来说,Disruptor提出了一种大幅晋升性能(TPS)的计划。Disruptor的github主页:https://github.com/LMAX-Exchange/disruptor03、Disruptor 的外围概念先从理解 Disruptor 的外围概念开始,来理解它是如何运作的。上面介绍的概念模型,既是畛域对象,也是映射到代码实现上的外围对象。 04、Ring Buffer如其名,环形的缓冲区。已经 RingBuffer 是 Disruptor 中的最次要的对象,但从3.0版本开始,其职责被简化为仅仅负责对通过 Disruptor 进行替换的数据(事件)进行存储和更新。在一些更高级的利用场景中,Ring Buffer 能够由用户的自定义实现来齐全代替。 05、Sequence Disruptor通过程序递增的序号来编号治理通过其进行替换的数据(事件),对数据(事件)的处理过程总是沿着序号一一递增解决。一个 Sequence 用于跟踪标识某个特定的事件处理者( RingBuffer/Consumer )的解决进度。 尽管一个 AtomicLong 也能够用于标识进度,但定义 Sequence 来负责该问题还有另一个目标,那就是避免不同的 Sequence 之间的CPU缓存伪共享(Flase Sharing)问题。(注:这是 Disruptor 实现高性能的关键点之一,网上对于伪共享问题的介绍曾经车载斗量,在此不再赘述)。 06、SequencerSequencer 是 Disruptor 的真正外围。此接口有两个实现类 SingleProducerSequencer、MultiProducerSequencer ,它们定义在生产者和消费者之间疾速、正确地传递数据的并发算法。 07、Sequence Barrier用于放弃对RingBuffer的 main published Sequence 和Consumer依赖的其它Consumer的 Sequence 的援用。Sequence Barrier 还定义了决定 Consumer 是否还有可解决的事件的逻辑。 08、Wait Strategy定义 Consumer 如何进行期待下一个事件的策略。(注:Disruptor 定义了多种不同的策略,针对不同的场景,提供了不一样的性能体现) 09、Event在 Disruptor 的语义中,生产者和消费者之间进行替换的数据被称为事件(Event)。它不是一个被 Disruptor 定义的特定类型,而是由 Disruptor 的使用者定义并指定。 ...

September 19, 2023 · 3 min · jiezi

关于java:micamqtt-224-发布简单易用的-java-mqtt

一、简介mica-mqtt 基于 java aio 实现的简略、低提早、高性能 的 mqtt 物联网开源组件。 mica-mqtt 更加易于集成到已有服务和二次开发,升高自研物联网平台开发成本。 二、性能反对 MQTT v3.1、v3.1.1 以及 v5.0 协定。反对 websocket mqtt 子协定(反对 mqtt.js)。反对 http rest api,http api 文档详见。反对 MQTT client 客户端。反对 MQTT server 服务端。反对 MQTT client、server 共享订阅反对(捐助VIP版采纳 topic 树存储,跟 topic 数无关,百万 topic 性能仍旧)。反对 MQTT 遗嘱音讯。反对 MQTT 保留音讯。反对自定义音讯(mq)解决转发实现集群。MQTT 客户端 阿里云 mqtt 连贯 demo。反对 GraalVM 编译老本机可执行程序。反对 Spring boot 我的项目疾速接入(mica-mqtt-spring-boot-starter)。mica-mqtt-spring-boot-starter 反对对接 Prometheus + Grafana。基于 redis pub/sub 实现集群,详见 mica-mqtt-broker 模块。三、应用场景物联网(云端 mqtt broker)物联网(边缘端音讯通信)群组类 IM音讯推送简略、易用的 mqtt client 客户端四、更新记录v2.2.4 - 2023-09-02 合并去年开源之夏的服务端共享订阅和欠缺。 优化 topic 测验 雷同 clientId 订阅雷同 匹配 topic 应该取最大的qos gitee #I7WWPN共享订阅mica-mqtt 反对两种共享订阅形式: ...

September 19, 2023 · 3 min · jiezi

关于java:Java并发Map的面试指南线程安全数据结构的奥秘

简介在计算机软件开发的世界里,多线程编程是一个重要且令人兴奋的畛域。然而,与其引人入胜的后劲相伴而来的是复杂性和挑战,其中之一就是解决共享数据。当多个线程同时拜访和批改共享数据时,很容易呈现各种问题,如竞态条件和数据不一致性。 本文将探讨如何在Java中无效地应答这些挑战,介绍一种弱小的工具——并发Map,它可能帮忙您治理多线程环境下的共享数据,确保数据的一致性和高性能。咱们将深刻理解Java中的并发Map实现,包含ConcurrentHashMap和ConcurrentSkipListMap,以及其余相干的知识点。无论您是初学者还是有教训的开发人员,都会在本文中找到无关并发编程的有用信息,以及如何在我的项目中利用这些常识的领导。让咱们开始这个令人兴奋的多线程之旅吧! 并发问题在深刻理解并发Map之前,让咱们首先探讨一下多线程编程中常见的问题。在多线程环境中,多个线程能够同时拜访和批改共享数据,这可能导致以下问题: 1. 竞态条件竞态条件是指多个线程试图同时拜访和批改共享数据,而最终的后果取决于线程的执行程序。这种不确定性可能导致不统一的后果,甚至是程序解体。 class Counter { private int value = 0; public void increment() { value++; } public int getValue() { return value; }}在下面的示例中,如果两个线程同时调用increment办法,可能会导致计数器的值不正确。 2. 数据不一致性在多线程环境中,数据的不一致性是一个常见问题。当一个线程批改了共享数据,其余线程可能不会立刻看到这些批改,因为缓存和线程本地内存的存在。这可能导致线程之间看到不同版本的数据,从而引发谬误。 为什么须要并发Map?当初,您可能会想晓得如何解决这些问题。这就是并发Map派上用场的中央。并发Map是一种数据结构,它专为多线程环境设计,提供了一种无效的形式来解决共享数据。它容许多个线程同时读取和批改数据,同时确保数据的一致性和线程安全性。 Java并发Map的概述当初,让咱们深刻理解Java规范库中提供的不同并发Map实现,以及它们的特点和实用场景。 1. ConcurrentHashMapConcurrentHashMap 是Java规范库中最罕用的并发Map实现之一。它应用分段锁(Segment)来实现高并发拜访,每个分段锁只锁定一部分数据,从而升高了锁的争用。这使得多个线程能够同时读取不同局部的数据,进步了性能。 ConcurrentMap<KeyType, ValueType> map = new ConcurrentHashMap<>();map.put(key, value);ValueType result = map.get(key);ConcurrentHashMap实用于大多数多线程应用程序,尤其是读多写少的状况。 2. ConcurrentSkipListMapConcurrentSkipListMap 是另一个乏味的并发Map实现,它基于跳表(Skip List)数据结构构建。它提供了有序的映射,而不仅仅是键值对的存储。这使得它在某些状况下成为更好的抉择,例如须要按键排序的状况。 ConcurrentMap<KeyType, ValueType> map = new ConcurrentSkipListMap<>();map.put(key, value);ValueType result = map.get(key);ConcurrentSkipListMap实用于须要有序映射的状况,它在一些特定利用中性能表现出色。 3. 其余Java并发Map实现除了ConcurrentHashMap和ConcurrentSkipListMap之外,Java生态系统还提供了其余一些并发Map实现,例如Google Guava库中的ConcurrentMap实现,以及Java 8中对ConcurrentHashMap的加强性能。另外,还有一些第三方库,如Caffeine和Ehcache,提供了高性能的缓存和并发Map性能。 ConcurrentHashMap详解当初,让咱们深入研究ConcurrentHashMap,理解它的外部实现和线程平安机制。 外部实现ConcurrentHashMap的外部实现基于哈希表和分段锁。它将数据分成多个段(Segment),每个段都是一个独立的哈希表,领有本人的锁。这意味着在大多数状况下,不同段的数据能够被不同线程同时拜访,从而进步了并发性能。 罕用操作ConcurrentHashMap反对许多常见的操作,包含put、get、remove等。上面是一些示例: ConcurrentMap<KeyType, ValueType> map = new ConcurrentHashMap<>();map.put(key, value);ValueType result = map.get(key);map.remove(key);这些操作是线程平安的,多个线程能够同时调用它们而不会导致竞态条件。 ...

September 19, 2023 · 2 min · jiezi

关于java:提升-Spring-Boot-吞吐量的-7-个神技让你的项目飞起来

一、异步执行实现形式二种: 应用异步注解 @aysnc、启动类:增加 @EnableAsync 注解JDK 8 自身有一个十分好用的 Future 类——CompletableFuture@AllArgsConstructorpublic class AskThread implements Runnable{ private CompletableFuture<Integer> re = null; public void run() { int myRe = 0; try { myRe = re.get() * re.get(); } catch (Exception e) { e.printStackTrace(); } System.out.println(myRe); } public static void main(String[] args) throws InterruptedException { final CompletableFuture<Integer> future = new CompletableFuture<>(); new Thread(new AskThread(future)).start(); //模仿长时间的计算过程 Thread.sleep(1000); //告知实现后果 future.complete(60); }}在该示例中,启动一个线程,此时 AskThread 对象还没有拿到它须要的数据,执行到 myRe = re.get() * re.get() 会阻塞。 ...

September 19, 2023 · 4 min · jiezi

关于java:Java-中for循环和foreach循环哪个更快

前言 在Java编程中,循环构造是程序员罕用的管制流程,而for循环和foreach循环是其中比拟常见的两种模式。对于它们哪一个更快的探讨始终存在。本文旨在探索Java中的for循环和foreach循环的性能差别,并帮忙读者更好地抉择适宜本身需要的循环形式。通过具体比拟它们的遍历效率、数据结构适用性和编译器优化等因素,咱们将为大家揭示它们的差别和实用场景,以便您可能做出更理智的编程决策。 for循环与foreach循环的比拟 小编认为for和foreach 之间惟一的理论区别是,对于可索引对象,咱们无权拜访索引。 for(int i = 0; i < mylist.length; i++) { if(i < 5) { //do something } else { //do other stuff }}然而,咱们能够应用 foreach 创立一个独自的索引 int 变量。例如: int index = -1;for(int myint : mylist) { index++; if(index < 5) { //do something } else { //do other stuff }}当初写一个简略的类,其中有 foreachTest() 办法,该办法应用 forEach 迭代列表。 import java.util.List;public class ForEachTest { List<Integer> intList; public void foreachTest(){ for(Integer i : intList){ } }}编译这个类时,编译器会在外部将这段代码转换为迭代器实现。小编通过执行 javap -verbose IterateListTest 反编译代码。 ...

September 19, 2023 · 2 min · jiezi

关于java:Java中的锁原理锁优化

一、为什么要用锁?锁-是为了解决并发操作引起的脏读、数据不统一的问题。 二、锁实现的基本原理2.1、volatileJava编程语言容许线程访问共享变量, 为了确保共享变量能被精确和统一地更新,线程应该确保通过排他锁独自取得这个变量。Java语言提供了volatile,在某些状况下比锁要更加不便。 volatile在多处理器开发中保障了共享变量的“ 可见性”。可见性的意思是当一个线程批改一个共享变量时,另外一个线程能读到这个批改的值。 论断:如果volatile变量修饰符应用失当的话,它比synchronized的应用和执行老本更低,因为它不会引起线程上下文的切换和调度。 2.2、synchronizedsynchronized通过锁机制实现同步。 先来看下利用synchronized实现同步的根底:Java中的每一个对象都能够作为锁。 具体表现为以下3种模式。 对于一般同步办法,锁是以后实例对象。对于动态同步办法,锁是以后类的Class对象。对于同步代码块,锁是Synchonized括号里配置的对象。当一个线程试图拜访同步代码块时,它首先必须失去锁,退出或抛出异样时必须开释锁。 2.2.1 synchronized实现原理synchronized是基于Monitor来实现同步的。 Monitor从两个方面来反对线程之间的同步: 互斥执行合作1、Java 应用对象锁 ( 应用 synchronized 取得对象锁 ) 保障工作在共享的数据集上的线程互斥执行。 2、应用 notify/notifyAll/wait 办法来协同不同线程之间的工作。 3、Class和Object都关联了一个Monitor。 Monitor 的工作机理 线程进入同步办法中。为了继续执行临界区代码,线程必须获取 Monitor 锁。如果获取锁胜利,将成为该监督者对象的拥有者。任一时刻内,监督者对象只属于一个流动线程(The Owner)领有监督者对象的线程能够调用 wait() 进入期待汇合(Wait Set),同时开释监督锁,进入期待状态。其余线程调用 notify() / notifyAll() 接口唤醒期待汇合中的线程,这些期待的线程须要从新获取监督锁后能力执行 wait() 之后的代码。同步办法执行结束了,线程退出临界区,并开释监督锁。2.2.2 synchronized具体实现1、同步代码块采纳monitorenter、monitorexit指令显式的实现。 2、同步办法则应用ACC_SYNCHRONIZED标记符隐式的实现。 通过实例来看看具体实现: javap -c 编译后的字节码如下: monitorenter 每一个对象都有一个monitor,一个monitor只能被一个线程领有。当一个线程执行到monitorenter指令时会尝试获取相应对象的monitor,获取规定如下: 如果monitor的进入数为0,则该线程能够进入monitor,并将monitor进入数设置为1,该线程即为monitor的拥有者。如果以后线程曾经领有该monitor,只是从新进入,则进入monitor的进入数加1,所以synchronized关键字实现的锁是可重入的锁。如果monitor已被其余线程领有,则以后线程进入阻塞状态,直到monitor的进入数为0,再从新尝试获取monitor。monitorexit 只有领有相应对象的monitor的线程能力执行monitorexit指令。每执行一次该指令monitor进入数减1,当进入数为0时以后线程开释monitor,此时其余阻塞的线程将能够尝试获取该monitor。 monitorexit有两个,另一个是用来确保异样完结时开释 monitor指令. 2.2.3 锁寄存的地位锁标记寄存在Java对象头的Mark Word中。 Java对象头长度 32位JVM Mark Word 构造 32位JVM Mark Word 状态变动 64位JVM Mark Word 构造 ...

September 18, 2023 · 1 min · jiezi

关于java:RBAC权限管理

如何用java实现一个端午节主题的RBAC权限管理系统 RBAC(Role-Based Access Control)是一种罕用的权限治理模型,它基于用户角色来控制系统中的资源拜访。在理论利用中,咱们通常会应用Spring Security框架来实现RBAC权限管理系统。RBAC的概念和原理 RBAC(Role-Based Access Control)是一种基于角色的访问控制模型,它将用户、角色和权限三者离开治理,从而简化了权限调配和治理的过程。RBAC的核心思想是,不是间接给用户调配权限,而是给用户调配角色,而后给角色调配权限,这样就能够实现多对多的关系,即一个用户能够领有多个角色,一个角色能够领有多个权限。 RBAC的根本组成部分有: 用户(User):指零碎中的实体,能够是人员、设施、程序等,须要拜访零碎中的资源。角色(Role):指零碎中的一组权限的汇合,代表了肯定的职责或性能。一个用户能够领有一个或多个角色,一个角色能够被调配给一个或多个用户。权限(Permission):指对系统中的资源执行某种操作的能力。一个角色能够领有一个或多个权限,一个权限能够被调配给一个或多个角色。RBAC的根本流程如下: 管理员依据组织构造和业务需要,定义零碎中的角色和权限,并将它们关联起来。管理员依据用户的身份和职责,将用户调配到相应的角色。用户登录零碎后,依据其所属的角色,取得相应的权限。用户依据其领有的权限,拜访零碎中的资源。RBAC的优缺点 RBAC作为一种罕用的权限治理模型,有以下几个长处: 简化了权限治理:通过将用户、角色和权限离开治理,升高了权限调配和治理的复杂度和老本。管理员只须要保护用户和角色、角色和权限之间的关系,而不须要为每个用户独自调配权限。进步了安全性:通过实现最小特权准则,即只给用户调配其执行职责所需的最小权限,缩小了数据泄露或滥用的危险。同时,通过实现责任拆散准则,即防止将互相抵触或矛盾的权限调配给同一个用户或同一个角色,加强了零碎的安全性。反对了灵活性:通过反对角色继承和层次结构,能够实现不同级别和类型的角色之间的关系,从而满足不同场景和需要下的权限管制。同时,通过反对动静拆散准则,能够依据上下文或会话状态来动静调整用户激活的权限。RBAC也有以下几个毛病: 须要理解组织构造:为了无效地定义和保护角色和权限,须要分明地理解组织构造和业务需要,并跨部门协调。这在大型或成长中的组织中可能是一项挑战。须要三思而行地施行:为了防止角色爆炸或特权蔓延等问题,须要在施行RBAC时思考到各种因素和状况,并制订正当和统一的策略。这可能须要破费大量的工夫和精力。不足细粒度的管制:RBAC基于角色来管制权限,而不是基于用户的属性或环境的条件。这可能导致RBAC过于死板或不够灵便,无奈满足一些非凡或简单的访问控制需要。表设计 在实现RBAC权限管理系统之前,咱们须要先设计相干的表构造。上面是一个简略的表设计: user表:存储用户信息,包含用户名、明码等id username password1 alice 1234562 bob 6543213 charlie 111111 role表:存储角色信息,包含角色名称、角色形容等id name description1 ADMIN 管理员2 USER 用户3 GUEST 访客 permission表:存储权限信息,包含权限名称、权限形容等id name description1 /admin/** 拜访管理员页面2 /user/** 拜访用户页面3 /guest/** 拜访访客页面 user_role表:存储用户角色关系,包含用户ID和角色IDuser_id role_id1 12 23 3 role_permission表:存储角色权限关系,包含角色ID和权限IDrole_id permission_id1 11 21 32 22 3配置Spring Security 在Spring Security中实现RBAC权限管理系统的关键在于配置平安拦截器链,即定义哪些URL须要哪些权限能力拜访。上面是一个简略的配置示例: @Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() // /admin/**门路下的申请须要ADMIN角色能力拜访 .antMatchers("/admin/**").hasRole("ADMIN") // /user/**门路下的申请须要USER角色能力拜访 .antMatchers("/user/**").hasRole("USER") // 其余申请须要认证后能力拜访 .anyRequest().authenticated() .and() .formLogin() // 登录页面的门路为/login .loginPage("/login") // 容许所有用户拜访登录页面 .permitAll() .and() .logout() // 容许所有用户拜访登出页面 .permitAll();}@Autowiredpublic void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth // 应用自定义的UserDetailsService来获取用户信息 .userDetailsService(userDetailsService) // 应用BCryptPasswordEncoder加密器来加密明码 .passwordEncoder(passwordEncoder());}@Beanpublic PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder();}} ...

September 18, 2023 · 2 min · jiezi

关于java:场景题海量数据如何判重

在海量数据如何确定一个值是否存在?这是一道十分经典的面试场景题。 那怎么答复这个问题呢?接下来咱们就具体的聊一聊。 参考答案判断一个值是否存在?通常有以下两种解决方案: 应用哈希表:能够将数据进行哈希操作,将数据存储在相应的桶中。查问时,依据哈希值定位到对应的桶,而后在桶内进行查找。这种办法的工夫复杂度为 O(1),但须要额定的存储空间来存储哈希表。如果桶中存在数据,则阐明此值已存在,否则阐明未存在。应用布隆过滤器:布隆过滤器是一种概率型数据结构,用于判断一个元素是否在汇合中。它利用多个哈希函数映射数据到一个位数组,并将对应地位置为 1。查问时,只须要看待查问的数据进行哈希,并判断对应的位是否都为 1。如果都为 1,则该数据可能存在;如果有一个位不为 1,则该数据肯定不存在。布隆过滤器的查问工夫复杂度为 O(k),其中 k 为哈希函数的个数。 相同点和不同点它们两的相同点是:它们都存在误判的状况。例如,应用哈希表时,不同元素的哈希值可能雷同,所以这样就产生误判了;而布隆过滤器的特色是,当布隆过滤器说,某个数据存在时,这个数据可能不存在;当布隆过滤器说,某个数据不存在时,那么这个数据肯定不存在。 它们两的区别次要有以下几点: 存储机制:哈希表应用一个数组来存储键值对,通过哈希函数将键映射到数组的索引地位,而后将值存储在对应的地位上。而布隆过滤器则应用一个位数组(或位向量),通过多个哈希函数将元素映射到位数组的多个位上。查问操作:哈希表在进行查问时,通过计算哈希值来定位键值对的存储地位,而后间接获取对应的值。查问工夫复杂度通常为 O(1)。布隆过滤器在进行查问时,也通过多个哈希函数计算多个位,而后判断对应的位是否都为 1 来确定元素是否存在。查问工夫复杂度为 O(k),其中 k 为哈希函数的个数。内存占用:哈希表须要依据数据规模来动静调整数组的大小,以保障存储效率。而布隆过滤器在事后设置位数组的大小后,不会随数据规模的减少而增长。因而布隆过滤器更实用于海量数据。 论断哈希表和布隆过滤器都能实现判重,但它们都会存在误判的状况,但布隆过滤器存储占用的空间更小,更适宜海量数据的判重。 布隆过滤器实现原理布隆过滤器的实现,次要依附的是它数据结构中的一个位数组,每次存储键值的时候,不是间接把数据存储在数据结构中,因为这样太占空间了,它是利用几个不同的无偏哈希函数,把此元素的 hash 值平均的存储在位数组中,也就是说,每次增加时会通过几个无偏哈希函数算出它的地位,把这些地位设置成 1 就实现了增加操作。 当进行元素判断时,查问此元素的几个哈希地位上的值是否为 1,如果全副为 1,则示意此值存在,如果有一个值为 0,则示意不存在。因为此地位是通过 hash 计算得来的,所以即便这个地位是 1,并不能确定是那个元素把它标识为 1 的,因而布隆过滤器查问此值存在时,此值不肯定存在,但查问此值不存在时,此值肯定不存在。 并且当位数组存储值比拟稠密的时候,查问的准确率越高,而当位数组存储的值越来越多时,误差也会增大。 位数组和 key 之间的关系,如下图所示: 如何实现布隆过滤器?布隆过滤器的实现通常有以下两种计划: 通过程序实现(内存级别计划):应用 Google Guava 库和 Apache Commons 库实现布隆过滤器。通过中间件实现(反对数据长久化):应用 Redis 4.0 之后提供的布隆过滤插件来实现,它的益处是反对长久化,数据不会失落。 Guava 实现布隆过滤器应用 Google Guava 库实现布隆过滤器总共分为以下两步: 引入 Guava 依赖应用 Guava API 操作布隆过滤器具体实现如下。 ① 引入 Guava 依赖<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId></dependency>② 应用 Guava APIimport com.google.common.hash.BloomFilter;import com.google.common.hash.Funnels;public class BloomFilterExample { public static void main(String[] args) { // 创立一个布隆过滤器,设置冀望插入的数据量为10000,冀望的误判率为0.01 BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.unencodedCharsFunnel(), 10000, 0.01); // 向布隆过滤器中插入数据 bloomFilter.put("data1"); bloomFilter.put("data2"); bloomFilter.put("data3"); // 查问元素是否存在于布隆过滤器中 System.out.println(bloomFilter.mightContain("data1")); // true System.out.println(bloomFilter.mightContain("data4")); // false }}在上述示例中,咱们通过 BloomFilter.create() 办法创立一个布隆过滤器,指定了元素序列化形式、冀望插入的数据量和冀望的误判率。而后,咱们能够应用 put() 办法向布隆过滤器中插入数据,应用 mightContain() 办法来判断元素是否存在于布隆过滤器中。 ...

September 18, 2023 · 1 min · jiezi

关于java:注意避坑Java-内部类持有外部类会导致内存泄露

简介阐明本文介绍 Java 外部类持有外部类导致内存泄露的起因以及其解决方案。 为什么外部类持有外部类会导致内存泄露 非动态外部类会持有外部类,如果有中央援用了这个非动态外部类,会导致外部类也被援用,垃圾回收时无奈回收这个外部类(即便外部类曾经没有其余中央在应用了)。 解决方案不要让其余的中央持有这个非动态外部类的援用,间接在这个非动态外部类执行业务。 将非动态外部类改为动态外部类。外部类改为动态的之后,它所援用的对象或属性也必须是动态的,所以动态外部类无奈取得内部对象的援用,只能从 JVM 的 Method Area(办法区)获取到static类型的援用。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice为什么要持有外部类Java 语言中,非动态外部类的次要作用有两个: 当外部类只在外部类中应用时,匿名外部类能够让内部不晓得它的存在,从而缩小了代码的保护工作。当外部类持有外部类时,它就能够间接应用外部类中的变量了,这样能够很不便的实现调用,如下代码所示:package org.example.a;class Outer{ private String outerName = "Tony"; class Inner{ private String name; public Inner() { this.name = outerName; } } Inner createInner() { return new Inner(); }}public class Demo { public static void main(String[] args) { Outer.Inner inner = new Outer().createInner(); System.out.println(inner); }}然而,动态外部类就无奈持有外部类和其非动态字段了。 比方下边这样就会报错: package org.example.a;class Outer{ private String outerName = "Tony"; static class Inner{ private String name; public Inner() { this.name = outerName; } } Inner createInner() { return new Inner(); }}public class Demo { public static void main(String[] args) { Outer.Inner inner = new Outer().createInner(); System.out.println(inner); }}报错: ...

September 12, 2023 · 2 min · jiezi

关于java:面试官说一下-MyBatis-缓存机制

MyBatis 的缓存机制属于本地缓存,实用于单机零碎,它的作用是缩小数据库的查问次数,进步零碎性能。 MyBaits 中蕴含两级本地缓存: 一级缓存:SqlSession 级别的,是 MyBatis 自带的缓存性能,默认开启,并且无奈敞开,因而当有两个 SqlSession 拜访雷同的 SQL 时,一级缓存也不会失效,须要查问两次数据库。二级缓存:Mapper 级别的,只有是同一个 Mapper,无论应用多少个 SqlSession 来操作,数据都是共享的,多个不同的 SqlSession 能够共用二级缓存,MyBatis 二级缓存默认是敞开的,须要应用时可手动开启,二级缓存也能够应用第三方的缓存,比方,应用 Ehcache 作为二级缓存。 一级缓存 VS 二级缓存一级缓存和二级缓存的次要区别如下: 一级缓存是 SqlSession 级别的缓存,它的作用域是同一个 SqlSession,同一个 SqlSession 中的屡次查问会共享同一个缓存。二级缓存是 Mapper 级别的缓存,它的作用域是同一个 Mapper,同一个 Mapper 中的屡次查问会共享同一个缓存。一级缓存是默认开启的,不须要手动配置。二级缓存须要手动配置,须要在 Mapper.xml 文件中增加 <cache> 标签。一级缓存的生命周期是和 SqlSession 一样长的,当 SqlSession 敞开时,一级缓存也会被清空。二级缓存的生命周期是和 MapperFactory 一样长的,当应用程序敞开时,二级缓存也会被清空。一级缓存只能用于同一个 SqlSession 中的屡次查问,不能用于跨 SqlSession 的查问。二级缓存能够用于跨 SqlSession 的查问,多个 SqlSession 能够共享同一个二级缓存。一级缓存是线程公有的,不同的 SqlSession 之间的缓存数据不会相互烦扰。二级缓存是线程共享的,多个 SqlSession 能够共享同一个二级缓存,须要思考线程平安问题。 开启二级缓存MyBatis 一级缓存是自带的缓存,默认开启,且无奈敞开。而二级缓存默认是敞开的,因而咱们只须要把握二级缓存的开启即可。二级缓存开启须要两步: 在 mapper xml 中增加 <cache> 标签。在须要缓存的标签上设置 useCache="true"(最新版本中,能够省略此步骤)。残缺示例实现如下: <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.mybatis.demo.mapper.StudentMapper"> <cache/> <select id="getStudentCount" resultType="Integer" useCache="true"> select count(*) from student </select></mapper>编写单元测试代码: ...

September 12, 2023 · 1 min · jiezi

关于java:推荐一款最新开源分布式任务调度框架

介绍Openjob 基于Akka架构的新一代分布式任务调度框架。反对多种定时工作、延时工作、工作流设计,采纳无中心化架构,底层应用一致性分片算法,反对有限程度扩容。 高牢靠 分布式无状态设计,采纳 Master/Worker 架构,反对多样的数据库(H2/MySQL/PostgreSQL/Oracle/TiDB)高性能 底层应用一致性分片算法,全程无锁化设计,任务调度准确到秒级别,反对轻量级分布式计算、有限程度扩容。定时调度 反对分布式定时工作、固定频率工作、高性能秒级任务、一次性工作定时调度。分布式计算 反对单机、播送、Map、MapReduce 和分片多种分布式编程模型,轻松实现大数据分布式计算。延时工作 基于 Redis 实现高性能延时工作,底层实现工作多级存储,提供丰盛的统计和报表。工作流 内置工作流调度引擎,反对可视化 DAG 设计,简略高效实现简单任务调度。权限治理 欠缺的用户治理,反对菜单、按钮以及数据权限设置,灵便治理用户权限报警监控 全面的监控指标,丰盛及时的报警形式,便于运维人员疾速定位和解决线上问题。跨语言 原生反对 Java/Go/PHP/Python 多语言 ,以及Spring Boot、Gin、Swoft 等框架集成。如果您正在寻找一款高性能的分布式任务调度框架,反对定时工作、延时工作、轻量级计算、工作流编排,并且反对多种编程语言,那么 Openjob 必定是不二之选(https://github.com/open-job/openjob)。 更新内容openjob 公布至今已更新到1.0.7 新增反对H2/TiDB 数据库,新增秒级任务、固定频率工作、播送工作、分片工作、Map Reduce 轻量计算。 秒级任务秒级任务,反对1\~60秒距离的秒级提早调度,即每次工作执行实现后,距离秒级工夫再次触发调度,实用于对实时性要求比拟高的业务。 劣势 高牢靠:秒级别工作具备高牢靠的个性,如果某台机器宕机,能够在另一台机器上从新运行。丰盛的工作类型:秒级别工作属于定时调度类型,能够实用于所有的工作类型和执行形式。 固定频率工作因为Crontab必须被60整除,如果须要每隔50分钟执行一次调度,则Cron无奈反对。 Map ReduceMapReduce 模型是轻量级分布式跑批工作。通过 MapProcessor 或 MapReduceProcessor 接口实现。绝对于传统的大数据跑批(例如Hadoop、Spark等),MapReduce无需将数据导入大数据平台,且无额定存储及计算成本,即可实现秒级别海量数据处理,具备成本低、速度快、编程简略等个性。 /** * @author stelin swoft@qq.com * @since 1.0.7 */@Component("mapReduceTestProcessor")public class MapReduceTestProcessor implements MapReduceProcessor { private static final Logger logger = LoggerFactory.getLogger("openjob"); private static final String TWO_NAME = "TASK_TWO"; private static final String THREE_NAME = "TASK_THREE"; @Override public ProcessResult process(JobContext context) { if (context.isRoot()) { List<MapChildTaskTest> tasks = new ArrayList<>(); for (int i = 1; i < 5; i++) { tasks.add(new MapChildTaskTest(i)); } logger.info("Map Reduce root task mapList={}", tasks); return this.map(tasks, TWO_NAME); } if (context.isTask(TWO_NAME)) { MapChildTaskTest task = (MapChildTaskTest) context.getTask(); List<MapChildTaskTest> tasks = new ArrayList<>(); for (int i = 1; i < task.getId()*2; i++) { tasks.add(new MapChildTaskTest(i)); } logger.info("Map Reduce task two mapList={}", tasks); return this.map(tasks, THREE_NAME); } if (context.isTask(THREE_NAME)) { MapChildTaskTest task = (MapChildTaskTest) context.getTask(); logger.info("Map Reduce task three mapTask={}", task); return new ProcessResult(true, String.valueOf(task.getId() * 2)); } return ProcessResult.success(); } @Override public ProcessResult reduce(JobContext jobContext) { List<String> resultList = jobContext.getTaskResultList().stream().map(TaskResult::getResult) .collect(Collectors.toList()); logger.info("Map Reduce resultList={}", resultList); return ProcessResult.success(); } @Data @AllArgsConstructor @NoArgsConstructor public static class MapChildTaskTest { private Integer id; }} ...

September 12, 2023 · 2 min · jiezi

关于java:Spring-中三种-BeanName-生成器

无论咱们是通过 XML 文件,还是 Java 代码,亦或是包扫描的形式去注册 Bean,都能够不设置 BeanName,而 Spring 均会为之提供默认的 beanName,明天咱们就来看看 Spring 中三种解决不同状况的 beanName 生成器。 1. BeanNameGeneratorSpring 中提供了一个名为 BeanNameGenerator 的接口,这个接口就只有一个须要实现的办法就是 generateBeanName,从名字就能看进去,这就是专门用来生成 beanName 的办法。 public interface BeanNameGenerator { String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);}这个办法有两个参数: definition:这个是要生成的 Bean 定义。registry:这个是未来 BeanDefinition 的注册器。BeanNameGenerator 有三个不同的实现类,对应不同的解决场景: AnnotationBeanNameGenerator:这个专门用来解决包扫描的时候扫到的 Bean,对于这些 Bean,其 name 属性该如何解决,由这个类来解决,当然,小伙伴们都晓得,通过 @Component/@Service/@Repository/@Controller 这些注解定义的 Bean,默认状况下,beanName 就是类名首字母小写。FullyQualifiedAnnotationBeanNameGenerator:这个继承自 AnnotationBeanNameGenerator,并重写了 AnnotationBeanNameGenerator#buildDefaultBeanName 办法,这个是应用类的全门路来作为 Bean 的默认名称。DefaultBeanNameGenerator:这个是专门用来解决 XML 文件中定义的 Bean 如果没有设置 beanName,那么就通过 DefaultBeanNameGenerator 来为其生成 beanName。看了下面三个场景之后,可能有小伙伴发现一个 BUG,那么 @Bean 注解定义的 Bean,其 beanName 属性是在哪里解决的呢?这个其实比拟非凡,是当场解决的,没用到 BeanNameGenerator,松哥前面独自说。 接下来咱们具体看下下面这三个实现类。 2. AnnotationBeanNameGenerator咱们间接来看最要害的 generateBeanName 办法吧: ...

September 12, 2023 · 3 min · jiezi

关于java:买彩票能中大奖用Java盘点常见的概率悖论-京东云技术团队

引言《双色球头奖概率与被雷劈中的概率哪个高?》 《3人轮流射击,枪法最差的反而更容易活下来?》 让咱们用Java来摸索ta们! 悖论1:驰名的三门问题规定形容:你正在加入一个游戏节目,你被要求在三扇门中抉择一扇:其中一扇前面有一辆车;其余两扇前面则是山羊。你抉择了一道门,假如是一号门,而后晓得门前面有什么的主持人,开启了另一扇前面有山羊的门,假如是三号门。他而后问你:“你想抉择二号门吗?请问若想取得车,参赛者应该换二号门吗? 论证:剖析需要,拆解为如下代码 /** * <p> 三门问题解决方案 </p> * @author yuanfeng.wang * @since 2023/8/29 */import java.util.Random;public class ThreeDoorSolution { public static void main(String[] args) { // 模仿执行1万次,打印获胜的概率 threeDoor(10000); } /** * 三门问题逻辑拆解 * @param numSimulations 总共执行多少轮游戏 */ private static void threeDoor(int numSimulations) { int switchWins = 0; int stayWins = 0; Random random = new Random(); for (int i = 0; i < numSimulations; i++) { // 随机确定车所在的门 int carDoor = random.nextInt(3); // 玩家随机抉择一扇门 int playerChoice = random.nextInt(3); // 主持人随机关上一扇门:要求该门不是玩家抉择的,且必须是羊 int openedDoor; do { openedDoor = random.nextInt(3); } while (openedDoor == carDoor || openedDoor == playerChoice); // 换门后的抉择:不能是关上的门,不能是玩家抉择的门,则是替换之后的门 int finalChoice; do { finalChoice = random.nextInt(3); } while (finalChoice == playerChoice || finalChoice == openedDoor); // 计算是否换门获胜 if (finalChoice == carDoor) { switchWins++; } // 计算不换门获胜 if (playerChoice == carDoor) { stayWins++; } } // 输入后果 System.out.println("在 " + numSimulations + " 次模仿中:"); System.out.println("换门获胜的概率:" + (double) switchWins / numSimulations); System.out.println("不换门获胜的概率:" + (double) stayWins / numSimulations); }}// 模仿运行,打印后果如下// 在 10000 次模仿中:// 换门获胜的概率:0.6679// 不换门获胜的概率:0.3321论断:三门问题看似一道简略的概率题,几十年来却始终引发微小争议,持两种不同观点的人根本是五五开;事实上始终抉择换门的玩家,获胜的概率2/3,而放弃原计划的胜率只有1/3 ...

September 12, 2023 · 3 min · jiezi

关于java:一个全面完整稳定的-k8s-集群架构值得借鉴

起源:https://www.cnblogs.com/zisefeizhu/p/13692782.html 前言我司的集群时刻处于解体的边缘,通过近三个月的把握,发现我司的集群不稳固的起因有以下几点: 1、发版流程不稳固 2、短少监控平台【最重要的起因】 3、短少日志零碎 4、极度短少无关操作文档 5、申请路线不明朗 总的来看,问题的次要起因是短少可预知的监控平台,总是等问题呈现了才晓得。主要的起因是服务器作用不明朗和发版流程的不稳固。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice解决方案发版流程不稳固重构发版流程。业务全面k8s化,构建以kubernetes为外围的ci/cd流程。 发版流程无关发版流程如下: 浅析:研发人员提交代码到developer分支(时刻确保developer分支处于最新的代码),developer分支合并到须要发版环境对应的分支,触发企业微信告警,触发部署在k8s集群的gitlab-runner pod,新启runner pod 执行ci/cd操作。在这个过程中须要有三个步骤:测试用例、打包镜像、更新pod。 第一次部署服务在k8s集群环境的时候可能须要:创立namespace、创立imagepullsecret、创立pv(storageclass)、创立deployment(pod controller)、创立svc、创立ingress、等。其中镜像打包推送阿里云仓库和从阿里云仓库下载镜像应用vpc拜访,不走公网,无网速限度。流程结束,runner pod 销毁,gitlab 返回后果。 须要强调的一点是,在这里的资源资源清单不蕴含configmap或者secret,牵扯到安全性的问题,不应该出 当初代码仓库中,我司是应用rancher充当k8s多集群治理平台,上述平安问题在rancher的dashboard中由运维来做的。 服务部署逻辑图无关服务部署逻辑图如下: 依据发版流程的浅析,再依据逻辑图能够明确发版流程。在这里看到我司应用的是kong代替nginx,做认证、鉴权、代理。而slb的ip绑定在kong上。0,1,2属于test job;3属于build job;4,5,6,7属于change pod 阶段。并非所有的服务都须要做存储,须要依据理论状况来定,所以须要在kubernetes.sh里写判断。 在这里我试图应用一套CI利用与所有的环境,所以须要在kubernetes.sh中用到的判断较多,且.gitlab-ci.yml显得过多。倡议是应用一个ci模版,利用于所有的环境,毕竟怎么省事怎么来。 还要思考本人的分支模式,具体参考:https://www.cnblogs.com/zisefeizhu/p/13621797.html 短少监控预警平台构建可信赖且合乎我司集群环境的联邦监控平台,实现对几个集群环境的同时监控和预故障告警,提前染指。 监控预警逻辑图无关监控预警逻辑图如下: 浅析:总的来说,我这里应用到的监控计划是prometheus➕shell脚本或go脚本➕sentry。应用到的告警形式是企业微信或者企业邮箱。上图三种色彩的线代表三种监控形式须要留神。 脚本次要是用来做备份告警、证书告警、抓贼等。prometheus这里采纳的是依据prometheus-opertor批改的prometheus资源清单,数据存储在nas上。sentry严格的来讲属于日志收集类的平台,在这里我将其归为监控类,是因为我看中了其收集利用底层代码的解体信息的能力,属于业务逻辑监控, 旨在对业务零碎运行过程中产生的谬误日志进行收集演绎和监控告警。 留神这里应用的是联邦监控平台,而部署一般的监控平台。 联邦监控预警平台逻辑图多集群联邦监控预警平台逻辑图如下: 因为我司有几个k8s集群,如果在每个集群上都部署一套监控预警平台的话,治理起来太过不便,所以这里我采取的策略是应用将各监控预警平台履行一个联邦的策略,应用对立的可视化界面治理。这里我将实现三个级别饿监控:操作系统级、应用程序级、业务级。对于流量的监控能够间接针对kong进行监控,模版7424。 短少日志零碎随着业务全面k8s化过程的推动,对于日志零碎的需要将更加渴望,k8s的个性是服务的故障日志难以获取。建设可观测的能过滤的日志零碎能够升高对故障的剖析难度。 无关日志零碎逻辑图如下: 浅析:在业务全面上k8s化后,不便了治理保护,但对于日志的治理难度就适当回升了。咱们晓得pod的重启是有多因素且不可控的,而每次pod重启都会从新记录日志,即新pod之前的日志是不可见的。当然了有多种办法能够实现日志长存:远端存储日志、本机挂载日志等。出于对可视化、可剖析等的思考,抉择应用elasticsearch构建日志收集零碎。 极度短少无关操作文档建设以语雀--> 运维相干材料为核心的文档核心,将无关操作、问题、脚本等具体记录在案,以备随时查看。 浅析因安全性起因,不便于过多共事查阅。运维的工作比拟非凡,平安化、文档化是必须要保障的。我认为不论是运维还是运维开发,书写文档都是必须要把握的,为己也好,为他也罢。文档能够简写,但必须要含苞外围的步骤。我还是认为运维的每一步操作都应该记录下来。 申请路线不明朗依据集群重构的新思路,从新梳理集群级流量申请路线,构建具备:认证、鉴权、代理、连贯、爱护、管制、察看等一体的流量治理,无效管制故障爆炸范畴。 申请路线逻辑图如下: 浅析:客户拜访https://www.cnblogs.com/zisefeizhu 通过kong网关鉴权后进入特定名称空间(通过名称空间辨别我的项目),因为服务曾经拆分为微服务,服务间通信通过istio认证、受权,须要和数据库交互的去找数据库,须要写或者读存储的去找pv,须要转换服务的去找转换服务...... 而后返回响应。 总结综上所述,构建以:以kubernetes为外围的ci/cd发版流程、以prometheus为外围的联邦监控预警平台、以elasticsearch为外围的日志收集零碎、以语雀为外围的文档管理中心、以kong及istio为外围的南北货色流量一体化服务,能够在高平发,高可靠性上做到很好保障。 附:总体架构逻辑图 注:请依据箭头和色彩来剖析。 浅析:上图看着仿佛过于凌乱,静下心来,依据下面的拆分模块一层层剖析还是能够看清晰的。这里我用不同色彩的连线代表不同模块的零碎,依据箭头走还是蛮清晰的。 依据我司目前的业务流量,上述功能模块,实践上能够实现集群的维稳。私认为此套计划能够确保业务在k8s集群上稳固的运行一段时间,再有问题就属于代码层面的问题了。这里没有应用到中间件,倒是应用到了缓存redis不过没画进去。我布局在上图搞定后再在日志零碎哪里和转换服务哪里减少个中间件kafka或者rq 看状况吧。 近期热文举荐: 1.1,000+ 道 Java面试题及答案整顿(2022最新版) ...

September 12, 2023 · 1 min · jiezi

关于java:PDF技术方案wkhtmltopdf

前端实现导出 PDF 产品报告,存在几个问题: 1. 是图片版的 PDF; 2. PDF 太大,会卡; 3. 可能会把文字裁剪分页; 4. 无奈满足平台提供 Api 接口服务。外围就是问题3和问题4,于是,思考后端服务实现导出 PDF 产品报告的计划。Java 实现 HTML 转 PDF 技术选型举荐应用 wkhtmltopdf, Itext,但 wkhtmltopdf 开源收费,Itext 须要思考版权参考:https://blog.csdn.net/weixin_43981813/article/details/128135730参考:https://www.cnblogs.com/IT-study/p/13706690.html技术实现计划技术采纳模板引擎 + PDF 插件实现。开发好页面模板,Thymeleaf 模板引擎渲染动态 HTML 文件,wkhtmltopdf 将动态的 HTML 生成 PDF 文件。整体计划流程如下:后盾应用 Thymeleaf 模板生成 Html 报告页面PDF 接口依据 ID 查问报告数据调用 wkhtmltopdf 工具 将 Html 转为 PDF 文件对于 wkhtmltopdf参数文档: https://wkhtmltopdf.org/usage/wkhtmltopdf.txtwkhtmltopdf 装置Yum 装置(可能是老版本存在bug,不举荐)yum -y install wkhtmltopdfrpm 包装置下载最新依照包,如wget https://objects.githubusercontent.com/github-production-relea...先装置依赖包yum install -y fontconfig libX11 libXext libXrender libjpeg libpng xorg-x11-fonts-75dpi xorg-x11-fonts-Type1wkhtmltox 装置rpm -ivh wkhtmltox-0.12.6-1.centos8.x86_64.rpm若须要门路执行,可配置cp /usr/local/bin/wkhtmltopdf /usr/bin/wkhtmltopdf内网装置先下载依赖包到指定目录,例如下载 openssl 依赖包到指定目录yum install --downloadonly --downloaddir=/usr/soft/wktooltopdf/ openssl之后,拷贝依赖包到内网环境,执行命令rpm -ivh --force --nodeps .rpmrpm -ivh --force --nodeps .rpm常见问题短少依赖包手动装置依赖包FAQ-linux 装置 wkhtmltopdf 中文乱码或者空白解决办法参考:https://www.cnblogs.com/jluo/p/17403785.html装置中文字体,或复制已有字体关上windows c:\Windows\fonts\simsun.ttc拷贝到linux服务器/usr/share/fonts/目录下,再次生成pdf中文显示失常呈现谬误: wkhtmltopdf:cannot connect to X server参考:https://www.jianshu.com/p/2cfc02961528需再装置xvfbyum install xorg-x11-server-Xvfb在 /usr/bin/ 目录下生成脚本 wkhtmltopdf.sh 并写入命令sudo vim /usr/bin/wkhtmltopdf.sh 命令:xvfb-run -a --server-args="-screen 0, 1024x768x24" /usr/bin/wkhtmltopdf -q $*更改文件权限并建设连贯chmod a+x /usr/bin/wkhtmltopdf.shln -s /usr/bin/wkhtmltopdf.sh /usr/local/bin/wkhtmltopdf中文字体装置若呈现中文乱码,则可能是短少字体阿里巴巴普惠体2.0,收费无版权,好用下载地址: https://done.alibabadesign.com/puhuiti2.0介绍阐明: https://fonts.adobe.com/fonts/alibaba-puhuiti设置字体集font-family: alibaba-puhuiti, sans-serif;font-style: normal;font-weight: 300;开发代码及配置动态资源目录位于 *-model 工程下的资源文件,包含以下目录templates/ - 模板文件static/ - 动态资源文件若前端有批改调整,需将更新的文件复制到 *-model 工程下对应目录,动态资源复制计划1:maven 插件配置, 用于复制公共的资源pom.xml 减少插件配置<plugin> <!-- 该插件的作用是用于复制 PDF 模板资源文件 --> ...

September 11, 2023 · 4 min · jiezi

关于java:springmvc解决跨域问题

写在后面 跨域问题并不是spring特有的,本文简要的介绍跨域问题的前因后果,以及 spring解决跨域问题的两种形式。 1.什么导致了跨域浏览器的同源策略导致了跨域问题。 1.1 同源策略同源策略限度了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在歹意文件的重要平安机制。 同源的定义:如果两个页面的协定,端口和主机都雷同,则两个页面具备雷同的源。 1.2 跨源拜访应用 CORS 容许跨源拜访。 CORS 的工作原理是: 增加新的HTTP标头,让服务器形容容许哪些起源从Web浏览器读取该信息 那么 CORS 是如何容许跨源拜访的?这篇文章解释的十分具体了,跨域资源共享 CORS 详解 Spring MVC 的跨域问题服务器不做任何跨域配置时,通过 ajax 从前端页面 localhost:8080 申请 localhost:8081 时:并且控制台会报如下谬误: 如果你仔细阅读了后面所给出的博客当前,会很容易了解为什么会呈现下面的问题。 那么 spring 如何解决跨域问题呢?我所找到可能通过以下两种办法来解决: CrossOrigin 注解CorsConfiguration 类2.1 CrossOrigin注解该注解能够作用在类以及办法层面上,当作用在类(Controller)层面上时,该类下的所有门路均容许跨域拜访;当作用在办法层面上时,只有以后办法对应的门路容许跨域拜访。 当将注解的 origins 的值设置为 “ http://localhost:8082 ”时(咱们理论的origin 为 http://localhost:8080),拜访会返回 403 状态码 ,这是个乏味的景象;这应该表明了容许跨域,但你并不是容许的源。 2.2 CorsConfiguration该类须要在 spring mvc 配置类中应用: @Configuration @EnableWebMvc public class WebMvcConfig implements WebMvcConfigurer { @Overridepublic void addCorsMappings(CorsRegistry registry) { //设置容许跨域的门路 registry.addMapping("/**") //设置容许跨域申请的域名 .allowedOrigins("*") //是否容许证书 不再默认开启 .allowCredentials(true) //设置容许的办法 .allowedMethods("*") //跨域容许工夫 .maxAge(3600);}@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(new StringHttpMessageConverter()); converters.add(new MappingJackson2HttpMessageConverter());}} ...

September 11, 2023 · 1 min · jiezi

关于java:4-Star狗头-让后台人员一键拥有自己系统的管理平台前端功能

前言没错,是 4 Star /狗头。话不多说,做人后端开发人员,不爱写前端代码,但又不得不须要一个零碎的治理端来配置些数据等等操作的时候,前端又木的人,那么怎么办。别怕,能够主动生成啦!我来提供个收费快捷的一键生成前端性能的工具啦。前后分来到型,无侵入。可在线应用,可本地部署,高效快捷。 开始置信很多小伙伴开发后端的时候会常常碰到很多须要动静配置的性能,或者须要些增删改查的页面,本人又不会(爱)写前端。就会有个难堪的处境,常常去间接手动改数据库这种危险操作。所以我做了个能够一键生成这些性能的网站来生成前端我的项目,三五分钟就能够进去个这些性能的管理系统,又不须要了解,间接用就完事了,你还在等什么呢,快来给你的接口生成一个后盾页面治理吧。 形式一,依据数据库构造一键生成导出咱们的表构造,上传到工具中,配置一下接口地址,再配置一下接口门路,就能够一键生成零碎,而后再手动配置下登录接口的入参数即可实现。 拜访网址:网站入口 须要登录,输出邮件获取验证码即可登录,再无其它验证。 点击 我的我的项目-AI智能创立我的项目 抉择 数据库构造导入 上传咱们导出的库构造(即创立表的sql,一个文件,反对多个创立语句) 配置下接口的基地址(如:http://localhost:8080/test,留神:线上间接拜访本地存在跨域问题,所以在本地调试的时候能够设置下容许任意域拜访,如何设置此处不多介绍) 抉择或主动创立页面母版,主动创立的话当初只提供了一套 增删改查 模版曾经够用的了,自定义较简单暂不过问。母版即是一个没有元素(参数)的空性能,主动调用 增删改查 接口以及数据处理 配置一下接口的门路以及参数变量, 比方咱们查问接口都是 /${变量}/search, 增加或更新接口都是 /${变量}/saveOrUpdate。变量是什么呢?因为咱们会生成多张页面,所以每个页面的接口应该是不一样的(每个页面的前置变量是一样的),所以 ${fileName} 就是变量,也对应下一步的生成的页面名称。而参数变量则是接口入参加返回的数据结构,为了反对不一样的后端数据结构。比方咱们查问的时候的分页参数名,以及如果断定接口是胜利的等等。 抉择生成的页面信息,留神 文件名 列是对应上一步的 ${fileName},如有不同自行批改。而后点击生成即可 实现!点击预览,零碎曾经实现。 当然,有可能你还须要个登录进行验权。咱们进入设计页面,配置一下登录信息,以及登录胜利跳转到哪过页面即实现零碎,咱们就能够在预览中间接应用,也能够下载到本地部署啦,一个零碎就实现了。 形式二,依据(.sql, .java, .txt)形容文件单页面生成有可能咱们并不想依据数据库生成,而想每个页面本人管制,那么咱们能够先创立一个我的项目(先在我的项目母版与页面母版中复制零碎个缺省的),而后进入设计工作台 新建页面,输出页面名称,与文件名称(同理对应下面的:{fileName}),而后抉择你的 java 对应的表实体,或者单表创立语句,或者文本形容文件。如先筹备表实体类,而后创立页面输出根本信息,再而后上传此类点击确定即可: @TableName(value = "component")@Datapublic class ComponentPO { @TableId private Integer componentId; //我的项目id private Integer projectId; //组件形容 private String componentDes; //组件名 private String componentName; //创立工夫 private Date createAt; @TableLogic private Integer isDeleted;} ...

September 11, 2023 · 1 min · jiezi

关于java:探索-Java-线程的创建

by emanjusaka from https://www.emanjusaka.top/archives/7 彼岸花开可奈何 本文欢送分享与聚合,全文转载请留下原文地址。前言在并发编程中咱们为啥个别选用创立多个线程去解决工作而不是创立多个过程呢?这是因为线程之间切换的开销小,实用于一些要求同时进行并且又要共享某些变量的并发操作。而过程则具备独立的虚拟地址空间,每个过程都有本人独立的代码和数据空间,程序之间的切换会有较大的开销。上面介绍几种创立线程的办法,在这之前咱们还是要先理解一下什么是过程什么是线程。 一、什么是过程和线程线程是过程中的一个实体,它自身是不会独立存在的。过程是零碎进行资源分配和调度的根本单位,线程则是过程的一个执行门路,一个过程中至多有一个线程,过程中的多个线程共享过程的资源。 过程和线程的关系图如下: 从下面的图中,咱们能够晓得一个过程中有多个线程,多个线程共享过程的堆和办法区资源,然而每个线程都有本人的程序计数器和栈区域。堆是一个过程中最大的一块内存,堆是被过程中的所有线程共享的,是过程创立时调配的,堆外面次要寄存应用new操作创立的对象实例。办法区则用来寄存 JVM 加载的类、常量及动态变量等信息,也是线程共享的。 二、线程的创立Java 中有几种线程创立的形式: 实现 Runnable 接口的 run 办法继承 Thread 类并重写 run 的办法<!----> 应用 FutureTask 形式应用线程池创立2.1、实现 Runnable 接口的 run 办法public static void main(String[] args) { RunableTask task = new RunableTask(); new Thread(task).start(); new Thread(task).start(); } public static class RunableTask implements Runnable { @Override public void run() { System.out.println("I am a child thread"); } }// 输入I am a child threadI am a child thread这段代码创立了一个RunableTask类,该类实现了Runnable接口,并重写了run()办法。在run()办法中,它打印了一条音讯:"I am a child thread"。 ...

September 11, 2023 · 3 min · jiezi

关于java:Spring-Cloud-Gateway新一代微服务-API-网关用起来真优雅

1.网关介绍如果没有网关,难道不行吗?性能上是能够的,咱们间接调用提供的接口就能够了。那为什么还须要网关? 因为网关的作用不仅仅是转发申请而已。咱们能够试想一下,如果须要做一个申请认证性能,咱们能够接入到 API 服务中。然而假使后续又有服务须要接入,咱们又须要反复接入。这样咱们不仅代码要反复编写,而且前期也不利于保护。 因为接入网关后,网关将转发申请。所以在这一层做申请认证,人造适合。这样这须要编写一次代码,在这一层过滤结束,再转发给上面的 API。 所以 API 网关的通常作用是实现一些通用的性能,如申请认证,申请记录,申请限流,黑白名单判断等。 API网关是一个服务器,是零碎的惟一入口。 API网关形式的外围要点是,所有的客户端和生产端都通过对立的网关接入微服务,在网关层解决所有的非业务性能。通常,网关提供REST/HTTP的拜访API。 2.Spring Cloud Gateway介绍Spring Cloud Gateway是Spring Cloud的新一代API网关,基于WebFlux框架实现,它旨在为微服务架构提供一种简略而无效的对立的API路由治理形式。 Spring Cloud Gateway作为Spring Cloud生态系统中的网关,指标是代替Netflix ZUUL,具备更好的性能、更强的扩展性、以及更丰盛的性能个性,其不仅提供对立的路由形式,并且基于Filter链的形式提供了网关根本的性能,例如:平安,监控/埋点,限流等。 3.Spring Cloud Gateway的个性基于Spring Framework 5, Project Reactor和Spring Boot 2.0动静路由:可能匹配任何申请属性能够对路由指定 Predicate 和 Filter集成Hystrix断路器集成Spring Cloud DiscoveryClient 服务发现性能易于编写的Predicate和Filter申请限流反对门路重写4.Spring Cloud Gateway的三大外围概念路由(Route): 路由是网关最根底的局部,路由信息由一个ID,一个指标URI,一组断言和过滤器组成。路由断言Predicate用于匹配申请,过滤器Filter用于批改申请和响应。如果断言为true,则阐明申请URI和配置匹配,则执行路由。 spring: cloud: gateway: # 定义多个路由 routes: # 一个路由route的id - id: path_route # 该路由转发的指标URI uri: https://example.org # 路由条件汇合 predicates: - Path=/test/** # 过滤器汇合 filters: - AddRequestHeader=X-Request-Id, 1024 - AddRequestParameter=color, red断言(Predicate): 参考Java8中的断言Predicate,用于实现申请匹配逻辑,例如匹配门路、申请头、申请参数等。申请与断言匹配则执行该路由。 ...

September 11, 2023 · 3 min · jiezi

关于java:Spring-MVC-六-DispatcherServlet处理请求过程

后面讲过了DispatcherServlet的初始化过程(源码角度的DispatcherServlet的具体初始化过程还没说,先放一放),明天说一下DispatcherServlet解决申请的过程。 处理过程WebApplicationContext绑定在以后request属性上(属性键值DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE)localResolver绑定在request的属性上(属性键值LOCALE_RESOLVER_ATTRIBUTE)themeResolver绑定在request属性上(属性键值HEME_RESOLVER_ATTRIBUTE)servlet容器配置了multipart resolver,并且以后申请蕴含multpart file,则包装以后request为MultipartHttpServletRequest。匹配以后申请的handlerMappings,获取到HandlerExecutionChain,匹配getHandlerAdapter调用HandlerExecutionChain的applyPreHandle办法:获取拦截器,调用拦截器的preHandle办法调用HandlerAdapter的handle办法,这儿会匹配并执行Conroller办法执行HandlerExecutionChain的applyPostHandle办法:调用拦截器的postHandle办法执行processDispatchResult办法,其中会调用拦截器的afterCompletion办法以上过程都被try catch包围起来了,所以才会有Spring MVC的异样解决机制:应用层不论哪里(controller、service、dao层...)抛出的异样,都会在这里被捕捉到,注册到WebApplicationContext容器中的HandlerExceptionResolver beans就有机会对立解决异样。 能够通过DispatcherServlet的初始化参数来定制化其行为,参数能够通过web.xml指定,包含: contextClass:指定以后DispatcherServlet绑定的容器类(ConfigurableWebApplicationContext的实现类),默认为XmlWebApplicationContext 。contextConfigLocation:上述contextClass指定的容器类的配置文件的地位,能够指定多个配置文件,逗号宰割。namespace:WebApplicationContext的namespace,默认[servlet-name]-servlet。throwExceptionIfNoHandlerFound:某一申请request没有匹配到handle的话,是否抛出NoHandlerFoundException异样,NoHandlerFoundException随后能够被HandlerExceptionResolver捕捉并解决。默认状况下该参数设置为false,DispatherServlet不抛出异样、间接导航到404。留神:如果配置了默认Servlet Handler(default servlet handling)的话,那么没匹配到的request会导航到默认handler解决,永远不会呈现404。拦挡HandlerMapping反对拦截器,拦截器需实现SpringMVC的HandlerInterceptor接口(org.springframework.web.servlet),蕴含如下办法: preHandle:HandlerMapping解决申请之前产生。postHandle:HandlerMapping解决申请之后产生。afterCompletion:整个申请解决实现之后。preHandle返回true则申请持续被解决,返回false则后续不会再解决申请。 postHandle对@ResponseBody和ResponseEntity办法简直没有什么作用,因为response曾经在postHandle之前被HandlerAdapter解决实现了,因而不可能被postHandle批改了。比方你想通过postHandle在response header中减少一个头信息是不可能的了。这种需要只能通过ResponseBodyAdvice、 Controller Advice 或者间接在RequestMappingHandlerAdapter中间接实现。 异样解决HandleMapping、HandlerAdapter、Controller中产生的任何异样,都能够被DispatcherServlet捕捉、交给HandlerExceptionResolver bean去解决异样。 SpringMVC提供如下异样解决的实现类: 异样解决链咱们能够配置多个HandlerExceptionResolver作为异样解决链(exception resolver chain)来解决异样,能够通过order属性指定其解决程序,order值越大、在chain中排名越靠后。 HandlerExceptionResolver能够返回: ModelAndView :谬误页面。空ModelAndView:谬误曾经被解决,不须要导航到谬误页面。Null:以后Resolver不解决,异样持续向上抛给chain中前面的Resolver,直到最初如果没有Resolver解决该异样的话,异样会抛出给Servlet容器(比方给到Tomcat,这种状况下Tomcat也不解决,可能就会间接抛出给前台)。SpringMVC会主动配置内建的异样处理器,咱们能够通过配置客户化异样处理器。SpringMVC的异样解决绝对比拟重要,前面咱们还会从源码和利用角度做一次剖析。 容器谬误页面如果异样没有被任何HandlerExceptionResolver解决,而且,如果response status被设置为4xx、5xx的话,servlet容器(比方tomcat)会导航到默认的错误处理页面,如果容器配置了错误处理页面的话。能够通过web.xml配置: <error-page> <location>/error</location></error-page>以上配置须要DispatcherServlet进一步解决: @RestControllerpublic class ErrorController { @RequestMapping(path = "/error") public Map<String, Object> handle(HttpServletRequest request) { Map<String, Object> map = new HashMap<>(); map.put("status", request.getAttribute("jakarta.servlet.error.status_code")); map.put("reason", request.getAttribute("jakarta.servlet.error.message")); return map; }}上一篇 Spring MVC 五 - DispatcherServlet初始化过程(续)

September 11, 2023 · 1 min · jiezi

关于java:Java并发程序设计总览学习

1、应用线程的一些教训设置名称 无论何种形式,启动一个线程,就要给它一个名字!这对排错诊断系统监控有帮忙。否则诊断问题时,无奈直观晓得某个线程的用处。响应中断 程序应该对线程中断作出失当的响应。应用ThreadLocal 它的功能非常简单,就是为每一个应用该变量的线程都提供一个变量值的正本,是每一个线程都能够独立地扭转本人的正本,而不会和其它线程的正本抵触。从线程的角度看,就如同每一个线程都齐全领有该变量。 留神:应用ThreadLocal,个别都是申明在动态变量中,如果一直的创立ThreadLocal而且没有调用其remove办法,将会导致内存泄露。 2、Executor :ExecutorService和Future为了不便并发执行工作,呈现了一种专门用来执行工作的实现,也就是Executor。由此,工作提交者不须要再创立治理线程,应用更不便,也缩小了开销。 java.util.concurrent.Executors是Executor的工厂类,通过Executors能够创立你所须要的Executor。 ExecutorService executor = Executors.newSingleThreadExecutor();Callable<Object> task = new Callable < Object > () { public Object call () throws Exception { Object result = "..."; return result; }} ;Future<Object> future = executor.submit(task);future.get();有两种工作:Runnable、Callable,Callable是须要返回值的工作。 Task Submitter把工作提交给Executor执行,他们之间须要一种通信伎俩,这种伎俩的具体实现,通常叫做Future。Future通常包含get(阻塞至工作实现),cancel,get(timeout)(期待一段时间)等等。Future也用于异步变同步的场景。 3、阻塞队列: put和take、offer和poll、drainTo 阻塞队列,是一种罕用的并发数据结构,罕用于生产者-消费者模式。在Java中,有三种罕用的阻塞队列:ArrayBlockingQueueLinkedBlockingQueueSynchronousQueue 应用阻塞队列: Monitor的实践模型 4、ReentrantLock和SynchronizedSynchronized是Lock的一种简化实现,一个Lock能够对应多个Condition,而synchronized把Lock和Condition合并了,一个synchronizedLock只对应一个Condition,能够说Synchronized是Lock的简化版本。 在JDK5,Synchronized要比Lock慢很多,然而在JDK6中,它们的效率差不多。 5、Lock-free算法LockFree算法,不须要加锁。通常都是三个局部组成:①循环②CAS (CompareAndSet)③break 进一步应用Lock-Free数据结构 class BeanManager { private ConcurrentMap<String, Object> map = new ConcurrentHashMap<String, Object>(); public Object getBean (String key) { Object bean = map.get(key); if (bean == null) { map.putIfAbsent(key, createBean()); bean = map.get(key); } return bean; }}ConcurrentHashMap并没有实现Lock-Free,只是应用了拆散锁的方法使得可能反对多个Writer并发。ConcurrentHashMap须要应用更多的内存。 ...

September 10, 2023 · 1 min · jiezi

关于java:volatile和synchronized关键字介绍

背景上篇文章介绍了java的53个关键字,其中个人感觉volatile和synchronized两个java关键字能够重点具体介绍下.这两个关键字都是作用在多线程并发环境下,其中volatile能保障操作对象的可见性和有序性,synchronized能保障操作对象的原子性和可见性. JMM多线程并发环境有必要先理解JMM(java memory model),在理解JMM前咱们须要晓得PC物理机的内存模型,如图:CPU解决指令的性能很高,而CPU间接从内存中读取数据的性能相对来说就很慢了,所以如果间接都从内存中读取数据,会重大拖慢PC的处理速度.所以才会有CPU缓存,个别都是3级缓存,级别越高CPU读取性能越高,CPU内存也有寄存器,它的读取性能是最高的.JMM内存模型如图:留神JMM不是实在物理的内存构造,它是java虚拟机栈工作内存的标准.每个线程都有本人的工作内存,线程对所有变量的操作都必须在工作内存中进行,而不能间接对主存进行操作,并且每个线程不能拜访其余线程的工作内存. 可见性当一个共享变量被批改时,它的值会立刻更新到主内存,当有其余线程读取时,都会去主存中读取最新值.阐明该变量是对所有线程是具备可见性. 有序性java虚拟机的编译器和处理器会对指令进行重排序优化,来晋升代码的执行效率.重排序会根据happens-before准则,保障指令代码的有序性.重排序不会影响单线程状况下的执行后果,但多线程并发的状况下可能会影响到它的正确性.所以并发状况下须要避免虚拟机对肯定代码的重排序. 原子性多个代码执行,要么同时都执行,要么都不执行,像原子一样不能被宰割,即这些操作不可被中断,咱们就说这些操作是具备原子性. volatile可见性代码例子public class VisibilityDemo { static boolean flag = true; public static void main(String[] args) throws Exception { new Thread(()->{ System.out.println("开始循环啦~~~"); while(flag){ } System.out.println("循环退出了~~~"); }, "t1").start(); Thread.sleep(2000); new Thread(()->{ System.out.println("flag的值批改为false"); flag=false; }, "t2").start(); }}t1线程中的flag始终获取不到t2线程批改flag变量后的值所以始终在循环中,运行后果如下图: 对变量应用volatile润饰就能够退出循环了. public class VisibilityVolatileDemo { static volatile boolean flag = true; public static void main(String[] args) throws Exception { new Thread(()->{ System.out.println("开始循环啦~~~"); while(flag){ } System.out.println("循环退出了~~~"); }, "t1").start(); Thread.sleep(2000); new Thread(()->{ System.out.println("flag的值批改为false"); flag=false; }, "t2").start(); }}t1线程中的flag能获取到t2线程批改flag变量后的值所以就退出循环了,运行后果如下图: ...

September 10, 2023 · 2 min · jiezi

关于java:在国企和央企当程序员体验太真实了

大家好,又到了求职季,给大家分享一段一位网友的央企工作经验: 起源:zhihu.com/question/276681361/answer/2134441878心愿对于张望工作机会的小伙伴,有些参考~ 我校招退出了某垄断央企,在外面从事研发工程师的工作。上面我将分享一些入职后的一些心得体会。在国企中,开发是最底层最苦逼的存在,在互联网可能程序员还可能和产品经理argue,然而在国企中,根本都是领导拍脑袋的决定,即使这个需要不合理,或者会造成很多问题等等,你所须要的就是去执行,而后实现领导的工作。 上面我会分享一些国企开发日常。 1、大量外部我的项目在入职前几个月,咱们都要基于一种国产编辑器培训,说白了团体的领导看市场上有Eclipse,idea这样编辑器,而后就说咱们外部也要搞一个国产的编辑器,所有的我的项目都要强制基于这样一个编辑器。 在国企里搞开发,通常会在我的项目中塞入一大堆其余我的项目插件,原本一个可能基于eclipse轻松搞定的事件,在国企须要通过2、3个我的项目跳转。但国企的我的项目原本就是领导导向,只需给领导演示即可,并不具备实用性。所以在一个我的项目集成多个我的项目后,能够被称为X山。 你集成的其余我的项目会忽然出一些十分奇怪的谬误,从而导致本人我的项目报错。然而这也没有方法,在国企中搞开发,有些我的项目或者插件是被要求必须应用的。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice2、外包说到开发,在国企必然是离不开外包的。在我这个公司,能够分为直聘+劳务差遣两种用工模式,劳务差遣就是咱们通常所说的外包,直聘就是通过校招进来的校招生。 直聘的劣势在于会有公司的对立编制,能够在零碎外部调动。当然这个调动是只存在于规定中,99.9%的普通员工是不会调动。劳务差遣通常是社招进来的或者外包。在咱们公司中,我的项目干活的主力都是外包。 我可能因为本身原本就比拟喜爱技术,并且感觉总要干几年技术能力对我的项目会有比拟深刻的了解,所以被动要求干活,也就是和外包一起干活。一开始我认为外包可能学历都比拟低或者都不行,然而在理论干活中,某些外包的技术执行力是很强的,大多数我的项目的理论控制权在外包上,咱们负责管理给钱,兴许对我的项目的理解的深度和颗粒度上不如外包。 上次我闲暇工夫与一个快40岁的外包聊天,才发现他之前在腾讯、京东等互联网公司都有工作过,架构设计方面都特地有教训。而后我问他为什么来到互联网公司,他就说身材受不了。所以身材如果不是特地好的话,国企也是一个不错的抉择。 3、技术栈在日常开发中,国企的技术个别不会特地新。我目前接触的技术,前端是JSP,后端是Springboot那一套。开发的过程个别不会波及到多线程,高并发等技术。基本上都是些表的设计和增删改查。如果集体对技术没啥谋求,可能一天的活2,3小时就干完了。如果你对技术有谋求,能够在剩余时间去折腾新技术,自由度比拟高。 所以在国企,作为一般基层员工,个别会有许多属于本人的工夫,你能够用这些工夫去刷手机,当然也能够去用这些工夫去复盘,去学习新技术。在社会中,总有一种声音说在国企呆久了就待废了,很多时候并不是在国企待废了,而是本人让本人待废了。 4、升职空间每个研发类央企都有本人的职级序列,个别分为技术和治理两种序列。 首先,治理序列你就不必想了,那是留给有关系+有能力的人的。其实,集体感觉在国企有关系也是一种有能力的体现,你的关系可能给公司解决问题那也行。 其次,技术序列大多数状况也是依据你的工龄长短和PPT能力。毕竟,国企研发大多数干的活不是研发与这个零碎的接口,就是给某个成熟互联网产品套个壳。技术深度基本上就是一个大专生去培训机构培训3个月的后果。你想要往上走,那就要学会去PPT,学会锤炼本人的表达能力,学会如何讲到领导想听到的那个点。既然来了国企,就不要再想钻研技术了,除非你想跳槽互联网。 最初,在国企底层随着工龄增长工资增长(不当领导)还是比拟容易的。然而,如果你想当领导,那还是天时地利人和缺一不可。 5、钱在后面说到,咱们公司属于老本单位,到工资这一块就体现为钱是总部发的。工资形成分由工资+年终奖+福利组成。 1.工资形成中没有绩效,没有绩效,没有绩效,重要的事件说三遍。工资是依照你的级别+职称来决定的,公司会有严格的等级晋升制度。然而根本能够概括为混年限。年限到了,你的级别就下来了,年限没到,你天天加班,与工资没有一毛钱关系。 2.年终奖,是总部给公司一个大的总包,而后大领导依据理论状况对不同部门调配,部门领导再依据每个人的工作状况将奖金调配到集体。所以,你干不干活,活干得好不好只和你的年终奖相干。据我理解一个部门外部员工的年终奖并不会相差太多。 3.最初就是福利了,以咱们公司为例,大抵能够分为通信贴补+房补+饭补+一些七七八八的货色,大多数国企都是这样模式。 总结1、陈词滥调了。在国企,工资待遇能够保障你在一线城市吃吃喝喝和根本的生存须要没问题,当然房子是不必想的了。 2、国企搞开发,技术不会特地新,很多时候是项目管理的角色。工作内容根本体现为领导的决定。 3、国企钻研技术没有意义,想当领导,就多学习做PPT和领导搞好关系。或者当一个平庸的人,混吃等死,把工夫留给家人,也不乏是一种好抉择。 近期热文举荐: 1.1,000+ 道 Java面试题及答案整顿(2022最新版) 2.劲爆!Java 协程要来了。。。 3.Spring Boot 2.x 教程,太全了! 4.别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!! 5.《Java开发手册(嵩山版)》最新公布,速速下载! 感觉不错,别忘了顺手点赞+转发哦!

September 10, 2023 · 1 min · jiezi

关于java:高并发系统设计之限流

本文已收录至GitHub,举荐浏览 Java随想录 微信公众号:Java随想录 原创不易,重视版权。转载请注明原作者和原文链接当咱们议论Web利用或者服务,一个重要的话题就不能防止:「限流」。这是一种爱护零碎和维持服务稳定性的重要伎俩。 尤其当咱们应用Java来进行利用开发时, 这个话题就显得尤为重要。限流能够保障一部分的申请失去失常的响应,是一种自我爱护的措施。 限流能够保障应用无限的资源提供最大化的服务能力,依照预期流量提供服务,超过的局部将会拒绝服务、排队或期待、降级等解决。 在这篇博客中,咱们将探讨限流技术。心愿这篇博客可能给予正在解决或者行将面临流量治理问题的读者们一些启发和帮忙。 首先,先来理解下几种限流算法。 限流算法计数器算法计数器算法是限流算法里最简略也是最容易实现的一种算法。 这种算法的大略思维如下: 设置一个计数器,比方咱们规定接口A在1分钟内拜访次数不能超过1000,咱们能够对固定工夫窗口1分钟进行计数,每有一个申请,计数器就+1,如果申请数超过了阈值,则舍弃该申请,当工夫窗口完结时,重置计数器为0。 计数器算法尽管简略,然而有一个非常致命的问题,那就是「临界问题」。 假如有一个用户,他在1~1:58前都没有申请,在1:59秒时霎时发送了1000个申请,并且1:01又发送了1000个申请,那么其实用户在 2秒外面,霎时发送了2000个申请,然而因为申请在两次工夫窗口的重置节点,计数器会断定没有超过阈值。 用户通过在工夫窗口的重置节点处突发申请, 能够霎时超过咱们的速率限度。用户有可能利用这个破绽卡Bug,霎时压垮咱们的利用。 毛病:没有方法避免工夫范畴临界点突发大流量,很可能在工夫范畴交界处被大量申请间接打到降级,影响后续服务。 滑动窗口滑动窗口算法解决了上诉计数器算法的毛病。计数器的工夫窗口是固定的,而滑动窗口的工夫窗口是「滑动」的,也就是动静的。 图中,整个红色的矩形框示意一个工夫窗口,在咱们的例子中,一个工夫窗口就是一分钟。而后咱们将工夫窗口进行划分。比方图中,咱们就将滑动窗口划成了6格,所以每格代表的是10秒钟。每过10秒钟,咱们的工夫窗口就会往右滑动一格。 这里的10秒称之为「步长」,1分钟称之为「窗口大小」。 那么滑动窗口怎么解决方才的临界问题的呢? 咱们能够看上图,0:59达到的1000个申请会落在灰色的格子中,而1:01达到的申请会落在橘黄色的格子中。当工夫达到1:00时,咱们的窗口会往右挪动一格,那么此时工夫窗口内的总申请数量一共是2000个,超过了限定的1000个,所以此时可能检测进去触发限流。 当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越准确。 然而计算器算法和滑动窗口算法都有一个固有的问题:「它不能平滑地管制申请流量」。 以下面的例子阐明,0:59和1:01秒都有1000个申请,而其余时间段没有申请,从宏观角度看,整个零碎的申请解决速率并不安稳,而是有着显著的稳定。 这样的稳定可能导致系统的负载霎时回升,对资源造成压力,同时也可能影响到零碎的稳定性。所以,尽管滑动窗口算法可能管制某个时间段内的申请总量,但它无奈确保申请流量的安稳,可能会导致宏观视角下的申请数量稳定较大。 漏桶算法说到漏桶算法的时候,咱们脑中先构思出一幅图:一个水桶,桶底下有一个小孔,水以固定的频率流出,水龙头以任意速率流入水,当水超过桶则「溢出」。 脑海中有这么一幅画面的时候,再举个例子: 假如咱们有一个漏桶,其容量为100字节,以每秒10字节的速率流出。当初,咱们有3个数据包,别离为20字节,50字节和120字节。 第一个数据包(20字节)进入漏桶,因为漏桶未满,数据包被胜利接管,并在两秒内发送实现(因为发送速度为10字节/秒)。接着第二个数据包(50字节)进入漏桶,同样,漏桶还未满,所以数据包被接管,并在五秒内发送实现。最初,第三个数据包(120字节)试图进入漏桶。但此时漏桶的残余容量不足以接管这个数据包,因而超出漏桶容量的数据(20字节)会被抛弃,只有100字节的数据可能被接管。而后,这100字节的数据在10秒内被发送实现。漏桶算法保障了固定的流出速率,这是漏桶算法的长处,也能够说是毛病。 毛病在于漏桶算法对「突发流量反馈不良」。 当大量数据忽然到来时,漏桶算法解决能力无限。一旦输出速率超过了漏桶的容量,所有溢出的数据都会被抛弃。 例如,如果咱们在短时间内发送大量数据,因为漏桶的固定进口速率,可能会导致大量数据失落,用户等待时间长,用户体验差。 始终恒定的解决速率有时候并不一定是好事件,对于突发的申请洪峰,在保障服务平安的前提下,应该尽最大致力去响应,这个时候漏桶算法显得有些僵滞,最终可能导致水位「溢出」,申请被抛弃。 令牌桶算法对于很多利用场景来说,除了要求可能限度数据的均匀传输速率外,还要求容许某种程度的突发传输。这时候漏桶算法可能就不适合了,令牌桶算法则更为适宜。 令牌桶算法的原理是零碎「以恒定的速率产生令牌」,而后把令牌放到令牌桶中,令牌桶有一个容量,当令牌桶满了的时候,再向其中放令牌,那么多余的令牌会被抛弃。 当想要解决一个申请的时候,须要从令牌桶中取出一个令牌,如果此时令牌桶中没有令牌,那么必须期待新的令牌被增加到桶中能力持续申请。 令牌桶算法能够通过限度可供立刻应用的令牌数量来控制数据的申请速率,容许突发流量在肯定水平上失去满足。 毛病:令牌桶的数量,生成的速度须要依据以往的零碎性能以及用户习惯等教训的累积来判断,因为令牌桶算法容许突发数据传输,如果没有其余机制来管制,可能会在网络中引发重大的拥塞,理论限流数难以预知。 限流实现咱们曾经探讨了限流算法的实践局部,上面来介绍具体在咱们的开发中该如何去实现限流。 Guava RateLimiter实现限流Guava工具包自带了「RateLimiter限流器」。 引入依赖 <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.1-jre</version></dependency>上面是一个应用的简略例子: import com.google.common.util.concurrent.RateLimiter;public class RateLimiterTest { public static void main(String[] args) { RateLimiter rateLimiter = RateLimiter.create(1); //创立一个每秒产生一个令牌的令牌桶 for (int i = 1; i <= 5; i++) { double waitTime = rateLimiter.acquire(i); //一次获取i个令牌 System.out.println("acquire:" + i + " waitTime:" + waitTime); } }}后果: acquire:1 waitTime:0.0acquire:2 waitTime:0.995081acquire:3 waitTime:1.998054acquire:4 waitTime:2.999351acquire:5 waitTime:3.999224能够发现等待时间差不多距离都是1秒。 ...

September 10, 2023 · 4 min · jiezi

关于java:高并发系统设计之负载均衡

本文已收录至GitHub,举荐浏览 Java随想录 微信公众号:Java随想录 原创不易,重视版权。转载请注明原作者和原文链接在咱们日常生活中,尤其是在拥挤的公共场所,咱们会看到很多排队等待的状况 —— 无论是在票房购票,超市结账,还是在银行期待服务。而为了防止让人们因过长的队伍和等待时间而感到焦躁,管理者往往会采取一种策略:开设更多的窗口或者柜台,将期待的人们平均地散布到各个地位去,这就是咱们生存中的「负载平衡」。 说回到计算机科学的世界里,负载平衡这个概念也施展着相似的作用。它就像是网络世界的向导,疏导来自用户的申请,确保每个服务器不会因为过多的申请而过载。 通过负载平衡,咱们能进步零碎的可用性,晋升响应速度,同时也能避免任何繁多的资源适度应用。总的来说,好的负载平衡让整个零碎运行得更加安稳,效率更高,就像是一个良好运行的机器,每个整机都在承当适宜本人的工作量。 当咱们的利用单实例不能撑持用户申请时,此时就须要扩容,从一台服务器扩容到两台、几十台、几百台。此时咱们就须要负载平衡,进行流量的转发。 本篇文章介绍几种罕用的负载平衡计划,心愿对大家可能有所启发。 DNS负载平衡一种是应用DNS负载平衡,行将域名映射多个IP。 DNS负载平衡是一种应用DNS(域名零碎)来扩散达到特定网站的流量的办法。 基本上,它是通过将一个域名解析到多个IP地址来实现的。当用户试图接入这个域名时,DNS服务器会依据肯定的策略抉择一个IP地址返回给用户,以此来实现网络流量的平衡调配。 举个例子来阐明: 假如你是一个大型电子商务网站的管理员,你的网站叫做www.myshop.com。因为你的业务正在快速增长,每天有数百万的用户拜访你的网站进行购物。如果所有的流量都集中在一台服务器上,那么可能会导致服务器过载,从而升高网站的性能甚至使其宕机。 为了解决这个问题,你决定采纳DNS负载平衡。你将运行网站的任务分配给三台不同的服务器(服务器A,服务器B,服务器C)。而后你设置你的DNS记录,以便当用户输出www.myshop.com时,他们能够被路由到任何一台服务器上。 例如,第一个用户可能被路由到服务器A,下一个用户可能被路由到服务器B,第三个用户可能被路由到服务器C,而后反复这个模式。这样,你就把流量平均分配到了所有的服务器上,从而加重了每台服务器的负载,并进步了网站的总体性能和可靠性。 DNS负载平衡蕴含多种策略: 轮询(Round Robin):轮询是一种最简略的办法,它将申请按程序调配到服务器上。例如,如果你有三个服务器A,B和C,那么第一个申请会发送到A,第二个发送到B,第三个发送到C,而后再从A开始。加权轮询(Weighted Round Robin):这是轮询的加强版本,在此策略中,每个服务器都调配有一个权重,权重较大的服务器接管更多的申请。起码连贯(Least Connections):在此策略中,新的申请会被发送到以后领有起码沉闷连贯的服务器。源地址哈希(IP Hash):依据源IP地址确定申请的服务器,能够保障同一用户的申请总是拜访同一个服务器。响应工夫:依据服务器的响应工夫来调配申请,响应工夫短的服务器会接管到更多的申请。能够依据理论的场景须要,抉择最合适的负载平衡策略。 然而DNS负载平衡存在一些问题,DNS负载平衡最大的问题在于它「无奈实时地响应后端服务器的状态变动」。 如果一个服务器忽然宕机,DNS负载平衡可能依然会将申请发送到这个曾经宕机的服务器上,直至DNS记录刷新,这可能导致用户体验降落和服务中断。 举个例子: DNS缓存了域名和IP的映射关系,假如我A服务器呈现了故障须要下线,即便批改了缓存记录,要使其失效也须要较长的工夫,这段时间,DNS依然会将域名解析到已下线的A服务器上,最终导致用户拜访失败,影响用户体验。 对于DNS缓存多久工夫失效,能够参考阿里云的帮忙文档:https://help.aliyun.com/document_detail/39837.html。 总结一下DNS负载平衡的优缺点: 长处:配置简略,将负载平衡的工作交给了DNS服务器,省去了治理的麻烦。毛病:DNS会有肯定的缓存工夫,故障后切换工夫长。Nginx负载平衡Nginx是一种高效的Web服务器/反向代理服务器,它也能够作为一个负载均衡器应用。在负载平衡配置中,Nginx能够将接管到的申请散发到多个后端服务器上,从而进步响应速度和零碎的可靠性。Nginx是负载平衡比拟罕用的计划。 负载平衡算法Nginx负载平衡是通过「upstream」模块来实现的,内置实现了三种负载策略,配置还是比较简单的。 轮循(默认):Nginx依据申请次数,将每个申请平均调配到每台服务器。起码连贯:将申请调配给连接数起码的服务器。Nginx会统计哪些服务器的连接数起码。IP Hash:每个申请按拜访IP的hash后果调配,这样每个访客固定拜访一个后端服务器,能够解决session共享的问题。fair(第三方模块):依据服务器的响应工夫来调配申请,响应工夫短的优先调配,即负载压力小的优先会调配。须要装置「nginx-upstream-fair」模块。url_hash(第三方模块):按拜访的URL的哈希后果来调配申请,使每个URL定向到一台后端服务器,如果须要这种调度算法,则须要装置「nginx_upstream_hash」模块。一致性哈希(第三方模块):如果须要应用一致性哈希,则须要装置「ngx_http_consistent_hash」模块。负载平衡配置Nginx负载平衡配置示例如下: http { upstream myserve { server 192.168.0.100:8080 weight=1 max_fails=2 fail_timeout=10; server 192.168.0.101:8080 weight=2; server 192.168.0.102:8080 weight=3; # server 192.168.0.102:8080 backup; # server 192.168.0.102:8080 down; # server 192.168.0.102:8080 max_conns=100; } server { listen 80; location / { proxy_pass http://myserve; } }}weight:weight是权重的意思,上例配置,示意6次申请中,调配1次,2次和3次。max_fails:容许申请失败的次数,默认为1。超过max_fails后,在fail_timeout工夫内,新的申请将不会调配给这台机器。fail_timeout:默认为10秒,上诉代码配置示意失败2次之后,10秒内 192.168.0.100:8080不会解决新的申请。backup:备份机,所有服务器挂了之后才会失效,如配置文件正文局部,只有192.168.0.100和192.168.0.101都挂了,才会启用192.168.0.102。down:示意某一台服务器不可用,不会将申请调配到这台服务器上,该状态的应用场景是某台服务器须要停机保护时设置为down,或者公布新性能时。max_conns:限度调配给某台服务器解决的最大连贯数量,超过这个数量,将不会调配新的连贯给它。默认是0,示意不限度最大连贯。它所起到的作用是避免服务器因连贯过多而导致宕机,限度同时解决的最大连贯数量。超时配置proxy_connect_timeout:后端服务器连贯的超时工夫,默认是60秒。proxy_read_timeout:连贯胜利后等待后端服务器响应工夫,也能够说是后端服务器解决申请的工夫,默认是60秒。proxy_send_timeout:发送超时工夫,默认是60秒。被动健康检查与被动健康检查Nginx负载平衡有个毛病,Nginx的服务查看是惰性的,Nginx只有当有拜访时后,才发动对后端节点探测。 ...

September 10, 2023 · 2 min · jiezi

关于java:如何使用RequiredArgsConstructor注解

@Autowired的注入过多,这个别没什么问题,因为注入的字段是无限的。然而业务代码,不加正文,单文件长度超过 2000 行的亘古未有。注入的属性能达到十几个之多。这部分注入代码真是脏乱差。不仅如此,这些字段,还会在 IDE 里变成灰色,通知你未被初始化,代码变成了丑八怪。事实上,Spring 从 4.0 开始, 就 不 推 荐 使 用 属 性 注 入 模 式 了  ,起因是它能够让咱们疏忽掉一些代码可能变坏的隐患。你能够自行搜寻这个问题,咱们也不开展说了。既然 Spring 举荐应用显示的 Setter 和结构器形式,那咱们就切换一下实现计划。Setter 办法基本上用的人比拟少,因为它更加臭更加长。要是给每一个属性写一个 set 办法,我预计你即应用代码生成器也玩吐了。结构器注入那么,结构器的办法就成了咱们的首选。样例代码如下: public class GoodsServiceImpl implements GoodsSrv {      private GoodsRepo goodsRepo;     private TagRepo tagRepo;     private TagRefRepo tagRefRepo;     private BrandRepo brandRepo;     private UnitRepo unitRepo;      public GoodsServiceImpl(             GoodsRepo goodsRepo,             TagRepo tagRepo,             TagRefRepo tagRefRepo,             BrandRepo brandRepo,             UnitRepo unitRepo) {         this.goodsRepo = goodsRepo;         this.tagRefRepo = tagRefRepo;         this.tagRefRepo = tagRefRepo;         this.brandRepo = brandRepo;         this.unitRepo = unitRepo;         this.tagRepo = tagRepo;     } }Spring 不须要退出其余注解,就能够应用结构器实现注入。问题是,咱们仍然要写很多代码。这个时候,你可能想到了 Lombok 的 AllArgsConstructor 注解。但它是针对于全副的属性的,如果类中有一些非 Bean  的属性,Spring 就会晕菜。这个时候,就能够应用 RequiredArgsConstructor 了。代码如下:@Service @RequiredArgsConstructor public class GoodsServiceImpl implements GoodsSrv {     final GoodsRepo goodsRepo;     final TagRepo tagRepo;     final TagRefRepo tagRefRepo;     final BrandRepo brandRepo;     final UnitRepo unitRepo; }咱们把须要注入的属性,批改成 final 类型的(或者应用 @NotNull 注解,不举荐),这些属性将形成默认的结构器。Java 要求 final 类型的属性必须要初始化,如果没有构造方法代码就会变红。咱们能够看到批改之后的 IDE,宜人的灰色提醒也隐没了。这样的代码,是十分简洁的。更高级一点RequiredArgsConstructor 注解,你还能够像上面这样写。即便是把 @__ 换成 @_,或者换成 @___,也是能失常的运行。 @RequiredArgsConstructor(onConstructor = @__(@Autowired))它的意思是,给应用 Lombok 生成的结构器办法,退出一个 @Autowired 注解。这是彻头彻尾的 Lombok 语法,不过当初的 Spring 曾经不须要退出这样的注解就能运行了。

September 10, 2023 · 1 min · jiezi

关于java:SpringCloudGateway-网关之我见

一、概述 在Spring-Cloud-Gateway之申请解决流程中最终网关是将申请交给过滤器链表进行解决。 外围接口:GatewayFilter,GlobalFilter,GatewayFilterChain。 二、网关过滤器作用 当应用微服务构建整个 API 服务时,个别有许多不同的利用在运行,如上图所示的mst-user-service、mst-good-service和mst-order-service,这些服务都须要对客户端的申请的进行 Authentication。最简略粗犷的办法就是像上图一样,为每个微服务利用都实现一套用于校验的过滤器或拦截器。 通过前置的网关服务来实现这些非业务性质的校验。 三、Filter 的生命周期 Spring Cloud Gateway 的 Filter 的生命周期有两个:“pre” 和 “post”。 “pre”和 “post” 别离会在申请被执行前调用和被执行后调用,和 Zuul Filter 或 Spring Interceptor 中相干生命周期相似,但在模式上有些不一样。 Zuul 的 Filter 是通过filterType()办法来指定,一个 Filter 只能对应一种类型,要么是 “pre” 要么是“post”。Spring Interceptor 是通过重写HandlerInterceptor中的三个办法来实现的。而 Spring Cloud Gateway 基于 Project Reactor 和 WebFlux,采纳响应式编程格调,关上它的 Filter 的接口GatewayFilter你会发现它只有一个办法filter。 四、外围接口解读 4.1、GatewayFilterChain--网关过滤链表 /** 网关过滤链表接口用于过滤器的链式调用 */public interface GatewayFilterChain { ...

September 10, 2023 · 5 min · jiezi

关于java:Java-中-cas-是什么怎样使用-cas

CAS是Compare And Swap(比拟并替换)的缩写,是一种非阻塞式并发控制技术,用于保障多个线程在批改同一个共享资源时不会呈现竞争条件,从而防止了传统锁机制的各种问题。在Java中,CAS次要是通过java.util.concurrent.atomic包下的一些类和办法来实现的,上面咱们就来具体理解一下CAS及其在Java中的应用。 什么是CAS?CAS是一种非阻塞式并发控制技术,它次要用于解决多个线程同时拜访同一个共享资源时可能呈现的竞争条件问题。为了保证数据的一致性和正确性,咱们通常须要采取同步机制来对共享资源进行加锁。然而,传统的锁机制在高并发场景下会带来重大的性能问题,因为所有线程都须要期待锁的开释能力进行操作,这就会导致大量线程的阻塞和唤醒,进而升高了零碎的并发性能。 为了解决这个问题,CAS应运而生。它是一种无锁的同步机制,能够在不应用锁的状况下实现数据的同步和并发管制。CAS的核心思想是:在执行操作之前,先比拟以后内存中的值是否等于期望值,如果相等,则执行批改操作;如果不相等,则不执行批改操作,持续进行比拟,直到内存中的值与期望值相等为止。这个过程中不会呈现线程的阻塞和唤醒,因而能够进步零碎的并发性能。 Java中的CAS在Java中,CAS次要是通过java.util.concurrent.atomic包下的一些类和办法来实现的。这些类和办法提供了一种原子操作的形式,能够保障多个线程同时拜访同一个共享资源时不会呈现竞争条件。 AtomicBooleanAtomicBoolean类示意一个布尔类型的原子变量,它提供了一些原子操作方法,例如compareAndSet、getAndSet、weakCompareAndSet等,能够保障对该变量的操作是原子的。 上面是一个示例代码: import java.util.concurrent.atomic.AtomicBoolean;public class AtomicBooleanTest { private static AtomicBoolean flag = new AtomicBoolean(false); public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { while (!flag.compareAndSet(false, true)) { System.out.println(Thread.currentThread().getName() + ": try again"); } System.out.println(Thread.currentThread().getName() + ": success"); },"Thread-1"); Thread t2 = new Thread(() -> { while (!flag.compareAndSet(false, true)) { System.out.println(Thread.currentThread().getName() + ": try again"); } System.out.println(Thread.currentThread().getName() + ": success"); },"Thread-2"); t1.start(); t2.start(); t1.join(); t2.join(); }}在这个例子中,咱们创立了一个AtomicBoolean类型的变量flag,并定义了两个线程t1和t2,它们都会一直地尝试将flag的值由false变为true,直到胜利为止。如果两个线程同时尝试批改flag的值,只有一个线程可能获得成功,另一个线程会持续尝试,直到胜利为止。 ...

September 10, 2023 · 2 min · jiezi

关于java:Java自学网站推荐全网最靠谱

简介网上有各种Java学习网站,本文举荐的这个Java网站全网最靠谱,品质远超其余所有网站。 这个网站是:自学精灵,这是全网最强的Java学习网站,能够间接百度搜寻自学精灵,或者拜访:自学精灵 - IT技术星球。我不喜爱“全网最强”这样的字眼,但本站的内容的确是全网最强!(大家能够多找几个Java网站与本站进行比拟,必定会发现本站在品质、真实性、实用性上是当先的) 这个网站主打的就是:高质量、高实用性、高真实性。其余网站没有一个有这样的品质,其余网站根本都是:内容有就行了、推广进来就行了,品质、实用性、真实性都一般般。 举例来说:此站Java学习路线很精准,能够疾速入门和进阶;Java入门我的项目实战是从零开发我的项目,十天把握Java实战;Java面试题都是实在高频原创的;Java设计模式都是实在我的项目场景;JavaWeb高级实战都是实在我的项目场景...... 网站内容 本站内容很丰盛,蕴含从入门到高级的内容:Java学习路线、JavaWeb入门我的项目实战、Java实在面试题、简历优化、模仿面试、Offer抉择、Java设计模式实战、JavaWeb高级实战、Shiro我的项目实战、架构与微服务设计、高并发实战、网站进攻技术等。(局部内容正在更新中) 本网站适宜如下人群:入门学Java的、应届生想找工作的、想跳槽换工作的、想进阶为高级Java开发的、想进阶为Java架构师的、想升职加薪的、想进攻网站被黑客攻击的。 网站截图主页 Java学习路线 Java入门我的项目实战 Java面试题 Java高级实战 

September 9, 2023 · 1 min · jiezi

关于java:JavaHow-Java-Memory-Works

SourceHow Java Memory Works?. Before we move on to the performence… | by Berkay Haberal | Jul, 2023 | Stackademic (medium.com) Before we move on to the performence things, we need to learn that what is really going on in the background of JVM (Java Virtual Machine). 在开始探讨性能问题之前,咱们须要理解 JVM(Java 虚拟机)的后盾到底产生了什么。 This is the starting point of every developer who wants to learn and tune performance in order to gain some speed. So let’s dive into the world of codes. ...

September 9, 2023 · 4 min · jiezi

关于java:ACP

ACP:在CAP实践中,C(Consistency)示意数据一致性,A(Availability)示意可用性,P(Partition Tolerance)示意分区容错性。依据CAP实践,分布式系统无奈同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition Tolerance)这三个要求,只能在其中两个方面进行衡量取舍。在AP模式中,零碎优先保障可用性(Availability)和分区容错性(Partition Tolerance),而对于一致性(Consistency)会有肯定的就义。这样能够确保零碎在遇到分区和网络故障时依然可能提供服务,并尽可能减少对用户的影响。在CP模式下,当分布式系统产生网络分区或节点故障时,零碎会进行对外提供服务并期待所有节点达到统一的状态,保证数据的一致性。尽管在零碎恢复正常运行前可能会呈现一段时间的不可用状态,但能够确保数据的一致性和完整性,以满足对数据准确性要求较高的业务场景。

September 8, 2023 · 1 min · jiezi

关于java:微服务粗略

什么是分布式和微服务?类似点和不同点? 咱们之前写的代码和我的项目都是单体架构:就是将业务的所有性能集中在一个我的项目中开发,打成一个包部署。单体我的项目的构造很简略,而且部署成本低,然而代码都纠缠在一起,所以耦合度很高。 那分布式的特点就是将代码以业务的不同进行拆分成不同的模块,扩散部署在不同的机器上的,一个服务可能负责几个性能。然而总的数据可可能还是同一个数据库,当用户应用的时候,会去调用不同的模块执行工作,不同的模块之间通信须要网络。分布式的长处是升高服务耦合,有利于服务降级和拓展,毛病就是服务调用关系盘根错节 微服务的意思也就是将模块拆分成一个独立的服务单元通过接口来实现数据的交互,是一种通过良好架构设计的分布式架构。简略来说微服务就是很小的服务,小到一个服务只对应一个繁多的性能,只做一件事。这个服务能够独自部署运行,服务之间能够通过RPC来互相交互,每个微服务都是由独立的小团队开发,测试,部署,上线,负责它的整个生命周期。咱们能够应用SpringCloud去构建微服务架构。 微服务的长处有: 繁多职责:微服务拆分粒度更小,每一个服务都对应惟一的业务能力,做到繁多职责 服务自治:团队独立、技术独立、数据独立,独立部署和交付 面向服务:服务提供统一标准的接口,与语言和技术无关 隔离性强:服务调用做好隔离、容错、降级,避免出现级联问题 分布式和微服务的概念比拟类似,分布式属于微服务。然而分布式和微服务在架构、作用和粒度上有所区别。因而,两者的关系是既互相分割又互相区别。 nacous和eureka的区别? 首先是共同点: 首先都反对服务注册和服务拉取:就是说应用nacous和eureka都能够将我的项目的代码放到注册核心,而后当一个模块须要应用另一个模块的性能时,须要进行导入依赖,配置文件,而后增加@LoadBalanced注解进行负载平衡。 再引申一下负载平衡。SpringCloud底层是利用了Ribbon的组件来实现负载平衡性能的。当咱们输出的是服务器的名字的并运行的时候,LoadBalancerIntercepor这个拦截器会进行拦挡,拦挡后再通过LoadBalancerClient的getLoadBalancer办法依据服务id获取ILoadBalancer,而ILoadBalancer会拿着服务id去eureka或者nacos中获取服务列表并保存起来。在接下来还有一个getServer办法,它会利用内置的负载平衡算法,从服务列表中抉择一个。那此时咱们的申请就走到了服务提供者的某一个服务器上了。负载平衡能够使得申请更均匀,不会大量的呈现在某一台服务器上,减缓了服务器的压力。负载平衡的策略有很多,默认的是轮询策略。 都反对服务提供者心跳形式做衰弱检测:衰弱检测是指一个服务定时的向注册核心报告本人的状态,阐明本人还在运行,如果没有发送状态,那注册核心就会认为这个服务除了问题,就会间接将他剔除。 Nacos与Eureka的区别 Nacos反对服务端被动检测提供者状态:长期实例采纳心跳模式,非长期实例采纳被动检测模式。长期实例心跳不失常会被剔除,非长期实例则不会被剔除 Nacos反对服务列表变更的音讯推送模式,服务列表更新更及时 Nacos反对ap和cp两种形式;Eureka则只反对ap 咱们要理解这个区别,首先要先理解什么是cp和ap。 CAP分为了:C:Consistency(一致性),A:Availability(可用性),P:Partition tolerance(分区容错) CAP准则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance),然而CAP 准则批示3个因素最多只能同时实现两点,不可能三者兼顾,因为网络硬件必定会呈现提早丢包等问题,然而在分布式系统中,咱们必须保障局部网络通信问题不会导致整个服务器集群瘫痪,另外即便分成了多个区,当网络故障打消的时候,咱们仍然能够保证数据一致性,所以咱们必须保障分区容错性; 而对于一致性和可用性,咱们须要二选一,假如咱们抉择一致性,那咱们就不能让用户拜访无奈进行数据同步的机器,因为该机器上的数据和其余失常机器上的不统一,这样咱们就抛弃了可用性;假如咱们抉择可用性,那咱们就能够让用户拜访无奈进行数据同步的服务器,尽管保障了可用性,然而咱们无奈保证数据一致性。 AP:当两个服务之间的通信因为网络起因或其余起因呈现稳定后,会分为两个区,此时的数据通信是不同步的,可能一个会新一点,一个会老一点。为了保证系统的可用性,此时当服务被调用的时候也能够调的通,然而数据并不是最新的,也就是失去了C 一致性的属性。Eureka就是一个AP架构的例子,当Eureka客户端心跳隐没的时候,那Eureka服务端就会启动自我爱护机制,不会剔除该EurekaClient客户端的服务,仍然能够提供需要; CP:当网络分区呈现后,为了保障一致性,就必须拒绝请求,否则无奈保障一致性。 CP构造抉择的是一致性和分区容错性,如果抉择一致性C(Consistency),为了保障数据库的一致性,咱们必须期待失去分割的服务恢复过来,在这个过程中,那个服务是不容许对外提供的,这时候零碎处于不可用状态(失去了A属性)。

September 8, 2023 · 1 min · jiezi

关于java:什么是网络分区

网络分区是指在一个分布式系统中,网络连接断开或某些节点之间无奈互相通信,导致系统外部的通信碰壁。在网络分区状况下,零碎中的不同局部或节点之间可能无奈相互拜访或替换数据,这可能会对系统的可用性和一致性产生影响。 网络分区能够产生在分布式系统中的不同节点之间,也能够产生在不同的数据中心、云服务提供商之间,或者是因为网络故障、硬件故障等起因引起的。无论是因为哪种起因,网络分区都可能会对分布式系统的失常运行产生重要影响。 网络分区可能导致以下问题: 数据不一致性:当不同节点无奈通信时,更新在一个分区上的数据可能无奈及时同步到其余分区,导致数据不统一。服务不可用:如果一个节点或一个服务的依赖节点被隔离在一个分区中,那么这个节点或服务可能会变得不可用,从而影响整个零碎的可用性。性能降落:在网络分区状况下,零碎可能须要期待分区解除,或者采纳其余机制来解决分区问题,这可能会导致性能降落。简单的决策:网络分区会导致分布式系统面临简单的决策,如何解决分区问题、何时进行故障切换、何时进行数据同步等都须要审慎思考。为了应答网络分区问题,分布式系统通常须要采纳一些策略和技术,如故障切换、分布式一致性协定、数据复制、负载平衡等。这些策略和技术有助于加重网络分区可能带来的影响,保障系统的可用性和一致性。

September 8, 2023 · 1 min · jiezi

关于java:释放开发人员生产力文档级代码了解一下

网上一个经久不衰的段子:程序员最厌恶的四件事:1、 写正文2、 写文档3、 他人不写正文4、 他人不写文档明天咱们就从让开发人员“看不惯又干不掉”的文档。 一、文档的重要性 高质量文档是记录和传播信息的无效工具,能够帮忙人们了解和恪守标准、政策和程序。它们还能够作为参考和证据,以反对决策和解决问题。通过书面记录,人们能够更长时间地保留和共享常识。此外,良好的文档还能够进步工作效率,缩小误会和谬误。总之,文档在集体生存和工作中扮演着重要角色,并且对组织的可继续倒退至关重要。 对于一个组织或团队来说,高质量的文档有许多好处。首先,文档能够使代码和API更容易被了解,缩小谬误产生的概率。其次,文档能够让团队成员更加专一于指标,迅速解决问题。此外,文档也使得一些手工操作更加轻松。另外,如果新成员退出,文档能够让他们更快地融入团队。 撰写文档具备重大的收益滞后性,与测试不同,运行一个测试用例能够立刻告知正确与否,其价值立刻体现。通过编写一份文档,随着工夫的推移,它的重要性会逐步显现出来。你可能只需写一次,但它将会被读取屡次,频次可达数百次,甚至上千次。 一份杰出的文档可能在将来代替你答复以下问题:•过后为什么做出这样的决策?•为何代码被这样实现?•到底有哪些概念被纳入这个我的项目中?•……撰写文档对于作者自身也有着微小的好处:•帮助您标准API设计:撰写文档是扫视API的过程,通过编写文档能够使您思考API设计是否正当,是否全面。如果您无奈用语言精确形容API,那么阐明以后的API设计是不合理的。•文档也是代码的另一种出现形式:例如,如果你在两年后再次看到你已经写过的代码,只有有正文和文档,你就能迅速了解代码。•晋升代码的专业性:咱们都会有这样的感觉,只有有残缺文档的API都是设计良好的API。只管这个感觉并不完全正确,但两者的确密不可分,在很多人眼中,文档的欠缺水平也成为掂量一个产品专业性的指标。•避免无谓的反复问题打搅:一些问题能够间接记录在文档中,这样当有人来问你时,你能够让他们间接查看文档,而不用再反复解释一遍。。 二、为什么大多数人都不喜爱写文档 为什么很多人还没有养成写文档的习惯呢?毕竟问题通过长时间后,文档就变得十分重要了。除了之前提到的文档收益滞后的起因外,还有以下几个因素: •许多工程师习惯将编写代码和写作宰割开来,不仅仅是在工作中,而且在思维上认为它们是齐全无关的两项工作,因而导致许多人更重视代码而漠视文档的重要性。 •许多工程师也认为本人不善于写作,于是索性抉择不写。然而,这只是一种偷懒的借口。其实,编写文档并不需要富丽的辞藻或者活泼的语言,你只须要把问题讲清楚就好了。 •某些时候,工具不好用也会对文档撰写产生影响。如果没有一个优质的写作工具将文档写作融入开发工作流程中,写作的累赘的确会减少。 •绝大多数人认为写文档是工作的另外一项累赘。我曾经没工夫写代码了,更何况写文档!这其实是一个谬误的观点。尽管编写文档可能须要一些后期投入,但它能大大降低代码保护的前期老本。置信大家都能了解磨刀不误砍柴工这个情理。 三、AI工具来帮忙 如果说当初有一个AI编程工具,能够生成“文档级”的代码,是不是能够解决绝大多数不会写、不想写正文、文档的开发人员的大问题? FuncGPT(慧函数) AI生成器作为飞算SoFlu软件机器人的一个重要组成部分,反对所有类型函数创立。慧函数(FuncGPT )AI生成器通过自然语言形容Java函数需要,实时生成高质量、高可读性的Java函数代码。生成代码可间接复制到IDEA,或一键导入Java全自动开发工具函数库。 FuncGPT(慧函数)能够很好的解决以下代码问题:1、代码标准:生成合乎Java语法和代码标准的函数代码,生成的代码将更易于浏览和了解。2、代码复用:生成的函数代码会偏向于应用可复用的最佳实际。能够缩小冗余代码,进步代码的可维护性。3、代码正文:生成的代码会蕴含清晰的代码正文,帮忙开发工程师了解函数的用处和输入输出。良好的正文对于前期保护十分重要。4、代码构造:生成的代码会偏向于应用良好的代码构造,防止过长的函数和适度嵌套。这有助于进步代码的可读性和可维护性。5、大量缩小代码调试工作:生成的代码通过大规模联结训练,它可能生成较为精确和稳固的代码,从而缩小了因为代码谬误引起的调试工作。 以工作管理系统中应用Java函数实现计算工作剩余时间的性能为例。函数性能:计算两个日期相差天数(返回字符串)参数1:参数名称:startTime;参数类型:Date;参数形容:开始工夫参数2:参数名称:endTime;参数类型:Date;参数形容:完结工夫参数3:参数名称:format;参数类型:String;参数形容:格式化字符,例:天,时,分 // 类名:DateUtils// 函数名:calculateDateDifference// 函数性能:计算两个日期相差天数// POM依赖包:// <dependency>// <groupId>joda-time</groupId>// <artifactId>joda-time</artifactId>// <version>2.10.10</version>// </dependency>import org.joda.time.DateTime;import org.joda.time.Days;public class DateUtils { /** * 计算两个日期相差天数 * @param startTime 开始工夫 * @param endTime 完结工夫 * @return 相差天数字符串 */ public static String calculateDateDifference(DateTime startTime, DateTime endTime, String format) { Days days = Days.daysBetween(startTime, endTime); // 应用Joda-Time计算相差天数 int difference = days.getDays(); String result; switch (format) { case "天": result = difference + "天"; break; case "时": result = difference * 24 + "小时"; break; case "分": result = difference * 24 * 60 + "分钟"; break; default: throw new IllegalArgumentException("Invalid format"); // 如果格局不非法,抛出异样 } return result; }}// 函数示例// 计算两个日期相差天数示例// 入参:startTime,开始工夫,类型为DateTime;endTime,完结工夫,类型为DateTime;format,格式化字符,类型为String// 出参:result,相差天数字符串// 调用示例:// DateTime startTime = new DateTime(2022, 1, 1, 0, 0); // 创立开始工夫对象// DateTime endTime = new DateTime(2022, 1, 5, 0, 0); // 创立完结工夫对象// String result = DateUtils.calculateDateDifference(startTime, endTime, "天");// System.out.println(result);// 输入后果:例如,计算2022年1月1日和2022年1月5日相差天数为:4// 则输入后果为:4天通过剖析不难发现:1、注解:代码上方有一段XML注解,表明该类须要joda-time库版本2.10.10。这对于了解代码的依赖关系和运行环境十分重要。2、可读性:函数名的命名是清晰和描述性的,它表明了这个函数的次要性能。参数名也是明确的,能够很容易地了解每个参数的作用。每个代码块(如导入语句和函数体)都应用适合的缩进和空格,使得代码易于浏览。3、代码品质: 应用Days.daysBetween办法计算两个日期之间的天数差别,这是一个很好的做法,因为它防止了间接进行时间差计算可能产生的问题(例如夏令时、时区等)。 应用了switch-case构造对不同的格局申请进行了解决,这样能够灵便地满足不同的需要。对于有效的格局输出,办法抛出了一个IllegalArgumentException,这表明了对于异常情况的解决。 应用了正当的变量名和办法名,使得代码易于了解和保护。 应用了正当的正文,解释了代码的性能和参数的作用。 代码中没有应用任何魔法数或硬编码的值,而是应用了适当的常量或变量。 输出参数类型为DateTime,这使得函数具备很好的通用性,能够承受各种工夫格局。 返回类型为String,这使得函数的输入具备良好的可读性和可展现性。**如果你也想体验FuncGPT(慧函数)带来的高效高质量的开发体验,收费下载应用吧:**https://c.suo.nz/8zCUC ...

September 8, 2023 · 1 min · jiezi

关于java:适配器模式如何让不兼容的接口变得兼容

在软件开发中,咱们常常会遇到这样的状况:咱们须要应用一个现有的类或者接口,但它与咱们零碎的指标接口不兼容,而咱们又不能批改它。这时候,咱们该怎么办呢?大多数状况下咱们都能够应用适配器模式来解决这个问题,本文将从以下四个方面解说适配器模式。 简介优缺点利用场景Java 代码示例简介适配器模式(Adapter Pattern)是一种结构型设计模式,它能够将一个接口转换成客户端所期待的另一个接口,从而使本来因为接口不兼容而不能一起工作的类能够一起工作。适配器模式也称为包装器模式(Wrapper Pattern),因为它通过一个包装类(即适配器)来包装不兼容的接口,并提供对立的指标接口。适配器模式能够在运行时依据须要抉择不同的适配器来适配不同的被适配者。 对象适配器模式的各角色定义如下。 Target(指标接口):客户端要应用的指标接口标准,对应下文中的三相插孔接口 TriplePin。Adapter(适配器):实现了指标接口,负责适配(转换)被适配者的接口 specificRequest()为指标接口 request(),对应本章下文中的电视机专属适配器类 TriplePinAdapter。Adaptee(被适配者):被适配者的接口标准,目前不能兼容指标接口的问题接口,能够有多种实现类,对应下文中的两相插孔接口 DualPin。Client(客户端):指标接口的使用者。举荐博主开源的 H5 商城我的项目waynboot-mall,这是一套全副开源的微商城我的项目,蕴含三个我的项目:经营后盾、H5 商城前台和服务端接口。实现了商城所需的首页展现、商品分类、商品详情、商品 sku、分词搜寻、购物车、结算下单、支付宝/微信领取、收单评论以及欠缺的后盾治理等一系列性能。 技术上基于最新得 Springboot3.0、jdk17,整合了 MySql、Redis、RabbitMQ、ElasticSearch 等罕用中间件。分模块设计、简洁易保护,欢送大家点个 star、关注博主。 github 地址:https://github.com/wayn111/waynboot-mall 优缺点适配器模式的长处有: 适配器模式能够加强程序的可扩展性,通过应用适配器,能够在不批改原有代码的根底上引入新的性能或者接口。适配器模式能够进步类的复用性,通过应用适配器,能够将已有的类或者接口重新组合和封装,使其合乎新的需要。适配器模式能够减少类的透明度,通过应用适配器,客户端只须要关注指标接口,而无需理解被适配者的具体实现。适配器模式能够灵便地切换不同的被适配者,通过应用不同的适配器,能够动静地抉择不同的被适配者来满足不同的场景。适配器模式的毛病有: 适配器模式会减少零碎的复杂性,过多地应用适配器会使零碎变得零乱和难以了解。适配器模式可能会升高零碎的性能,因为每次调用指标接口时都须要通过适配器的转换。适配器模式可能会违反开闭准则,如果指标接口发生变化,则须要批改所有的适配器类。利用场景适配器模式实用于以下场景: 当须要在一个已有零碎中引入新的性能或者接口时,它与零碎的指标接口不兼容,但又不能批改原有代码时,能够应用适配器模式。例如在一个数据库操作系统中,如果想要反对多种类型的数据库源,但零碎只提供了一个固定类型数据库源的操作接口时,能够应用一个数据库源操作适配器来将不同类型数据库源转换成对立类型数据库源。当须要在多个独立开发的零碎或者组件之间进行合作时,但因为各自采纳了不同的接口或者协定时,能够应用适配器模式。例如在一个分布式服务零碎中,如果想要让不同语言编写的服务之间进行通信和调用,但各自采纳了不同的通信协议和数据格式时,能够应用一个服务通信适配器来将不同协定和数据格式转换成对立协定和数据格式。Java 代码示例举一个生存中常见的实例,咱们新买了一台电视机,其电源插头是两相的,不巧的是墙上的插孔却是三相的,这时电视机便无奈通电应用,咱们以代码来重现这个场景。 定义指标接口:三相插口 TriplePin,其中 3 个参数 l、n、e 别离对应前线(live)、零线(null)和地线(earth)。public interface TriplePin { public void electrify(int l, int n, int e);}定义被适配者接口:两项插口 DualPin,能够看到参数中短少了地线 e 参数。public interface DualPin { public void electrify(int l, int n);}增加被适配者接口具体实现类:TV,能够看到 TV 实现的是两相接口,所在无奈间接在三项接口中应用。public class TV implements DualPin { @Override public void electrify(int l, int n) { System.out.println("前线通电:" + l + ",零线通电:" + n); System.out.println("电视开机"); }}定义适配器类:三项接口适配器 TriplePinAdapter,实现了三项接口并且蕴含两项接口属性,在 electrify 办法中调用被适配设施的两插通电办法,疏忽地线参数 e,以此来实现三项接口对两项接口的兼容。这也就意味着 TriplePinAdapter 类能帮忙咱们将 TV 类与三项接口兼容。 ...

September 8, 2023 · 1 min · jiezi

关于java:为什么-listsort-比-streamsorted-要更快测试结果把我惊呆了

作者:是奉壹呀 \起源:juejin.cn/post/7262274383287500860 看到一个评论,外面提到了list.sort()和list.strem().sorted()排序的差别。 说到list sort()排序比stream().sorted()排序性能更好,但没说到为什么。 有敌人也提到了这一点。本文从新开始,先问是不是,再问为什么。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice真的更好吗?先简略写个demo List<Integer> userList = new ArrayList<>(); Random rand = new Random(); for (int i = 0; i < 10000 ; i++) { userList.add(rand.nextInt(1000)); } List<Integer> userList2 = new ArrayList<>(); userList2.addAll(userList); Long startTime1 = System.currentTimeMillis(); userList2.stream().sorted(Comparator.comparing(Integer::intValue)).collect(Collectors.toList()); System.out.println("stream.sort耗时:"+(System.currentTimeMillis() - startTime1)+"ms"); Long startTime = System.currentTimeMillis(); userList.sort(Comparator.comparing(Integer::intValue)); System.out.println("List.sort()耗时:"+(System.currentTimeMillis()-startTime)+"ms");输入 stream.sort耗时:62msList.sort()耗时:7ms由此可见list原生排序性能更好。 能证实吗? 证据错了。 再把demo变换一下,先输入stream.sort List<Integer> userList = new ArrayList<>(); Random rand = new Random(); for (int i = 0; i < 10000 ; i++) { userList.add(rand.nextInt(1000)); } List<Integer> userList2 = new ArrayList<>(); userList2.addAll(userList); Long startTime = System.currentTimeMillis(); userList.sort(Comparator.comparing(Integer::intValue)); System.out.println("List.sort()耗时:"+(System.currentTimeMillis()-startTime)+"ms"); Long startTime1 = System.currentTimeMillis(); userList2.stream().sorted(Comparator.comparing(Integer::intValue)).collect(Collectors.toList()); System.out.println("stream.sort耗时:"+(System.currentTimeMillis() - startTime1)+"ms");此时输入变成了 ...

September 8, 2023 · 2 min · jiezi

关于java:Spring02-Bean的注入

1. 默认无参结构User:其中User为默认无参结构 public class User { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; }}beans.xml:(这样不会出错) <bean id="user" class="com.pojo.User"> <property name="name" value="Bob" /> </bean> 若是User没有了无参结构,只有有参结构,beans.xml 那样机会出错: public class User { private String name; public User(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; }}beans.xml:(默认无参结构,这样会出错) <bean id="user" class="com.pojo.User"> <property name="name" value="Bob" /> </bean>2. 无参结构怎么实现的值的注入?答:通过 setter如没有setter, 也会出错。(能够将 setter正文掉,就会出错)、 ...

September 8, 2023 · 3 min · jiezi

关于java:日流量200亿聊聊-携程网关的架构设计

大家好,我是不才陈某~ 本文目录- 说在后面 - 日流量200亿,携程网关的架构设计 - 一、概述 - 二、高性能网关外围设计 - 2.1. 异步流程设计 - 2.2. 流式转发&单线程 - 2.3 其余优化 - 三、网关业务状态 - 四、网关治理 - 4.1 多协定兼容 - 4.2 路由模块 - 4.3 模块编排 - 五、总结 - 说在最初:有问题能够找老架构取经 - 局部历史案例 日流量200亿,携程网关的架构设计计划的作者:Butters,携程软件技术专家,专一于网络架构、API网关、负载平衡、Service Mesh等畛域。 一、概述相似于许多企业的做法,携程 API 网关是随同着微服务架构一起引入的基础设施,其最后版本于 2014 年公布。随着服务化在公司内的迅速推动,网关逐渐成为应用程序裸露在外网的规范解决方案。后续的“ALL IN 无线”、国际化、异地多活等我的项目,网关都随着公司公共业务与基础架构的独特演进而一直倒退。截至 2021 年 7 月,整体接入服务数量超过 3000 个,日均解决流量达到 200 亿。 在技术计划方面,公司微服务的晚期倒退深受 NetflixOSS 的影响,网关局部最早也是参考了 Zuul 1.0 进行的二次开发,其外围能够总结为以下四点: server端:Tomcat NIO + AsyncServlet业务流程:独立线程池,分阶段的责任链模式client端:Apache HttpClient,同步调用外围组件:Archaius(动静配置客户端),Hystrix(熔断限流),Groovy(热更新反对) 家喻户晓,同步调用会阻塞线程,零碎的吞吐能力受 IO 影响较大。 作为行业的领先者,Zuul 在设计时曾经思考到了这个问题:通过引入 Hystrix,实现资源隔离和限流,将故障(慢 IO)限度在肯定范畴内;联合熔断策略,能够提前开释局部线程资源;最终达到部分异样不会影响整体的指标。 ...

September 8, 2023 · 3 min · jiezi

关于java:Java后端学习路线经验分享全网最靠谱

简介本文是Java自学的教训分享,5个月即可入职Java后端开发岗位。 我之前是自学的Java,Java零根底,用了5个月的工夫,拿到了6家offer。 有的货色不能复制,但学习Java的办法是能够复制的。在本站学习,你将能复制站长的历程,你也能够Java零根底拿到月薪10K左右的offer。 目前我是CSDN博客专家、多个开源我的项目的作者、继续输入Java入门到Java高级的教程。 Java学什么?在Boss直聘上间接搜寻:Java开发,即可找到Java岗位的须要把握的技术。须要学习的技术如下: Java根底、JVM、多线程、MySQL、Redis、设计模式、框架(Spring、SpringMVC、SpringBoot、MyBatis)、中间件(MQ、Shiro)分布式(SpringCloud、Dubbo)、ElasticSearch。 Java怎么学(学习路线)?学习路线是: 学Java后端基础知识学Java入门我的项目实战背Java面试题投简历开始找工作 1.学Java后端基础知识(3-4个月)自学Java后端基础知识有两种办法:1.看书 2.看视频。站长举荐看书,看书比看视频快很多,只有选对了书,是很好入门的。选书的规范是:1.内容是高级的,适宜初学者。2.实践联合实战。(举荐看PDF版本,因为易于保留和携带、可搜寻。) 站长刚学Java时在网上搜了很多书,每一样技术都找了七八本书进行了比对,而后从当选1本最好的。书籍如下: 技术 书籍 必看的章节 学习工夫 学习办法Java根底 《JAVA开发实战经典 第2版》 第1-15章,第24章 1~2个月 边学边敲代码。JVM 《深刻了解Java虚拟机 JVM高级个性与最佳实际 第2版》 第2-4章 1周 简略理解,无需深刻。后边的面试题会帮你深刻。多线程 《Java并发编程之美》 第1-2章 1周 简略理解,略微敲一点代码。后边的面试题会帮你深刻。MySQL 《MySQL必知必会》 下边这些不必看,其余都要看。不必看的章节:第2章的2.2.2,2.2.3;第9-10章,第22-30章 3周 一边学一边用Navicat写语句。Redis 《Redis开发与运维》 第1-2章深刻学习;第3,5,6,9,10,11章简略理解。 2周 一边学一边用命令行写语句。设计模式 我找过十来本书,全都不靠谱,浪费时间。间接看站长的教程即可:设计模式 理解一些罕用的设计模式是什么即可。 1周 理解即可,不须要会利用。利用设计模式是Java中高级SpringBoot 《深入浅出Spring Boot 2.x》 第3,4,6章 1周 理解概念即可,比方:IOC,AOP。里边实战不太好,难入门,先不必学实战,等看完这里的所有PDF,再看站长的视频教程最好:入门实战。MyBatis-Plus 我找过五六本书,全都不靠谱,浪费时间。看站长的教程最好:入门实战 学会增删改查。 0天 这里先不必学,等看完这里的所有PDF,再看站长的视频教程最好:入门实战。MQ 《RabbitMQ实战指南》 第1-4章 1周 理解概念即可。书里没有联合SpringBoot的实战,能够间接看站长的文章:文章地址Shiro 我找过六七本书,全都不靠谱,浪费时间。看站长的教程最好:Shiro实战 1周 大体晓得是怎么管制的即可,比方:先校验token,再校验资源权限(url权限或数据权限)。不须要理论会写代码,因为权限管制是Java中高级做的。SpringCloud 《深入浅出Spring Boot 2.x》 第17章 1周 本人搭个环境,把feign调用跑通。Dubbo 不须要学 0 Dubbo不须要学。ElasticSearch 不须要学,只需理解什么是倒排索引,见:此文 上边这些书籍,站长之前收集了PDF,增加了目录、内容可搜寻,站长间接收费分享进去: ...

September 7, 2023 · 1 min · jiezi

关于java:爬虫系统的核心如何创建高质量的HTML文件

在网页抓取或爬虫零碎中,HTML文件的创立是一项重要的工作。HTML文件是网页的根底,蕴含了网页的所有内容和构造。在爬虫零碎中,咱们须要生成一个HTML文件,以便于保留和解决网页的内容。在这种状况下,能够应用Java函数来实现将爬取到的网页内容保留为HTML文件的性能。具体来说,当爬虫零碎获取到须要保留的网页内容时,它能够通过调用以下Java函数,将网页内容作为参数传递给函数。函数会依据给定的文件名和网页内容,生成对应的HTML文件并返回文件对象。而后,爬虫零碎能够进一步解决该HTML文件,如进行数据提取、剖析等操作。 函数性能:创立HTML文件参数1:参数名称:fileName;参数类型:String;参数形容:新生成文件名称参数2:参数名称:fileContent;参数类型:String;参数形容:源文件 返回值:File 基于以上Java函数需要,通过人工编码的形式,代码示例如下: @MethodDesc(desc = "创立HTML文件", params = { @ParamDesc(name = "fileName", desc = "新生成文件名称"), @ParamDesc(name = "file", desc = "源文件")})public static File generateHtml(String fileName,String fileContent) throws IOException { String content = fileContent.replaceAll("&lt;","<").replaceAll("&gt;",">"); StringBuilder sb = new StringBuilder(); sb.append("<!DOCTYPE html>\n" + "<html lang=\"zh-cn\">\n" + "<head>\n" + " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n" + " <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no\">\n" + " <meta name=\"author\" content=\"\">\n" + " <title></title>\n" + " <meta name=\"keywords\" content=\"\">\n" + " <meta name=\"description\" content=\"\">\n" + "</head>\n").append(content).append("\n</html>"); File file = new File(fileName+".html"); try (FileOutputStream fileOutputStream = new FileOutputStream(file); PrintStream printStream = new PrintStream(fileOutputStream)) { printStream.println(sb); fileOutputStream.flush(); printStream.flush(); }catch (IOException e){ logger.error(e.getMessage()); } return file;}总体来说,以上代码是依据输出的文件名和源文件内容,创立一个蕴含指定头部和尾部信息的HTML文件,并将源文件内容写入该文件中。然而这段代码的命名正文欠佳,可读性个别。 ...

September 7, 2023 · 2 min · jiezi

关于java:MyBatis-架构与原理深入解析面试随便问

作者:七寸知架构 \链接:https://www.jianshu.com/p/ec40a82cae28 1 引言本文次要解说JDBC怎么演变到Mybatis的突变过程,重点解说了为什么要将JDBC封装成Mybaits这样一个长久层框架。再而阐述Mybatis作为一个数据长久层框架自身有待改良之处。 2 JDBC实现查问剖析咱们先看看咱们最相熟也是最根底的通过JDBC查询数据库数据,个别须要以下七个步骤: 加载JDBC驱动;建设并获取数据库连贯;创立 JDBC Statements 对象;设置SQL语句的传入参数;执行SQL语句并取得查问后果;对查问后果进行转换解决并将处理结果返回;开释相干资源(敞开Connection,敞开Statement,敞开ResultSet);举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice以下是具体的实现代码: public static List<Map<String,Object>> queryForList(){ Connection connection = null; ResultSet rs = null; PreparedStatement stmt = null; List<Map<String,Object>> resultList = new ArrayList<Map<String,Object>>(); try { // 加载JDBC驱动 Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); String url = "jdbc:oracle:thin:@localhost:1521:ORACLEDB"; String user = "trainer"; String password = "trainer"; // 获取数据库连贯 connection = DriverManager.getConnection(url,user,password); String sql = "select * from userinfo where user_id = ? "; // 创立Statement对象(每一个Statement为一次数据库执行申请) stmt = connection.prepareStatement(sql); // 设置传入参数 stmt.setString(1, "zhangsan"); // 执行SQL语句 rs = stmt.executeQuery(); // 解决查问后果(将查问后果转换成List<Map>格局) ResultSetMetaData rsmd = rs.getMetaData(); int num = rsmd.getColumnCount(); while(rs.next()){ Map map = new HashMap(); for(int i = 0;i < num;i++){ String columnName = rsmd.getColumnName(i+1); map.put(columnName,rs.getString(columnName)); } resultList.add(map); } } catch (Exception e) { e.printStackTrace(); } finally { try { // 敞开后果集 if (rs != null) { rs.close(); rs = null; } // 敞开执行 if (stmt != null) { stmt.close(); stmt = null; } if (connection != null) { connection.close(); connection = null; } } catch (SQLException e) { e.printStackTrace(); } } return resultList; }3 JDBC演变到Mybatis过程下面咱们看到了实现JDBC有七个步骤,哪些步骤是能够进一步封装的,缩小咱们开发的代码量。 ...

September 7, 2023 · 9 min · jiezi

关于java:Sermant类隔离架构解析解决JavaAgent场景类冲突的实践

一、JavaAgent场景为什么要留神类抵触问题?类抵触问题并非仅存在于JavaAgent场景中,在Java场景中始终都存在,该问题通常会导致运行时触发NoClassDefFoundError、ClassNotFoundException、NoSuchMethodError等异样。 从应用场景来看,基于JavaAgent技术所实现的工具,往往用于监控、治理等场景,并非企业外围业务程序。如果在应用时引入类抵触问题,可能会造成外围业务程序故障,得失相当,所以防止向外围业务程序引入类抵触是一个JavaAgent工具的根本要求。 还有一个重要起因是在Java利用中能够于开发态采纳依赖的升降级、对立依赖架构治理等伎俩解决该问题。但基于JavaAgent技术实现的工具作用于运行态,无奈在开发态就和须要被加强的Java利用进行对立的依赖治理,所以引入类抵触问题的可能性更大。 二、JavaAgent场景如何解决该问题?无论是在Java利用中,还是在JavaAgent场景,修复类抵触的逻辑都是统一的,就是防止引入会抵触的类。不同点在于基于JavaAgent技术实现的各式各样的工具,往往都具备业务无关性,在设计和实现之初,并不会为特定的Java利用类型而定制。对于JavaAgent程序而言,须要被字节码加强的利用即是黑盒,所以无奈像Java利用那样去梳理依赖构造,排除、降级依赖项,对立进行依赖架构治理。并且JavaAgent往往在运行时应用,所以只能通过保障依赖相对隔离的形式来防止引入抵触。 为何会产生类抵触,本文重点不在此,简略讲是因为咱们在Java中因为反复引入传递依赖、类的加载程序无法控制等问题,导致引入了雷同【类加载器和全限定类名(Fully Qualified Class Name)都雷同】但又体现不同【因为类版本不同而导致的类逻辑不统一】的类。所以为了防止抵触,咱们就须要防止在运行时引入雷同的类,如何让JavaAgent引入的类和宿主齐全不雷同,从全限定类名和类加载器下手才是基本: 基于maven shade plugin 进行类隔离该插件是Maven提供用于构建打包的插件,通过maven-shade-plugin的‘Relocating Classes’能力,来批改某些类的全限定类名。 此办法的原理便是通过扭转全限定类名来让JavaAgent引入的类和Java程序的类齐全不可能呈现雷同的状况,从根本上防止类抵触。然而咱们在应用一种框架,或者应用一种产品时,往往约定要优于配置,基于maven-shade-plugin通过配置去扭转全限定类名并不是一个简略的方法,在应用时就须要针对JavaAgent所波及依赖进行梳理,在maven-shade-plugin中进行配置,并且须要在每次依赖变更后从新筛查。对继续迭代极不敌对。 采纳上述办法也对Debug造成妨碍,在Debug过程中被重定向的类的断点将不可达,重大升高调试效率。 基于类加载机制进行类隔离基于maven-shade-plugin批改全限定类名往往用来解决单点的类抵触问题,尽管也能做到将JavaAgent所引入类齐全隔离,但并不是一个好的解决方案。 基于类抵触原理,咱们还能够通过限度两个雷同全限定类名的类的加载器来让其不同,如Tomcat那样,通过自定义类加载器毁坏Java的双亲委派准则,来隔离JavaAgent引入的类。这样既防止了沉重的配置,也防止了依赖变更而带来的影响。但也有其弊病,在JavaAgent场景中往往会利用到Java应用程序的类,所以基于类加载器的隔离机制,往往就让开发者只能通过反射等操作实现此类逻辑,这会对性能和开发效率产生不良影响。 三、Sermant如何做?Sermant是基于Java字节码加强技术的无代理服务网格,不仅是一个开箱即用的服务治理工具,也同样是一个易用的服务治理能力开发框架。 “把简略留给他人,把麻烦留给本人!” Sermant从设计之初就遵循上述重要准则,并布局了全方面的类隔离架构,利用Java的类加载机制对本身各模块做了充沛类隔离,让使用者和开发者无需思考因应用JavaAgent而导致类抵触问题,并且也针对开发者的应用场景做了优化,能够在开发中无缝应用被加强Java程序的类,防止因反射等行为带来的不利影响。Sermant是如何实现的呢,下文将对Sermant类隔离架构进行具体解析。 1) Sermant的类隔离架构解析如上文所说,Sermant不仅是个开箱即用的服务网格,也同样是一个易用的服务治理能力开发框架,服务治理能力是多样的包含但不限于流量治理、可用性治理、平安治理等,所以Sermant采纳插件化的架构来让用户能更灵便的接入和开发服务治理能力。 在Sermant的整体架构下,咱们不仅须要保障不向宿主服务引入类抵触问题,防止在开箱即用时对宿主服务造成负面影响,同时也须要保障框架与插件、插件与插件之间不会引入类抵触问题,防止插件开发者因为和其余服务治理插件产生类抵触问题而苦恼,所以Sermant设计了如下类隔离构造: SermantClassLoader,毁坏双亲委派,用于加载Sermant框架外围逻辑,并在AppClassLoader下隔离出Sermant的类加载模型。防止受到宿主服务本身简单类加载构造的影响,缩小应答不同类加载构造服务的适配需要。FrameworkClassLoader,毁坏双亲委派,次要作用是隔离Sermant外围能力所引入的三方依赖,防止向宿主服务及服务治理插件引入类抵触问题。目前的次要场景 ①用于隔离Sermant的日志零碎,防止对宿主服务的日志零碎产生影响 ②隔离Sermant框架的外围服务(心跳、动静配置、对立音讯网关)所需三方依赖。PluginClassLoader,遵循双亲委派,次要用于隔离Sermant各服务治理插件,防止不同服务治理插件之间产生类抵触问题。ServiceClassLoader,毁坏双亲委派,次要用于隔离插件中的依赖,通过该类加载器加载插件服务的相干lib(插件服务会在插件加载时被Sermant初始化),开发者可任意引入三方依赖,无需关怀对插件主逻辑的影响。其中的PluginClassloader和ServiceClassloader不仅在类隔离中起到至关重要的作用,更是一种久远的思考,为每个插件设计独立的类加载器,使得Sermant能够平滑的进行插件动静装置&卸载以及插件热更新。 2) 插件隔离的非凡之处 在上文中所述类隔离架构中,能够看到一处特地的逻辑(红框处),这也是Sermant中PluginClassLoader(插件类加载器)的非凡之处,在理论应用过程中,每个插件类加载器会在其中为每个线程保护一个部分的类加载器(localLoader)。 PluginClassLoader遵循双亲委派,在类加载过程中先委派SermantClassLoader加载Sermant的外围类,再通过本身加载插件类,当须要应用宿主服务的类时,则会委托部分类加载器(其Parent能够是任何类加载器,不局限于图中所批示)进行加载。用于让字节码加强的切面逻辑(Sermant拦截器)能够获取到宿主服务所应用的类,这有利于服务治理场景,其逻辑如下图所示: 通过重写类加载器loadClass逻辑,在执行Sermant拦截器时,配置一个部分的类加载环境,让Sermant拦截器中的逻辑能够顺利的应用宿主服务加载的类,这样开发服务治理插件时无需通过反射获取宿主服务的类,从而晋升服务治理能力的开发效率和最终运行时的性能,同时还防止了宿主服务和服务治理插件的类抵触。 (代码实现能够在开源仓库进行查看:) 3) 实战成果如何因接入JavaAgent而导致的依赖抵触、类抵触问题乃是业界通病,但如果有Sermant的类加载机制加持,该问题则可从本源防止,不再让宽广JavaAgent的使用者和开发者深受其害! 《托付,别在 agent 中依赖 fastjson 了》所述案例,是一个因JavaAgent而产生的依赖抵触问题的典型场景,其利用通过AppClassLoader加载到了Agent中fastjson的类FastJsonHttpMessageConverter, 该类依赖spring-web.jar的类GenericHttpMessageConverter,但因为AppClassLoader的搜寻门路中并没有spring-web.jar(fastjson通过provide形式引入),最终加载类失败。 但如基于Sermant开发则不会产生该问题,基于Sermant开发JavaAgent和Spring利用一起运行时的类隔离架构如下: 在此类加载器的构造下,有两个要害的不同: 因为Sermant扭转了类加载的构造,通过Agent引入的fastjson已不在AppClassLoader的搜寻门路中,因而Agent中的FastJsonHttpMessageConverter类不再会被Spring利用通过AppClassLoader加载到,从本源上防止了文中所触发的类抵触问题。当运行时若Agent须要应用spring-web的类GenericHttpMessageConverter时,则可通过Sermant提供的部分类加载环境胜利通过LaunchedUrlClassloader胜利从Spring利用中获取。正是因为此两点差别,让基于Sermant开发的能力能够在和利用之间进行类隔离,防止通过JavaAgent引入类抵触问题,同时能够在运行时应用利用所引入的类。 四、总结Sermant是基于Java字节码加强技术的无代理服务网格,其利用Java字节码加强技术为宿主应用程序提供服务治理性能。因深知JavaAgent场景中类抵触问题会造成的影响,Sermant在设计之初便为此布局了全面的类隔离架构。经验屡次迭代,现在Sermant的类隔离架构已能够轻松的应答各种简单的类加载环境。 除了保障类隔离,Sermant作为服务网格须要重点关注本身的服务治理能力对宿主服务带来的性能影响,所以也通过独有设计防止因为适度隔离带来的性能损耗。同时Sermant还在构建凋谢的服务治理插件开发生态,并提供高效的服务治理能力开发框架。在类隔离设计时也思考到了易用性、开发效率晋升等方面的问题。并未因为类隔离机制的存在,而升高开发的效率,增大学习曲线的平缓水平。 Sermant 作为专一于服务治理畛域的字节码加强框架,致力于提供高性能、可扩大、易接入、功能丰富的服务治理体验,并会在每个版本中做好性能、性能、体验的看护,宽泛欢送大家的退出。 Sermant 官网: https://sermant.ioGitHub 仓库地址: https://github.com/huaweicloud/Sermant扫码退出 Sermant 社区交换群

September 7, 2023 · 1 min · jiezi

关于java:96学习总结

软件架构1、单体架构:将所有的代码集中在一个我的项目中开发,打成一个包部署长处:架构简略,部署成本低毛病:耦合度高保护艰难2分布式架构:把一个残缺的零碎,依据业务性能对系统做拆分,每个业务功能模块作为独立我的项目开发,称为一个服务。一个残缺的业务性能,可能须要多个服务进行通信能力实现。服务之间通信是须要网络的。长处:有利于服务器降级和拓展,升高服务耦合毛病:服务调用关系盘根错节问题:服务拆分的粒度?服务之间如何调用?服务如何治理?服务衰弱状态?3、微服务架构(SpringCloud)是一种良好架构的思维 微服务拆分服务准则不同微服务不要开发反复性能微服务数据独立,不要拜访其余服务的数据库微服务能够将本人的接口裸露民工其余微服务调用 配置RestTemplate,配置完能够应用依赖注入来调用 RestTemplate罕用API

September 6, 2023 · 1 min · jiezi

关于java:并发编程三要素是什么在-Java-程序中怎么保证多线程的运行安全

并发编程三要素(线程的安全性问题体现在):原子性:原子,即一个不可再被宰割的颗粒。原子性指的是一个或多个操作要么全副执行胜利要么全副执行失败。可见性:一个线程对共享变量的批改,另一个线程可能立即看到。(synchronized,volatile)有序性:程序执行的程序依照代码的先后顺序执行。(处理器可能会对指令进行重排序)呈现线程平安问题的起因:● 线程切换带来的原子性问题● 缓存导致的可见性问题● 编译优化带来的有序性问题解决办法:● JDK Atomic结尾的原子类、synchronized、LOCK,能够解决原子性问题● synchronized、volatile、LOCK,能够解决可见性问题● Happens-Before 规定能够解决有序性问题并行和并发有什么区别?● 并发:多个工作在同一个 CPU 核上,按细分的工夫片轮流(交替)执行,从逻辑上来看那些工作是同时执行。● 并行:单位工夫内,多个处理器或多核处理器同时解决多个工作,是真正意义上的“同时进行”。● 串行:有n个工作,由一个线程按程序执行。因为工作、办法都在一个线程执行所以不存在线程不平安状况,也就不存在临界区的问题。做一个形象的比喻:并发 = 两个队列和一台咖啡机。并行 = 两个队列和两台咖啡机。串行 = 一个队列和一台咖啡机。什么是多线程,多线程的优劣?多线程:多线程是指程序中蕴含多个执行流,即在一个程序中能够同时运行多个不同的线程来执行不同的工作。多线程的益处:能够进步 CPU 的利用率。在多线程程序中,一个线程必须期待的时候,CPU 能够运行其它的线程而不是期待,这样就大大提高了程序的效率。也就是说容许单个程序创立多个并行执行的线程来实现各自的工作。多线程的劣势:● 线程也是程序,所以线程须要占用内存,线程越多占用内存也越多;● 多线程须要协调和治理,所以须要 CPU 工夫跟踪线程;● 线程之间对共享资源的拜访会相互影响,必须解决竞用共享资源的问题。

September 6, 2023 · 1 min · jiezi

关于java:RestTemplate使用

RestTemplate的应用RestTemplate 反对所有 Restful 格调办法,你能够依据须要进行抉择,这里咱们只介绍一些罕用的办法。所有办法都反对URI 模板和URI参数,反对上面这种写法: 相似 spring mvc 中的 @PathVariable restTemplate提供了如下API: getForObject --- optionsForAllow 分为一组,这类办法是惯例的 Rest API(GET、POST、DELETE 等)办法调用; exchange:接管一个 RequestEntity 参数,能够本人设置 HTTP method,URL,headers 和 body,返回 ResponseEntity; execute:通过 callback 接口,能够对申请和返回做更加全面的自定义管制。 getForObject的应用restTemplate.getForObject(要拜访的URL, 用于承受后果的类型.class, 入参)入参能够应用Map的模式,也能够以可变参数的模式,定义:可变参数:String result = template.getForObject( "url/{count}/{page}", String.class, "5", "1"); //restTemplate会对参数进行URI编码 getForEntity 的应用此办法有3个重载 办法参数同getForObject。 惟一区别是: 返回值是ResponseEntity<T>类型 ResponseEntity<T> 蕴含了HTTP响应的头信息header 通过header能够获取到响应的头信息,比方status 状态码, ContentType 响应类型等等body则是响应数据通过HttpMessageConverter转换的数据. postForObject 的应用此办法有3个重载与 getForObject相比多了一个Object request参数。其余参数作用和getForObject雷同 Object request能够应用以下值作为参数:org.springframework.util.MultiValueMap通过MultiValueMap携带多个参数 在大多数状况下,您不用为每个部件指定Content-Type。内容类型是依据HttpMessageConverter所选内容类型主动确定的,不指定Content-Type以便基于文件扩展名的状况下进行主动抉择。postForEntity的应用此办法有3个重载 办法参数同postForObject 惟一区别是返回值是ResponseEntity类型 ResponseEntity 蕴含了HTTP响应的头信息header exchange的应用该办法是通用的申请形式,反对 GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE,当下面的形式不能满足你可采纳该形式定制,该形式提供了更加灵便的 API,比方你能够定制 GET 办法的申请头,放入 Jwt Token等操作,这是getForObject 无法比拟的。 ...

September 6, 2023 · 1 min · jiezi

关于java:15000字6个代码案例5个原理图让你彻底搞懂Synchronized

Synchronized本篇文章将围绕synchronized关键字,应用大量图片、案例深入浅出的形容CAS、synchronized Java层面和C++层面的实现、锁降级的原理、源码等 大略观看工夫17分钟 能够带着几个问题去查看本文,如果认真看完,问题都会迎刃而解: 1、synchronized是怎么应用的?在Java层面是如何实现? 2、CAS是什么?能带来什么益处?又有什么毛病? 3、mark word是什么?跟synchronized有啥关系? 4、synchronized的锁降级优化是什么?在C++层面如何实现? 5、JDK 8 中轻量级锁CAS失败到底会不会自旋? 6、什么是object monitor?wait/notify办法是如何实现的?应用synchronized时,线程阻塞后是如何在阻塞队列中排序的? ... synchronized Java层面实现synchronized作用在代码块或办法上,用于保障并发环境下的同步机制 任何线程遇到synchronized都要先获取到锁能力执行代码块或办法中的操作 在Java中每个对象有一个对应的monitor对象(监视器),当获取到A对象的锁时,A对象的监视器对象中有个字段会指向以后线程,示意这个线程获取到A对象的锁(具体原理后文形容) synchronized能够作用于一般对象和动态对象,当作用于动态对象、静态方法时,都是去获取其对应的Class对象的锁 synchronized作用在代码块上时,会应用monitorentry和monitorexit字节码指令来标识加锁、解锁 synchronized作用在办法上时,会在拜访标识上加上synchronized 指令中可能呈现两个monitorexit指令是因为当产生异样时,会主动执行monitorexit进行解锁 失常流程是PC 12-14,如果在此期间出现异常就会跳转到PC 17,最终在19执行monitorexit进行解锁 Object obj = new Object(); synchronized (obj) { } 在上篇文章中咱们说过原子性、可见性以及有序性 synchronized加锁解锁的字节码指令应用屏障,加锁时共享内存从主内存中从新读取,解锁前把工作内存数据写回主内存以此来保障可见性 因为获取到锁能力执行相当于串行执行,也就保障原子性和有序性,须要留神的是加锁与解锁之间的指令还是能够重排序的 CAS为了更好的阐明synchronized原理和锁降级,咱们先来聊聊CAS 在上篇文章中咱们说过,volatile不能保障复合操作的原子性,应用synchronized办法或者CAS可能保障复合操作原子性 那什么是CAS呢? CAS全称 Compare And Swap 比拟并替换,读取数据后要批改时用读取的数据和地址上的值进行比拟,如果相等那就将地址上的值替换为目标值,如果不相等,通常会从新读取数据再进行CAS操作,也就是失败重试 synchronized加锁是一种乐观策略,每次遇到时都认为会有并发问题,要先获取锁才操作 而CAS是一种乐观策略,每次先大胆的去操作,操作失败(CAS失败)再应用弥补措施(失败重试) CAS与失败重试(循环)的组合形成乐观锁或者说自旋锁(循环尝试很像在自我旋转) 并发包下的原子类,依附Unsafe大量应用CAS操作,比方AtomicInteger的自增 public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } //var1是调用办法的对象,var2是须要读取/批改的值在这个对象上的偏移量,var4是自增1 public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { //var5是通过对象和字段偏移量获取到字段最新值 var5 = this.getIntVolatile(var1, var2); //cas:var1,var2找到字段的值 与 var5比拟,相等就替换为 var5+var4 } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }CAS只能对一个变量进行操作,如果要对多个变量进行操作,那么只能对外封装一层(将多个变量封装为新对象的字段),再应用原子类中的AtomicReference ...

September 6, 2023 · 8 min · jiezi

关于java:Spring-Boot-宣布移除-run-命令真让我猝不及防

大家好,我是栈长。 昨天有粉丝反馈栈长《Spring Boot 外围技术课》中的一个问题: Spring Boot CLI 命令行工具中的 run 命令找不到了? 这是什么鬼?前面为你揭晓原由! Spring Boot CLI 根本介绍Spring Boot CLI 全称即:Spring Boot Command-Line Interface,是一个结构 Spring Boot 我的项目命令行工具,可用于从 start.spring.io 网站构建新我的项目或用来明码加密。 它能够运行 Groovy 脚本,它也是 JVM 系语言,领有和 Java 相似的语法,但它比 Java 要无比简洁,无需太多冗余的我的项目构造配置代码,从而能够疾速构建我的项目。 Spring Boot 并不一定须要 Spring Boot CLI,但有了 Spring Boot CLI ,能够在无需 IDE 的状况下疾速启动基于 Spring 的应用程序。 Spring Boot CLI 提供了很多快捷性能,其中一个亮点就是能够反对运行 Groovy 脚本,以疾速构建 Spring 我的项目。 比方,栈长在桌面创立了一个简略的 app.groovy 脚本文件: @RestControllerclass ThisWillActuallyRun { @RequestMapping("/hi") String home() { "Hello Spring Boot!" }}而后应用 Spring Boot CLI 运行命令就能间接运行了: ...

September 6, 2023 · 2 min · jiezi

关于java:不好意思listcontain-去重该换换了

最近又是一轮代码review , 发现了一些实现去重的代码,在应用 list.contain ...... 我深思,是不是其实很多初学者也存在这种去重应用问题? 所以我抉择把这个事件整进去,分享一下。 举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice①首先是造出一个 List<String> 模仿数据,一共2W条,外面有一半数据1W条是反复的: public static List<String> getTestList() { List<String> list = new ArrayList<>(); for (int i = 1; i <= 10000; i++) { list.add(String.valueOf(i)); } for (int i = 10000; i >= 1; i--) { list.add(String.valueOf(i)); } return list;}先看看咱们用 contain 去重的代码: /** * 应用 list.contain 去重 * * @param testList */private static void useContain2Distinct(List<String> testList) { System.out.println("contains 开始去重,条数:" + testList.size()); List<String> testListDistinctResult = new ArrayList<>(); for (String str : testList) { if (!testListDistinctResult.contains(str)) { testListDistinctResult.add(str); } } System.out.println("contains 去重结束,条数:" + testListDistinctResult.size());}咱们调用一下看看耗时: ...

September 6, 2023 · 2 min · jiezi

关于java:好不容易通过华为面试签约时告诉我签的是华为慧通该不该去

大家好,我是栈长。 最近看到一个话题: 前几天去华为面试,起初说通过了,然而HR通知我签约签的是华为慧通的,我该不该去? 起源:https://www.zhihu.com/question/310409624/answer/2437587008 面对这一问题,网友们纷纷表示当然不该去。有网友反诘: 其中,网友clause的高赞答复给出了明确的理由: 不要去,刚刚从华为来到,与你的状况应该是统一的,与正岗一起工作,HR通知我工作没有区别,能够取得华为编制,但理论的工作体验齐全不同,你与你的公司领导是没有接触的,与华为只是劳动服务关系,遇到了艰难没有任何人会帮忙,集体教训以供参考,具体如下: 1、对于支出:入职前有好几个单位offer,华为是把薪资压到最低的,高的能给超过1.5倍,华为对外包类(含od、odc、慧通、中软、软通…)便宜劳动力有对立的定价:一万高低,会做背调,集体薪资上调不得超过20%,及时原本就超过一万多的人,进来华为也只会给一万左右的支出(技术岗会高一点点),除非你有某些非凡的本事,领导十分赏识这位外包同学,要给他运作运作,在华为目前的状况不太可能,很多共事的搭档都被裁了。 每一次加班,要提前邮件给主管批才会给算加班费,其余加班属于被迫加班,并且每月一次的周六两倍薪资也看领导是否批准能力来(我领导在前期就不批了,说活周内干不完就是集体能力问题,打低绩效,绩效也会影响支出)。 我家里有亲戚是做的大厂正岗,我才晓得齐全不一样,正岗每年有两次被动调薪,且不说日常的支出就差距迥异,光是年终奖,在我眼里高的离谱,年终奖拿的4个月薪资(近十万),我这边年终奖只有不到0.5个月薪资(<5k)。 2、对于工作我进去的时候也是心里带着华为光环的,心愿去大公司学习,让本人更有能力,实际上…部门老大在一次大会议上间接说“这种没什么价值的事件不要用正岗劳动力,丢给外包干就能够了”。 此外外包很多权限没有凋谢(不要置信说华为子公司这个名号,说就是华为编制,都是HR骗人的)正岗能看到、外包看不到的很多,有些状况还能找领导申请权限(查看、下载),有些会议也是不会让外包参加的(年度布局类、专制生存节、研讨会等),如果想旁听,独自申请,看领导批不批准。 3、对于权限每个月一次信息安全和考勤标准的培训(华为不会提供业务类培训),这些培训全是洗脑,不能将任何货色外发,手机摄像头一旦正对电脑屏幕就会弹窗揭示违规(其实根本都是登陆账号扫码才正对屏幕),守法信息安全法抵偿案例…… 不到维权的时候我都不晓得这些有啥不妥,直到隔离那个月,华为主管不想给我批工资,想让我申请无薪假(这个我征询过华为正式的HR,意思是只有业务部门认为我在家没有产出工作,或者是示意不须要我居家期间办公,则我居家隔离期间就是没有支出的),起初我征询律师的时候都不敢截图聊天记录(聊天记录属于外部公开类,外发也有责任)律师说咱们被洗脑太重大了,让我不要申请,如果主管最终没批准我的居家办公,导致支出升高,属于守法 4、对于教育我最器重的就是到华为里能精进业务,实际上进了华为,很快你就会学习到华为外部的鄙视链,从工牌、工号上就能辨别哪些是便宜劳动力—外包,哪怕那个部门的人你不意识,你就能晓得他原来只是个干杂活的……这就是为什么有些其余部门的正岗同学体现得很翘,他们是真心的,并且他们能够一键到你老板那边投诉你,一句话的事件,集体绩效压低…… 领导也会教育你留神本人的身份:列举不完,有几个比拟典型的事件,如下: “你终日在部门里忙忙碌碌的在我看了就和猪一样,你是不是认为你在华为天天给乙方训话特地有自卑感?华为给你发钱,不是让你培训乙方怎么做出好的物料,这么喜爱和乙方磨细节,就罗唆滚回乙方,去找乙方拿工资吧!”这是刚到华为的时候,第一个我的项目延期,其实我的项目延期是华为认可的一个程序,组里延期的我的项目十分多,很多我的项目一年多也没闭环。 已经组里人太少,我的负荷太重,给负责我工作的项目经理汇报了,项目经理评估过后也给咱们部长申请人力反对,部长批准咱们再招一些共事,主管那边给部长说能够把一个odc调过来,而后项目经理让我分一部分工作来给那位odc,我梳理了一部分不那么紧急的不便新人动手,并且与项目经理核查无误,交给主管批准,主管说“给你们组一个odc不是给你干活,你凭什么分工作给他人?项目经理那边再有立项安顿这个人才会界入,你的活本人想方法干完” 因为加班太重,我常常写加班申请,而申请的邮件总是会抄送HRBP,如果总是驳回,主管思考对她集体影响,因而她找我面对面谈话“别以为加班多就致力,少做这些打动本人的事件,我通知你,你这种生存是不衰弱的,本人想方法解决问题吧。”尔后加班就没再提申请,因为入职工夫短,不心愿太早来到履历不难看,始终是要求本人适应这样的环境,华为骂人的领导太多了,大家也不感觉奇怪。 除了鄙视链,还能学到人事内卷…凌晨一点多,群里部长忽然发了一条聊天记录,而后说了下隔壁业务线能够做的一些筹备,没有艾特任何人,半小时后,隔壁组负责人进去回应。咱们就晓得咱们组也马上不远了,立马开始想咱们组要怎么去调整,一早组里散会,说上次领导发了一篇文章给隔壁组,隔壁组立马两小时弄出来一篇,咱们这边也快点,每人一篇文章,要求思维粗浅,两天内发来……在汇报前夜,熬到凌晨几点还能看到部门几位共事是常态,毕竟汇报得丑陋比事件做得丑陋重要多了…… 临时先这些吧,心愿能对你有点帮忙。其实未必大厂里工作过就被其余企业推戴,反而其余企业会感觉大公司病,既然违心便宜去做外包,那其余好一点的公司是不是能通过画饼升高用人老本呢?目前自己刚到职几天,还没有找到适合的工作,心愿支出能回到进华为前谈成的15k吧…… 对于到职的那个月,项目经理让我整顿一下工作内容,让主管给个交接人(工作是项目经理安顿,然而她没有考评权限,集体考评齐全是主管来打,因而很多事件只能给主管审批)我按要求写完当前,主管回复的邮件是不给交接人,她只给安顿了一个材料整顿完交给谁的交接人,其余工作做完能力离场(没错的,如果没做完会怎么样?离场前,外包公司会给一张离场表格要领导签字,还有离司电子流要审批,领导不批没得离场,当然做不完来补工时也不会额定发工资——我过后赶在走之前赶完了,依据教训盲猜:如果没做完可能会要求集体写承诺书,承诺前面几天来工作属于合作方配合行为,不要工资啥的,外包公司的主管之后通知你,加班也得做完离场) 对于我的事,最初一点工夫卷入了华为的大HR,他很同情,给了一些帮忙,保障我在最初一天能够顺利离司(如领导还是成心不批电子流,HR会帮推动),然而大局为重,HR不能界入部门治理,外包,只能本人想方法 另一方面,或者对于某些企业的招聘官来说,在华为工作过也带光环呢?仅供参考。 近期热文举荐: 1.1,000+ 道 Java面试题及答案整顿(2022最新版) 2.劲爆!Java 协程要来了。。。 3.Spring Boot 2.x 教程,太全了! 4.别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!! 5.《Java开发手册(嵩山版)》最新公布,速速下载! 感觉不错,别忘了顺手点赞+转发哦!

September 6, 2023 · 1 min · jiezi

关于java:如何使用Java-React计算个人所得税

前言 在报表数据处理中,Excel公式领有弱小而多样的性能,广泛应用于各个业务畛域。无论是投资收益计算、财务报表编制还是保险收益估算,Excel公式都扮演着不可或缺的角色。传统的做法是间接依赖Excel来实现简单的业务逻辑,并生成相应的Excel文件。因而只需在预设地位输出相应参数,Excel公式即可被激活,迅速计算并出现后果。正因如此,在这类场景中,企业积攒了大量用于计算的Excel文件,它们曾经成为了无价的财产。 然而,传统的Excel文件形式存在难以治理和数据不平安的毛病。为了解决这些问题,能够采纳B/S架构+Excel组件库的形式。 本文将以个人所得税的计算为例,应用React+Spring Boot+GcExcel来实现。首先筹备好Excel文件,依照国家税务总局提供的个税计算页面进行创立。 个人所得税的支出类型有8种: 工资薪金所得年终奖所得劳务报酬所得个体工商户、生产经营所得酬劳所得偶尔所得利息、股息、红利所得财产转让所得其中,工资薪金所得最为简单,包含社会保险和专项扣除。每种类型的计税形式都不同,为了便于了解,咱们为每个类型创立了一个工作表进行计算。 以下是筹备好的Excel文件,其中蓝色局部为须要输出参数的单元格,其余单元格将主动计算。 实现筹备工作后,上面开始前后端工程的搭建。 实际 前端 React 创立React工程 新建一个文件夹,如TaxCalculator,进入文件夹,在资源管理器的地址栏里输出cmd,而后回车,关上命令行窗口。应用上面的代码创立名为client-app的react app。 npx create-react-app salary-client进入刚创立的salary-client文件夹,应用IDE,比方VisualStudio Code关上文件夹。 界面局部 个人所得税波及的支出类型一共有8种,其中(“酬劳所得”,“偶尔所得”,“利息、股息、红利所得”,“财产转让所得”)四种的计算形式靠近,UI布局类似,借助React的component个性,最终须要提供5种表单界面。 如下图所示: 为了让UI看起来更好看一些,能够先引入一个UI框架,这里咱们应用了MUI。 npm install @mui/material @emotion/react @emotion/styled首先,更新Src/App.js的代码,其中增加了DarkMode的Theme, 代码如下: import './App.css';import { ThemeProvider } from '@emotion/react';import { createTheme } from '@mui/material';import { FormContainer } from './Component/FormContainer';const darkTheme = createTheme({ palette: { mode: 'dark', },});function App() { return ( <ThemeProvider theme={darkTheme}> <div className="App-header"> <h2>个人所得税计算器</h2> <FormContainer></FormContainer> </div> </ThemeProvider> );}export default App;能够看到,App.js中援用了FormContainer,下来增加 ./Component/FormContainer.js。 ...

September 6, 2023 · 9 min · jiezi

关于java:依赖注入的三种方式

一、依赖注入形式 对于Spring配置一个bean时,如果须要给该bean提供一些初始化参数,则须要通过依赖注入形式,所谓的依赖注入就是通过Spring将bean所须要的一些参数传递到bean实例对象的过程Spring的依赖注入有3种形式: ·应用属性的setter办法注入 ,这是最罕用的形式;·应用结构器注入;·应用Filed注入(用于注解形式)。1、应用属性注入 属性注入即通过setXxx()办法注入Bean的属性值或依赖对象,因为属性注入形式具备可选择性和灵活性高的长处,因而属性注入是理论利用中最常采纳的注入形式。 属性注入要求Bean提供一个默认的构造函数,并为须要注入的属性提供对应的Setter办法。 属性注入原理:Spring先调用Bean的默认构造函数实例化Bean对象,而后通过反射的形式调用Setter办法注入属性值。 Car类中定义了3个属性,并别离提供了对应的Setter办法。(注:默认构造函数是不带参的构造函数。Java语言规定如果类中没有定义任何构造函数,则JVM主动为其生成一个默认的构造函数。反之,如果类中显示定义了构造函数,则JVM不会为其生成默认的构造函数。所以假如Car类中显示定义了一个带参的构造函数,如public Car(String brand),则须要同时提供一个默认构造函数public Car(),否则应用属性注入时将抛出异样。) 在上述代码中配置了一个Bean,并为该Bean的3个属性提供了属性值。具体来说,Bean的每一个属性对应一个<property>标签,name为属性的名称,在Bean实现类中领有与其对应的Setter办法:maxSpeed对应setMaxSpeed(),brand对应setBrand()。 须要指出的是:Spring只会查看Bean中是否有对应的Setter办法,至于Bean中是否有对应的属性变量则不做要求。例如配置文件中<property name="brand"/>的属性配置项仅要求Car类中领有setBrand()办法,但Car类不肯定要领有brand成员变量。2、构造函数注入 构造函数注入是除属性注入之外的另一种罕用的注入形式,它保障一些必要的属性在Bean实例化时就失去设置,并且确保了Bean实例在实例化后就能够应用。应用形式: 第一,在类中,不必为属性设置setter办法,然而须要生成该类带参的构造方法。第二,在配置文件中配置该类的bean,并配置结构器,在配置结构器中用到了<constructor-arg>节点,该节点有四个属性: · index是索引,指定注入的属性,从0开始; · type是指该属性所对应的类型; · ref 是指援用的依赖对象; · value 当注入的不是依赖对象,而是根本数据类型时,就用value; 3、应用字段(Filed)注入(用于注解形式) 除了下面讲到的应用属性的setter办法或应用结构器办法来注入依赖对象,还有一种注入依赖对象的办法,就是应用注解。

September 5, 2023 · 1 min · jiezi

关于java:面试题java锁高并发多线程1

并发编程的三要素是什么(线程的安全性问题体现在哪)? 原子性:一个或多个操作要么全副执行胜利,要么全副执行失败。可见性:一个线程对共享变量的批改,另一个线程可能立即看到(synchronized,volatile)。有序性:程序执行的程序依照代码的先后顺序执行。(有序性不代表禁止指令重排)。 什么是JAVA内存模型?首先,JAVA内存模型是指JMM,而不是指内存构造,内存构造是在物理上的区域划分,而JMM则是抽象概念上的划分。JMM(内存模型)次要包含两块:主内存+工作内存。主内存:多个线程间通信的共享内存称之为主内存,即,数据是多个线程工共享的,在物理内存构造上通常对应“堆”中的线程共享数据。工作内存:多个线程各自对应本人的本地内存,即,数据只属于该线程本人的,在物理内存构造上通常对应“本地办法栈”中的线程公有数据。Java内存模型规定了所有的变量都存储在主内存(Main Memory)中,每条线程还有本人的工作内存(Working Memory),线程的工作内存中保留了被该线程应用到的变量的主内存正本拷贝,线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能间接读写主内存中的变量,不同的线程之间也无奈间接拜访对方工作内存中的变量,线程间变量值得传递均须要通过主内存来实现。 volatile 关键字的作用Java 提供了 volatile 关键字来保障可见性和禁止指令重排(肯定有序)。 volatile 提供 happens-before 的保障,确保一个线程的批改能对其余线程是可见的。当一个共享变量被 volatile 润饰时,它会保障批改的值会立刻被更新到主存,当有其余线程须要读取时,它会去内存中读取新值。 Volatile是怎么保障可见性的?对volatile润饰的变量,执行写操作的话,JVM会发送一条lock前缀指令给CPU,CPU在计算完之后会立刻将这个值写回主内存,同时因为有MESI缓存一致性协定,所以各个CPU都会对总线进行嗅探,本人本地缓存中的数据是否被他人批改。如果发现他人批改了某个缓存的数据,那么CPU就会将本人本地缓存的数据过期,而后这个CPU上执行的线程在读取那个变量的时候,就会从主内存从新加载最新的数据。小结:lock前缀指令 + MESI缓存一致性协定。 Volatile能保障强一致性吗?不能。可见性能够认为是最弱的“一致性”(弱统一),只保障用户见到的数据是统一的,但不保障任意时刻,存储的数据都是统一的(强统一)。它只能保障线程过去读取数据时,能获取到以后的最新数据。 什么是MESI缓存一致性协定?M(批改, Modified): 本地处理器曾经批改缓存行, 即是脏行, 它的内容与内存中的内容不一样. 并且此cache只有本地一个拷贝(专有)。E(专有, Exclusive): 缓存行内容和内存中的一样, 而且其它处理器都没有这行数据。S(共享, Shared): 缓存行内容和内存中的一样, 有可能其它处理器也存在此缓存行的拷贝。I(有效, Invalid): 缓存行生效, 不能应用。过程:Core0批改v后,发送一个信号,将Core1缓存的v标记为生效,并将批改值写回内存。Core0可能会屡次批改v,每次批改都只发送一个信号(发信号时会锁住缓存间的总线),Core1缓存的v放弃着生效标记。Core1应用v前,发现缓存中的v曾经生效了,得悉v曾经被批改了,于是从新从其余缓存或内存中加载v。 Volatile是怎么做到禁止指令重排的?对于volatile批改变量的读写操作,都会退出内存屏障。每个volatile写操作后面,加StoreStore屏障,禁止下面的一般写和他重排;每个volatile写操作前面,加StoreLoad屏障,禁止跟上面的volatile读/写重排。每个volatile读操作前面,加LoadLoad屏障,禁止上面的一般读和voaltile读重排;每个volatile读操作前面,加LoadStore屏障,禁止上面的一般写和volatile读重排。

September 5, 2023 · 1 min · jiezi

关于java:什么是Spring-MVC框架的控制器

Spring MVC框架控制器是一个用于解决Web应用程序中HTTP申请的组件,它的次要作用就是接管客户端发送的HTTP申请,依据申请解决完相干业务后响应数据。 以下是Spring MVC框架中控制器的一些重要特点和用处: 申请映射:控制器通过@RequestMapping注解将特定的HTTP申请映射到相应的解决办法。这些办法通常称为处理器办法。处理器办法:处理器办法是控制器中的函数,负责执行特定的业务逻辑。它们接管HTTP申请参数,解决申请,并生成一个响应。处理器办法能够返回视图名称、模型数据或间接响应JSON、XML等数据。参数绑定:Spring MVC框架容许将HTTP申请中的参数绑定到处理器办法的参数上。这样,您能够不便地拜访申请参数、表单数据、门路变量等。视图解析:控制器通常返回一个视图名称,Spring MVC框架应用视图解析器来将视图名称映射到理论的视图资源,这能够是JSP、Thymeleaf、FreeMarker等模板引擎。拦截器:控制器能够配置拦截器来在申请进入处理器办法之前或之后执行一些共享的逻辑,例如身份验证、日志记录、性能监控等。多重控制器:一个Spring MVC应用程序通常蕴含多个控制器,每个控制器解决不同类型的申请或应用程序的不同模块。

September 5, 2023 · 1 min · jiezi

关于java:AIGC系列1chatgpt可以用来做哪些事情

上图的意思:神器轩辕剑 那么,在当初AI流行的信息时代, 你是否晓得如何取得和利用ChatGPT这一把轩辕剑来晋升你的攻击力和生存能力呢? 故事 程序员小张: 刚毕业,加入工作1年左右,日常工作是CRUD 架构师老李: 多个大型项目教训,精通各种开发架构屠龙宝术; 在将来的世界里,程序员小张和架构师老李一起效劳于一家科技公司, 他们的职业身份虽有不同,但指标却是统一的——为人类发明更好的将来。然而,在这个疾速倒退的IT职场中,他们也面临着有数的挑战和窘境。 小张是公司里的一名优良程序员,他工作勤奋,技术娴熟,对代码有着极致的谋求。 然而,在这个突飞猛进的科技行业里,他感到压力越来越大。为了放弃本人的竞争力,他必须一直学习新的技术和工具,而这须要消耗大量的工夫和精力。 老李是公司的架构师,他在团队中扮演着首领的角色,负责设计和布局各种简单的技术零碎。 只管他的工作重要而具备挑战性,但他也经常感到力不从心。他心愿找到 一种更加高效的办法,来帮忙他和他的团队解决难题。 在这个时候,一款名为ChatGPT的智能AI工具进入了他们的视线。这款工具可能自主学习, 并依据输出的文本生成各种类型的答复,从简略的问答到简单的编程问题,都能失去称心的答案。 小张和老李对这个工具产生了浓重的趣味。他们决定尝试应用ChatGPT来进步工作效率,缩小人为谬误。 然而,在应用过程中,他们也发现了一些问题。ChatGPT尽管弱小, 但并不完满,有时会给出谬误或不精确的答案。 这让他们开始思考,如何更好地利用这个工具,使其成为职场生存的重要利器。 随着工夫的推移,小张和老李逐步发现, ChatGPT并不是要取代他们的工作,而是要成为他们工作的一种辅助工具。它能够帮忙他们更快地解决问题, 进步工作效率,缩小谬误。 同时,ChatGPT也在一直学习和提高,使得它的答复越来越精确和精密。 在ChatGPT的帮忙下,小张和老李的工作变得更加高效和精确。 他们的团队也在逐步适应和应用这个工具,使得整个团队的工作效率和品质都失去了晋升。 最终,小张和老李意识到, **拥抱智能AI工具ChatGPT是职场生存的要害。**只有一直地学习和提高,能力适应这个疾速倒退的科技行业。 而ChatGPT的呈现,为他们提供了一个全新的机会,使他们可能更好地实现本人的职业指标,为人类的将来发明更多的可能性。 为什么ChatGPT失去人类的认可? 上面我依照脉络,一起来认识一下ChatGPT . 什么是ChatGPT? ChatGPT是一种: 通用自然语言生成模型 应用大量意料数据训练,以实现生成文本,答复问题,对话生成性能。 根本能力超能力(VS 智能客服)语言生成上下文学习世界常识1. 响应人类指令 (编码)2. 泛化到没见过的工作(模拟xx写文案)3. 代码生成和代码了解(浏览编写代码)如果不好了解,我打个比方。 有一个叫做ChatGPT的刚毕业的大学生,它当家教,帮你解答一些问题。 铊可能了解你的语言,通过内置的翻译软件生成多种语言的答复; 铊可能联合你前后几句话的意思,给出贴合语境的答复; 铊能够通过google看世界,晓得世界上其它中央的人文,历史常识; 铊也十分有后劲,能够做上面这几类高级的事件。 能够写代码;对没解决过的问题有通用的解决模型,并且解决的像模像样;ChatGPT倒退历史?版本参数阐明GPT-1 20181.17亿有肯定泛化能力,能用于和监 督工作无关的NLP工作GPT-215亿除了理解能力外,GPT-2 在生成方面体现出了弱小的天才:浏览摘要、聊天、编故事,生成假新闻、钓鱼邮件、在线角色扮演等GPT-31750亿自监督模型,能够实现自然语言解决 的绝大部分工作:写代码、创作、写 剧本,模拟某个人的文字等GPT-3.5 instructChatGPT一个通过微调的新版 GPT-3, 可将无害、不实在的、有偏差 的输入最小化 InstructGPT的衍生品,它将人类的反馈纳入训练过程,更好地让模型与用户用意保持一致GPT-41000*1750亿人脑神经元的数量=2* GPT4它通过监督模型和基于人类反馈的强化学习(RLHF) 具备了如下能力: 对用户实在用意的了解 上下文连接能力 对常识和逻辑理解能力 ChatGPT处理过程?1 收集数据,微调监督模型监督学习 ...

September 5, 2023 · 1 min · jiezi

关于java:RabbitMQ-如何实现延迟队列

提早队列是指当音讯被发送当前,并不是立刻执行,而是期待特定的工夫后,消费者才会执行该音讯。提早队列的应用场景有以下几种: 未按时领取的订单,30 分钟过期之后勾销订单。给活跃度比拟低的用户距离 N 天之后推送音讯,进步活跃度。新注册会员的用户,期待几分钟之后发送欢送邮件等。 1.如何实现提早队列?提早队列有以下两种实现形式: 通过音讯过期后进入死信交换器,再由交换器转发到提早生产队列,实现提早性能;应用官网提供的提早插件实现提早性能。晚期,大部分公司都会采纳第一种形式,而随着 RabbitMQ 3.5.7(2015 年底公布)的提早插件的公布,因为其应用更简略、更不便,所以它当初才是大家一般会采纳的,实现提早队列的形式,所以本文也只讲第二种形式。 2.实现提早队列2.1 装置并启动提早队列2.1.1 下载提早插件https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases留神:须要依据你本人的 RabbitMQ 服务器端版本抉择雷同版本的提早插件,能够在 RabbitMQ 控制台查看: 2.1.2 将插件放到插件目录接下来,将上一步下载的插件放到 RabbitMQ 服务器装置目录,如果是 docker,应用一下命令复制: docker cp 宿主机文件 容器名称或ID:容器目录如下图所示:之后,进入 docker 容器,查看插件中是否蕴含提早队列: docker exec -it 容器名称或ID /bin/bashrabbitmq-plugins list如下图所示: 2.1.3 启动插件rabbitmq-plugins enable rabbitmq_delayed_message_exchange如下图所示: 2.1.4 重启RabbitMQ服务装置完 RabbitMQ 插件之后,须要重启 RabbitMQ 服务能力失效。如果应用的是 Docker,只须要重启 Docker 容器即可: docker restart 容器名称或ID如下图所示: 2.1.5 验收后果在 RabbitMQ 控制台查看,新建交换机时是否有提早音讯选项,如果有就阐明提早音讯插件曾经失常运行了,如下图所示: 2.1.6 手动创立提早交换器(可选)此步骤可选(非必须),因为某些版本下通过程序创立提早交换器可能会出错,如果出错了,手动创立提早队列即可,如下图所示: 2.2 编写提早音讯实现代码2.2.1 配置交换器和队列import org.springframework.context.annotation.Configuration;import org.springframework.amqp.core.*;import org.springframework.context.annotation.Bean;/** * 提早交换器和队列 */@Configurationpublic class DelayedExchangeConfig { public static final String EXCHANGE_NAME = "myDelayedExchange"; public static final String QUEUE_NAME = "delayed.queue"; public static final String ROUTING_KEY = "delayed.routing.key"; @Bean public CustomExchange delayedExchange() { return new CustomExchange(EXCHANGE_NAME, "x-delayed-message", // 音讯类型 true, // 是否长久化 false); // 是否主动删除 } @Bean public Queue delayedQueue() { return QueueBuilder.durable(QUEUE_NAME) .withArgument("x-delayed-type", "direct") .build(); } @Bean public Binding delayedBinding(Queue delayedQueue,CustomExchange delayedExchange) { return BindingBuilder.bind(delayedQueue()).to(delayedExchange()).with(ROUTING_KEY).noargs(); }}2.1.2 定义音讯发送办法import org.springframework.amqp.rabbit.core.RabbitTemplate;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;@Componentpublic class DelayedMessageProducer { @Autowired private RabbitTemplate rabbitTemplate; @Scheduled(fixedDelay = 5000) public void sendDelayedMessage(String message) { rabbitTemplate.convertAndSend(DelayedExchangeConfig.EXCHANGE_NAME, DelayedExchangeConfig.ROUTING_KEY, message, messagePostProcessor -> { messagePostProcessor.getMessageProperties().setDelay(10000); // 设置延迟时间,单位毫秒 return messagePostProcessor; }); }}2.1.3 发送提早音讯import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/delayed")public class DelayedMessageController { @Autowired private DelayedMessageProducer delayedMessageProducer; @GetMapping("/send") public String sendDirectMessage(@RequestParam String message) { delayedMessageProducer.sendDelayedMessage(message); return "Delayed message sent to Exchange: " + message; }}2.1.4 接管提早音讯import org.springframework.amqp.rabbit.annotation.RabbitListener;import org.springframework.stereotype.Component;@Componentpublic class DelayedMessageConsumer { @RabbitListener(queues = DelayedExchangeConfig.QUEUE_NAME) public void receiveDelayedMessage(String message) { System.out.println("Received delayed message: " + message); }}PS:获取本文提早队列的实现 Demo,请加我:GG_Stone【备注:提早队列】小结实现 RabbitMQ 提早队列目前支流的实现形式,是采纳官网提供的提早插件来实现。而提早插件须要先下载插件、而后配置并重启 RabbitMQ 服务,之后就能够通过编写代码的形式实现提早队列了。 ...

September 5, 2023 · 2 min · jiezi

关于java:Java低代码开发jvslist列表引擎功能一配置说明

在低代码开发平台中,列表页是一个用于显示数据列表的页面。它通常用于展现数据库中的多条记录,并提供搜寻、排序和筛选等性能,以不便用户对数据进行查找和浏览。 jvs-list是jvs疾速开发平台的列表页的配置引擎,它和一般的crud 具备更好的交互操作性,次要特点如下:反对动静模型创立,列表引擎反对动态创建物理库表,无需提前建库建表,大大降低操作技术门槛反对可视业务逻辑配置,反对CRUD之外的配置,按钮能够触发列表、表单、api接口、业务逻辑(详见jvs-logic介绍)等列表与表单配置解耦,配置解耦后可配置的页面更加灵便,满足更丰盛的场景多种灵便款式反对,反对多种类型的款式配置,简洁高效 列表页配置列表页是治理平台中的根底页面,外围的逻辑是实现数据的 增删改查(CRUD),列表页外围的几个因素:页面内容的数据展现、查问条件、页面按钮及按钮触发的逻辑。具备利用配置权限的用户,能够在列表页目录上,鼠标悬空,零碎会弹出列表页设计的菜单,如下图所示: 点击“设计页面”,零碎进入列表页设计器,其中包含四个板块的设计内容: 页面根底信息的设计如下图所示,展现“页面设置”的性能界面, 其中包含列表页名称,这里的名称就是目录上展现的页面名称,页面形容会在界面上展现为列表页的备注阐明 页面布局有三种模式,一般布局(如上图所示),树表布局(如下图所示),卡片布局(如下图所示) 预览地址是能够间接在浏览器上通过url拜访到这个列表页的页面展示。 列表页设计进入列表页设计界面,本页面次要提供列表页界面展现的数据配置,如下图所示: ①:模型设置,这里是列表页关联的数据模型设置入口②:列表页的数据设置tab界面③:字段排序的设置tab界面④:列表页上的按钮设置的tab页面⑤:列表页上展示数据时,默认过滤设置tab页面⑥:列表页上展现数据的具体配置⑦:减少一列数据字段的操作按钮⑧:预览配置列表页的成果预览按钮点击排序条件tab页,展现如下图所示 ①:字段下拉抉择框,抉择须要排序非凡设置的字段②:零碎会主动展现对应字段抉择框中的 字段类型③:排序下拉抉择框,抉择升序与降序设置④:删除本条排序设置按钮⑤:新增一个字段的排序设置 页面权限设置 数据设置 在线Demo:https://frame.bctools.cn开源地址:https://gitee.com/software-minister/jvs 列表页相干往期干货低代码工具:jvs-list(列表引擎)2.1.7性能清单及新增性能介绍

September 5, 2023 · 1 min · jiezi

关于java:面试官Tomcat-为什么要破坏-Java-双亲委派机制被问傻眼了

起源:www.jianshu.com/p /abf6fd4531e7 我想,在钻研tomcat 类加载之前,咱们温习一下或者说坚固一下java 默认的类加载器。楼主以前对类加载也是懵懵懂懂,借此机会,也好好温习一下。 楼主打开了神书《深刻了解Java虚拟机》第二版,p227, 对于类加载器的局部。请看: 1. 什么是类加载机制?代码编译的后果从本地机器码转变成字节码,是存储格局的一小步,却是编程语言倒退的一大步。 Java虚拟机把形容类的数据从Class文件加载进内存,并对数据进行校验,转换解析和初始化,最终造成能够呗虚拟机间接应用的Java类型,这就是虚拟机的类加载机制。 虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取形容此类的二进制字节流”这个动作放到Java虚拟机内部去实现,以便让应用程序本人决定如何去获取所须要的类。实现这动作的代码模块成为“类加载器”。 类与类加载器的关系类加载器尽管只用于实现类的加载动作,但它在Java程序中起到的作用却远远不限于类加载阶段。对于任意一个类,都须要由加载他的类加载器和这个类自身一起确立其在Java虚拟机中的唯一性,每一个类加载器,都领有一个独立的类命名空间。 这句话能够表白的更艰深一些:比拟两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即便这两个类来自同一个Class文件,被同一个虚拟机加载,只有加载他们的类加载器不同,那这个两个类就必然不相等。 2. 什么是双亲委任模型1.从Java虚拟机的角度来说,只存在两种不同类加载器:一种是启动类加载器(Bootstrap ClassLoader),这个类加载器应用C++语言实现(只限HotSpot),是虚拟机本身的一部分;另一种就是所有其余的类加载器,这些类加载器都由Java语言实现,独立于虚拟机内部,并且全都继承自抽象类java.lang.ClassLoader. 2.从Java开发人员的角度来看,类加载还能够划分的更粗疏一些,绝大部分Java程序员都会应用以下3种零碎提供的类加载器: 启动类加载器(Bootstrap ClassLoader): 这个类加载器简单将寄存在 JAVA_HOME/lib 目录中的,或者被-Xbootclasspath 参数所指定的门路种的,并且是虚拟机辨认的(仅依照文件名辨认,如rt.jar,名字不合乎的类库即便放在lib目录下也不会重载)。扩大类加载器(Extension ClassLoader): 这个类加载器由sun.misc.Launcher$ExtClassLoader实现,它负责夹杂JAVA_HOME/lib/ext 目录下的,或者被java.ext.dirs 零碎变量所指定的门路种的所有类库。开发者能够间接应用扩大类加载器。应用程序类加载器(Application ClassLoader): 这个类加载器由sun.misc.Launcher$AppClassLoader实现。因为这个类加载器是ClassLoader 种的getSystemClassLoader办法的返回值,所以也成为零碎类加载器。它负责加载用户类门路(ClassPath)上所指定的类库。开发者能够间接应用这个类加载器,如果利用中没有定义过本人的类加载器,个别状况下这个就是程序中默认的类加载器。这些类加载器之间的关系个别如下图所示: 图中各个类加载器之间的关系成为 类加载器的双亲委派模型(Parents Dlegation Mode)。双亲委派模型要求除了顶层的启动类加载器之外,其余的类加载器都该当由本人的父类加载器加载,这里类加载器之间的父子关系个别不会以继承的关系来实现,而是都应用组合关系来复用父加载器的代码。 类加载器的双亲委派模型在JDK1.2 期间被引入并被广泛应用于之后的所有Java程序中,但他并不是个强制性的束缚模型,而是Java设计者举荐给开发者的一品种加载器实现形式。 双亲委派模型的工作过程是: 如果一个类加载器收到了类加载的申请,他首先不会本人去尝试加载这个类,而是把这个申请委派父类加载器去实现。每一个档次的类加载器都是如此,因而所有的加载申请最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈本人无奈实现这个申请(他的搜寻范畴中没有找到所需的类)时,子加载器才会尝试本人去加载。为什么要这么做呢?如果没有应用双亲委派模型,由各个类加载器自行加载的话,如果用户本人编写了一个称为java.lang.Object的类,并放在程序的ClassPath中,那零碎将会呈现多个不同的Object类, Java类型体系中最根底的行为就无奈保障。应用程序也将会变得一片凌乱。 双亲委任模型时如何实现的?非常简单:所有的代码都在java.lang.ClassLoader中的loadClass办法之中,代码如下: 逻辑清晰易懂:先查看是否曾经被加载过,若没有加载则调用父加载器的loadClass办法, 如父加载器为空则默认应用启动类加载器作为父加载器。如果父类加载失败,抛出ClassNotFoundException 异样后,再调用本人的findClass办法进行加载。3. 如何毁坏双亲委任模型?刚刚咱们说过,双亲委任模型不是一个强制性的束缚模型,而是一个倡议型的类加载器实现形式。在Java的世界中大部分的类加载器都遵循者模型,但也有例外,到目前为止,双亲委派模型有过3次大规模的“被毁坏”的状况。 第一次:在双亲委派模型呈现之前-----即JDK1.2公布之前。 第二次:是这个模型本身的缺点导致的。 咱们说,双亲委派模型很好的解决了各个类加载器的根底类的对立问题(越根底的类由越下层的加载器进行加载),根底类之所以称为“根底”,是因为它们总是作为被用户代码调用的API, 但没有相对,如果根底类调用会用户的代码怎么办呢? 这不是没有可能的。一个典型的例子就是JNDI服务,JNDI当初曾经是Java的规范服务,它的代码由启动类加载器去加载(在JDK1.3时就放进去的rt.jar),但它须要调用由独立厂商实现并部署在应用程序的ClassPath下的JNDI接口提供者(SPI, Service Provider Interface)的代码,但启动类加载器不可能“意识“这些代码啊。因为这些类不在rt.jar中,然而启动类加载器又须要加载。怎么办呢? 为了解决这个问题,Java设计团队只好引入了一个不太优雅的设计:线程上下文类加载器(Thread Context ClassLoader)。这个类加载器能够通过java.lang.Thread类的setContextClassLoader办法进行设置。如果创立线程时还未设置,它将会从父线程中继承一个,如果在应用程序的全局范畴内都没有设置过多的话,那这个类加载器默认即便应用程序类加载器。 嘿嘿,有了线程上下文加载器,JNDI服务应用这个线程上下文加载器去加载所须要的SPI代码,也就是父类加载器申请子类加载器去实现类加载的动作,这种行为实际上就是买通了双亲委派模型的层次结构来逆向应用类加载器,实际上曾经违反了双亲委派模型的一般性准则。但这无可奈何,Java中所有波及SPI的加载动作根本胜都采纳这种形式。例如JNDI,JDBC,JCE,JAXB,JBI等。 第三次:为了实现热插拔,热部署,模块化,意思是增加一个性能或减去一个性能不必重启,只须要把这模块连同类加载器一起换掉就实现了代码的热替换。 书中还说到: Java 程序中根本有一个共识:OSGI对类加载器的应用时值得学习的,弄懂了OSGI的实现,就能够算是把握了类加载器的精华。 牛逼啊!!! 当初,咱们曾经根本明确了Java默认的类加载的作用了原理,也晓得双亲委派模型。说了这么多,差点把咱们的tomcat给忘了,咱们的题目是Tomcat 加载器为何违反双亲委派模型?上面就好好说说咱们的tomcat的类加载器。 4. Tomcat 的类加载器是怎么设计的? 首先,咱们来问个问题: ...

September 5, 2023 · 1 min · jiezi

关于java:Spring-MVC-五-DispatcherServlet初始化过程续

明天的内容是SpringMVC的初始化过程,其实也就是DispatcherServilet的初始化过程。 Special Bean TypesDispatcherServlet委托如下一些非凡的bean来解决申请、并渲染正确的返回。这些非凡的bean是Spring MVC框架治理的bean、依照Spring框架的约定解决相干申请,个别状况下是框架内置的,咱们当然也能够定制或扩大他们的性能。 这些非凡bean包含: HandlerMapping:依据肯定的规定把申请映射到对应的HandlerMapping去解决,HandlerMapping能够蕴含一系列拦截器,进行前置或后置解决。框架默认提供了RequestMappingHandlerMapping(解决@RequestMapping注解办法的)和SimpleUrlHandlerMapping两个HandlerMapping。HandlerAdapter:HandlerMapping匹配到申请之后,调用HandlerAdapter具体解决申请。HandlerExceptionResolver:产生异样后的异样处理器。ViewResolver:解决返回LocaleResolver, LocaleContextResolver:本地化处理器ThemeResolver:Theme渲染处理器MultipartResolver:Multipart处理器,文件上传下载的解决。FlashMapManager:跨申请存储和获取“input”和“output”的处理器Web MVC ConfigDispatcherServlet初始化过程中会依据WebApplicationContext的配置(xml或注解形式,后面两篇文章剖析过)实现上述非凡bean的初始化,如果DispatcherServlet在WebApplicationContext中没有发现相应的配置,则采纳DispatcherServlet.properties文件中的默认配置实现初始化。 DispatcherServlet.properties文件在Spring web mvc包下: 咱们猜测Spring MVC框架是通过DispatcherServlet的init办法实现上述各非凡bean的初始化的,上面咱们要详细分析一下具体的初始化过程。 Servlet Config通过注解形式、或通过xml形式初始化DispatcherServlet的具体方法,后面两篇文章曾经做过剖析,此处不在赘述。 DispatcherServlet的初始化家喻户晓,Servlet容器(比方Tomcat)会通过调用Servlet的init办法实现Servlet的初始化。 咱们接下来看一下DispatcherServlet的初始化过程,也就是DispatcherServlet的init办法。 先来看一眼DispatcherServlet的类构造: init办法在他的父类HttpServletBean中: @Override public final void init() throws ServletException { // Set bean properties from init parameters. PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); if (!pvs.isEmpty()) { try { BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); initBeanWrapper(bw); bw.setPropertyValues(pvs, true); } catch (BeansException ex) { if (logger.isErrorEnabled()) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); } throw ex; } } // Let subclasses do whatever initialization they like. initServletBean(); }下面的代码是对以后Servlet属性的解决,与咱们的指标无关,初始化逻辑在最上面的办法initServletBean中,在他的子类(也是DispatcherServlet的间接父类)FrameworkServlet中: ...

September 4, 2023 · 4 min · jiezi

关于java:时间复杂度简述

工夫复杂度(1)工夫频度 一个算法执行所消耗的工夫,从实践上是不能算进去的,必须上机运行测试能力晓得。但咱们不可能也没有必要对每个算法都上机测试,只需晓得哪个算法破费的工夫多,哪个算法破费的工夫少就能够了。并且一个算法破费的工夫与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它破费工夫就多。一个算法中的语句执行次数称为语句频度或工夫频度。记为T(n)。(2)工夫复杂度 在方才提到的工夫频度中,n称为问题的规模,当n一直变动时,工夫频度T(n)也会一直变动。但有时咱们想晓得它变动时出现什么法则。为此,咱们引入工夫复杂度概念。 个别状况下,算法中基本操作反复执行的次数是问题规模n的某个函数,用T(n)示意,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进工夫复杂度,简称工夫复杂度。 另外,下面公式中用到的 Landau符号其实是由德国数论学家保罗·巴赫曼(Paul Bachmann)在其1892年的著述《解析数论》首先引入,由另一位德国数论学家艾德蒙·朗道(Edmund Landau)推广。Landau符号的作用在于用简略的函数来形容简单函数行为,给出一个上或下(确)界。在计算算法复杂度时个别只用到大O符号,Landau符号体系中的小o符号、符号等等比拟不罕用。这里的O,最后是用大写希腊字母,但当初都用大写英语字母O;小o符号也是用小写英语字母o,符号则维持大写希腊字母。 T(n) = (f (n)) 示意存在一个常数C,使得在当n趋于正无穷时总有 T (n) ≤ C f(n)。简略来说,就是T(n)在n趋于正无穷时最大也就跟f(n)差不多大。也就是说当n趋于正无穷时T (n)的上界是C f(n)。其尽管对f(n)没有规定,然而个别都是取尽可能简略的函数。例如,O(2n2+n +1) = O (3n2+n+3) = O (7n2 + n) = O ( n2 ) ,个别都只用O(n2)示意就能够了。留神到大O符号里暗藏着一个常数C,所以f(n)里个别不加系数。如果把T(n)当做一棵树,那么O(f(n))所表白的就是树干,只关怀其中的骨干,其余的细枝末节全都摈弃不论。 在各种不同算法中,若算法中语句执行次数为一个常数,则工夫复杂度为O(1),另外,在工夫频度不雷同时,工夫复杂度有可能雷同,如 T(n)=n2+3n+4与T(n)=4n2+2n+1它们的频度不同,但工夫复杂度雷同,都为O(n2)。 按数量级递增排列,常见的工夫复杂度有:常数阶O(1),对数阶O(log2n),线性阶O(n), 线性对数阶O(nlog2n),平方阶O(n2),立方阶O(n3),..., k次方阶O(nk),指数阶O(2n)。随着问题规模n的一直增大,上述工夫复杂度一直增大,算法的执行效率越低。

September 4, 2023 · 1 min · jiezi

关于java:程序员你如何写可重复执行的SQL语句

上图的意思: 屡战屡败,屡试不爽。 故事 程序员小张: 刚毕业,加入工作1年左右,日常工作是CRUD 架构师老李: 多个大型项目教训,精通各种开发架构屠龙宝术; 小张留神到,在理论的我的项目开发场景中,很多开发人员只关注编写SQL脚本来满足性能需要,而疏忽了脚本的可反复执行性。 这就意味着,如果脚本中的某个局部执行失败,运维人员就必须从头提供一个新的脚本,这对运维团队和开发人员来说是一个挑战。 因而,小张决定钻研如何编写基于MySQL的能够反复执行的SQL脚本,以进步开发效率和简化运维流程。 他向公司的架构师老李征询了这个问题。老李是一位经验丰富的架构师, 他在多个大型项目中积攒了许多贵重的教训,精通各种开发架构屠龙宝术。 老李听了小张的问题后,笑了笑并开始给予领导。他向小张解释了如何编写一个具备可反复执行性的SQL脚本,并分享了以下几个关键点: a.应用事务:事务是一组SQL语句的逻辑单元,能够保障这组语句要么全副执行胜利,要么全副回滚。 通过应用事务,能够确保脚本的所有批改操作要么残缺地执行,要么不执行。b.应用条件查看:在每个须要批改数据的语句之前,增加条件查看以确保只有当数据不存在或满足特定条件时才进行批改。 这样能够防止反复插入雷同的数据,或者执行不必要的更新操作。c.错误处理:在编写脚本时,思考到可能呈现的谬误状况,并提供适当的错误处理机制。例如,应用IF...ELSE语句来解决特定条件下的执行逻辑。 d.应用存储过程:如果脚本非常复杂,蕴含多个步骤和业务逻辑,能够思考将它们封装为存储过程。这样能够更好地组织和治理代码,并进步脚本的可读性和维护性。 小张听得津津乐道,他开始将老李的倡议付诸实践。他认真钻研每个SQL语句,依据老李的领导进行批改和优化。 他应用了事务来包裹整个脚本,增加了条件查看来防止反复插入数据,并实现了错误处理机制以应答异常情况。 背景所以开发提供给到运维的SQL脚本有肯定根本要求: 1.能反复执行; 2.不出错,(不报错,逻辑正确); 如果脚本不可反复执行,则运维无奈自动化,会反过来要求后端开发人员给出适配以后环境的新的SQL脚本,减少了运维和沟通老本。 那么怎么写可反复执行的SQL脚本呢? 分成4个场景,来介绍举例。 1 创立表create table if not exists nginx_config ( id varchar(36) not null default '' comment 'UUID', namespace varchar(255) not null default '' comment '环境命名空间', config_content text comment "nginx http块配置", content_md5 varchar(64) not null default '' comment '配置内容的MD5值', manipulator varchar(64) not null default '' comment '操作者', description varchar(512) not null default '' comment '形容', gmt_created bigint unsigned not null default 0 comment '创立工夫', primary key(id))ENGINE=InnoDB comment 'nginx配置表' ;删除表在生产环境是禁止的。 ...

September 4, 2023 · 6 min · jiezi

关于java:前瞻|Java-21-新特性-String-Templates字符串模版

在日常写Java的时候,对于字符串的操作是十分广泛的,其中最常见的就是对字符串的组织。也因为这个操作十分广泛,所以诞生了很多计划,总下来大略有这么几种: 应用+拼接应用StringBuffer和SpringBuilderString::format and String::formatted应用java.text.MessageFormat上面,咱们一起来学习一下Java 21中的新计划!如果您对于下面这些还不相熟的话,倡议能够先看一下这篇《Java自带的4种字符串组织和格式化办法》,理解以前的机制,这样与最新的解决计划做比照,了解会更粗浅。 模版表达式在Java 21中解决字符串的新办法称为:Template Expressions,即:模版表达式。 模版表达式是Java语言中的一种新表达式。它能够执行字符串插值,帮忙开发人员通过编程的形式平安高效地组织字符串。此外,模板表达式不仅仅能够用于组织字符串,它还能够依据特定模型的规定将结构化文本转换为任何类型的对象。 上面通过一个简略的案例来认识一下它: String blog = "blog.didispace.com";String str = STR."My blog is \{blog}";上述代码中的第2行就是一个模版表达式,其中次要蕴含三个局部: 模版处理器:STR蕴含内嵌表达式(\{blog})的模版通过.把后面两局部组合起来,模式上相似办法调用当模版表达式运行的时候,模版处理器会将模版内容与内嵌表达式的值组合起来,生成后果,所以下面案例中的字符串str在运行时的后果为:My blog is blog.didispace.com。 多行模版表达式还记得之前咱们的Java新个性专栏中,介绍过Java 15中的文本块个性吗?相似上面这样的写法: String html = """ <html> <body> <h1>Java 15 新个性:文本块 | 程序猿DD</h1> <p>didispace.com</p> </body> </html> """;模版表达式也反对相似的多行字符串解决,所以开发者能够用它来不便的组织html、json、xml等字符串内容,比方上面这样: var json = STR."""{ "user": "\{name}", "age: \{age}}""";STR模版处理器下面案例中咱们所用的STR模版处理器中的内嵌表达式都采纳了字符串内容,而实际上STR模版处理器还有更多的用处。 内嵌表达式中还能够之前数学运算,比方:int x = 10, y = 20;String s = STR."\{x} + \{y} = \{x + y}";最终s字符串后果为:10 + 20 = 30 ...

September 4, 2023 · 2 min · jiezi

关于java:点了下详情系统CPU-100%

作者:玛奇玛 \链接:https://juejin.cn/post/7233307834456129593 又是一个百无聊赖的晚上,我在高兴地摸鱼,工作群响了:离线零碎登录不上了。我第一反馈是不迷信啊,零碎曾经很久改变过了...连忙上生产环境看看,CPU高达1200%。接着又是熟练地敲出那几行排查CPU过高的命令: top -H -p pid 查看java占用率最高的几条线程jstack pid > xxx.txt 打印线程快照jmap -heap pid 查看堆内存状况举荐一个开源收费的 Spring Boot 实战我的项目: https://github.com/javastacks/spring-boot-best-practice 看这玩意啥都看不出来,感觉是零碎对象没有开释,在疯狂GC,然而因为FULL GC的时候曾经STW了,所以无奈查看到底是哪个线程出了问题。而后过了10分钟零碎忽然又好了....梗塞的操作曾经实现,gc能失常回收了。 而后过了两分钟又卡死了,我先重启了零碎,前面再剖析剖析。 等零碎没什么人用的时候,我再试着重现一下问题,关上零碎一顿乱点,后果是点开某个性能的详情时零碎卡住了,CPU又飚下来了,脍炙人口~问题定位到了,再实锤一下之前是不是这个问题,我看了一下localhost_access_log日志发现,的确是这个接口卡了一千多秒。 因为离线没什么人应用,所以问题过了很久再裸露进去,看了一下代码,次要是业务逻辑问题,有个参数没传进去,导致sql要查很久,查到了几百万的数据,gc也无奈回收。 复盘一开始我认为是某个接口调了很屡次并发太高导致的,没想到点一下详情零碎就挂了。。咱们能够看到CPU在GC回收的时候STW,是没有线程能占用到CPU的,所以top -H -p pid 只能看到CPU全被GC线程占用了。如果是某个接口并发太高导致的,咱们能够看jstack线程快照,外面是会有这个接口在执行的记录。 还有一个问题就是说零碎GC卡了10-20分钟,却没有报OOM,还是始终在梗塞状态,前面还失常了一小会,这个是须要看堆内存的状况..因为比拟难排查所以只是通过景象晓得GC还是能够回收一点点垃圾的 总结1、CPU100%的时候能够打印线程快照jstack pid,查看是哪个线程占用了CPU,个别都是某个业务线程阻塞无奈进行GC回收导致。 2、能够查看localhost_access_log查看零碎接口用时,个别用时很久的都是有问题的接口。 3、记得看业务代码参数有没有漏传,如果漏传参数可能会导致全表扫描间接卡死零碎。 近期热文举荐: 1.1,000+ 道 Java面试题及答案整顿(2022最新版) 2.劲爆!Java 协程要来了。。。 3.Spring Boot 2.x 教程,太全了! 4.别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!! 5.《Java开发手册(嵩山版)》最新公布,速速下载! 感觉不错,别忘了顺手点赞+转发哦!

September 4, 2023 · 1 min · jiezi

关于java:java关键字整理

简介关键字java关键字一共有53个,蕴含51个关键字加两个保留字(goto和const).关键字是对java编译器有非凡含意的字符串,不能被程序员用作定义包、类、成员属性、办法、部分属性的名称. abstractassertbooleanbreakbytecasecatchcharclasscontinuedefaultdodoubleelseenumextendsfalsefinalfinallyfloatforifimplementsimportinstanceofintinterfacelongnativenewnullpackageprivateprotectedpublicreturnstrictfpshortstaticsuperswitchsynchronizedthisthrowthrowstransienttruetryvoidvolatilewhileconst(保留字)goto(保留字)分组归类包(2)关键字应用阐明package定义包门路import引入包须要的java文件名拜访修饰符(3)关键字应用阐明public用作类、成员属性、办法上,示意被润饰者可被全局拜访.protected用作成员属性、办法上,示意被润饰者可被以后包下的类或者子类拜访.private用作成员属性、办法上,示意被润饰者可被以后类拜访.定义文件类型、关系、创建对象(6)关键字应用阐明class定义该文件为java类.interface定义该文件为java接口.enum定义该文件为java枚举.extends示意该类继承父类或者该接口继承父接口,单继承(只能有一个父类或父接口),子类如果不是抽象类,必须实现父类所有的形象办法否则也为抽象类.implements示意实现父接口,多实现(能够有一个或多个父接口),子类如果不是抽象类,必须实现父类所有的形象办法否则也为抽象类.new创建对象(类的实例)数据类型(12)关键字应用阐明boolean8个根本类型之一,占1个字节,润饰的对象示意虚实byte8个根本类型之一,占1个字节,润饰的对象示意字节大小char8个根本类型之一,占2个字节,润饰的对象示意字符大小short8个根本类型之一,占2个字节,润饰的对象示意短整型int8个根本类型之一,占4个字节,润饰的对象示意整型long8个根本类型之一,占8个字节,润饰的对象示意长整型float8个根本类型之一,占4个字节,润饰的对象示意单精度浮点型double8个根本类型之一,占8个字节,润饰的对象示意双精度浮点型void润饰的办法示意无返回值null示意空值,用来对非根本类型的变量赋空值true示意真,用来对boolean类型的变量赋真false示意假,用来对boolean类型的变量赋假流程管制(13)关键字应用阐明if条件判断,为真则进入条件体外部执行代码,为假则不进入else须要与if配合应用,if条件不满足,会进行else的条件判断,满足条件或没有判断条件会间接进入外部执行代码,if条件满足则间接跳过else外部代码体while循环条件判断,为真则进入条件体内执行代码,执行实现后需再次判断条件体为真则继续执行,为假则跳过while体内代码do与下面的while配合应用,与下面的区别是while体内的代码会先被执行一次在做条件的虚实判断for循环条件判断,体内条件为双分号,会先执行第一个分号前的内容,第一个分号后的为判断条件,为真则执行条件体内代码,执行实现后需执行第二分号后的内容,而后再次判断条件体为真则继续执行,为假则跳过for体内代码switch抉择对应的变量类型的值,通常与case一起配合应用,变量类型能够是byte、short、int或者char、从jdk1.7当前也反对了字符串.case与下面switch关键字配合应用,示意case前面的值和switch的值相等则进入case体内执行对应代码,如果执行代码最初没有break关键字,则会继续执行下方case的代码,直到完结.如果有return则退出执行switch代码体.default与下面switch和case关键字配合应用,示意case条件的值都不相等,则进入default办法体内的代码执行.其它同case的流程管制逻辑break跳出该循环体,常与case、while、for等关键字配合应用contine跳过该循环体前面的代码,间接进入条件判断,长于while、for等关键字配合应用return退出对应办法,前面会有值或没有值,次要看办法是否定义了返回对象instanceof是一个二元操作符,示意右边对象是否是左边对象同对象或者子对象assert断言条件判断,满足继续执行,不满足则抛出一个AssertionError异常中断代码体的执行修饰符(10)关键字应用阐明abstract用来润饰类,办法,示意该类或者该办法是形象的,须要被子类给从新实现static用来润饰成员属性、办法,示意被润饰者都是类资源,能够间接用类名调用.该类的所有实例都能够共享该类资源final用来润饰类、办法、变量,示意被润饰者初始化后不能被批改super示意该类父类的援用this示意该类的援用native用来润饰办法,示意该办法须要本地办法栈去调用本地代码办法synchronized用来润饰办法、对象,示意将该对象资源(实例对象或类对象)进行上锁同步,保障代码的有序性和原子性,但不能保障可见性transient用来润饰成员属性,示意该属性不能对序列化volatile用来润饰成员属性,示意该属性的可见性,也能保障代码的有序性.但不能保障原子性strictfp用来润饰类、接口、办法,能够保障其运算后果的精度一致性(个别状况下很少应用,会影响代码的运行效率)异样(5)关键字应用阐明try与catch或finally配合应用,该代码块中的办法,如果出现异常则会退出执行进入catch或finally代码块执行catch与try配合应用,catch的代码异样属于try代码块抛出的异样之内(instanceof),则会进入catch体内执行,否则判断是否满足下一个catch块中的异样.finally与try配合应用,不论是否有异样finally中的代码在返回之前都会被执行throw抛出异样,在办法内应用throws抛出异样,在办法上应用保留字(2)保留字应用阐明const润饰局部变量,示意不能被批改goto跳转到指定标签继续执行总结java关键字是浏览和编写java代码的根底,必须要先了解每个关键字的正确含意作用.以上整顿如有谬误,还望大家进行斧正,谢谢! [下一篇 介绍volatile和synchronized关键字详解]

September 3, 2023 · 1 min · jiezi

关于java:finalfinally和finalize的区别

final,finally和finalize的区别final关键字用于润饰变量、办法和类。当用于润饰变量时,示意该变量的值不能被批改;当用于润饰办法时,示意该办法不能被子类重写;当用于润饰类时,示意该类不能被继承。应用final关键字能够提供安全性、效率性、稳定性等方面的益处。finally关键字用于结构化异样解决中的try-catch-finally语句块。无论在try块中是否产生异样,finally块中的代码总会被执行。通常状况下,finally块用于开释资源、敞开连贯或者执行必须要做的清理工作。finalize是一个办法,它是在对象被垃圾回收器回收之前调用的。在Java中,通过重写finalize办法,能够在对象被销毁前进行一些特定的操作,比方开释资源、敞开连贯等。然而,因为垃圾回收的机会是不确定的,因而不倡议适度依赖finalize办法来开释资源,最好应用显式的资源开释形式。总的来说就是: final关键字用于润饰变量、办法和类,别离示意不可批改、不能被重写和不能被继承;finally关键字用于结构化异样解决中的try-catch-finally语句块,用于保障代码块中的语句无论是否产生异样都会被执行;finalize办法是在对象被垃圾回收之前调用的办法,能够用来执行对象销毁前的清理工作。

September 3, 2023 · 1 min · jiezi

关于java:Linux命令

ip addr:查看IPpwd:查看以后所在目录shutdown -h now:立刻关机reboot :重启ping ip或域名:查看网络是否OKctrl + c:强制完结占用窗口的命令top:查看内存状况kill -9 pid:强制杀死指定过程ps -ef | grep -i 过程名字:查看过程运行信息 '|'是管道命令clear:清屏history:查看历史命令-->!历史命令编号:执行历史命令具体命令 -h:查看具体命令的帮忙信息 目录相干命令cd [目录或符号]:切换指定目录-->符号:~[波浪线]:家目录 .:当前目录 ..:下级目录 -:从哪来,回哪去ls参数:展现指定目录下的内容-->参数-a:展现所有 -b:展现目录 -1:以列表的模式展现目录:有,则展现指定目录内容无,展现以后所有目录内容mkdir[-p]目录名:创立目录 -p:创立多级目录rm[-rf]目录名:删除目录 -r:递归 -f:不提醒cp[-r]原目录 指标门路:复制目录mv 原目录 指标门路:指标门路存在,则挪动;指标门路不存在,能够挪动后再改名 文件相干命令touch 文件名:创立新文件vi 文件名:编辑文件 ->三种模式:查看模式[命令模式] ->编辑模式[插入模式]:批改内容 ->底行模式:->:wq保留并退出 :q!不保留退出 :set nu 显示行号 :set nonu勾销行号显示 :n定位到第n行,如:10就是定位到第10行 查看文件展现文件所有内;实用于看小文件 ->more:分页展现文件内容;实用于看大文件; ->tail [-f] 文件名:动静查看文件内容;监控日志文件rm -f 文件名1 文件名2:删除文件不提醒cp原文件名 目录指标:赋值文件到指定目录mv:mv文件名 目录:挪动 ->:mv 文件名 目录/新文件名 批改文件名tar:tar -zcvf 压缩后的文件名 被压缩的文件或目录列表:压缩tar -zxvf 要解压缩的文件名[-C 指定目录] :解压缩参数阐明:-z:z代表的是gzip,通过gzip命令解决文件,gzip能够对文件压缩或者解压-c:c打包或压缩-x:x解包或解压-v:v显示进度条-f:f为文件取一个名字 5.查找命令find 目录 参数 文件名 :查看本人定义的文件-->find/etc -name*profilegrep 内容 文件名:从指定文件中查找指定的文本内容:grep Hello*.java->grep -n Hello*.java:-n示意显示行号 ...

September 3, 2023 · 1 min · jiezi

关于java:多线程

什么要应用多线程?先从总体上来说:从计算机底层来说: 线程能够比作是轻量级的过程,是程序执行的最小单位,线程间的切换和调度的老本远远小于过程。另外,多核 CPU 时代意味着多个线程能够同时运行,这缩小了线程上下文切换的开销。从当代互联网发展趋势来说: 当初的零碎动不动就要求百万级甚至千万级的并发量,而多线程并发编程正是开发高并发零碎的根底,利用好多线程机制能够大大提高零碎整体的并发能力以及性能。再深刻到计算机底层来探讨:单核时代:在单核时代多线程次要是为了进步单过程利用 CPU 和 IO 零碎的效率。 假如只运行了一个 Java 过程的状况,当咱们申请 IO 的时候,如果 Java 过程中只有一个线程,此线程被 IO 阻塞则整个过程被阻塞。CPU 和 IO 设施只有一个在运行,那么能够简略地说零碎整体效率只有 50%。当应用多线程的时候,一个线程被 IO 阻塞,其余线程还能够持续应用 CPU。从而进步了 Java 过程利用系统资源的整体效率。多核时代: 多核时代多线程次要是为了进步过程利用多核 CPU 的能力。举个例子:如果咱们要计算一个简单的工作,咱们只用一个线程的话,不管零碎有几个 CPU 外围,都只会有一个 CPU 外围被利用到。而创立多个线程,这些线程能够被映射到底层多个 CPU 上执行,在工作中的多个线程没有资源竞争的状况下,工作执行的效率会有显著性的进步,约等于(单核时执行工夫/CPU 外围数)。 应用多线程可能带来什么问题?并发编程的目标就是为了能进步程序的执行效率进步程序运行速度,然而并发编程并不总是能进步程序运行速度的,而且并发编程可能会遇到很多问题,比方:内存透露、死锁、线程不平安等等。如何了解线程平安和不平安? 线程平安和不平安是在多线程环境下对于同一份数据的拜访是否可能保障其正确性和一致性的形容。线程平安指的是在多线程环境下,对于同一份数据,不论有多少个线程同时拜访,都能保障这份数据的正确性和一致性。线程不平安则示意在多线程环境下,对于同一份数据,多个线程同时拜访时可能会导致数据凌乱、谬误或者失落。

September 2, 2023 · 1 min · jiezi

关于java:从零开发Java入门项目十天掌握

简介这是一个靠谱的Java入门我的项目实战,名字叫蚂蚁爱购。从零开发我的项目,视频加文档,十天就能学会开发Java我的项目,教程路线是:搭建环境=> 装置软件=> 创立我的项目=> 增加依赖和配置=> 通过表生成代码=> 编写Java代码=> 代码自测=> 前后端联调=> 筹备找工作。 学完即可成为合格的Java开发,心里有底,再也不必放心不会应用git、再也不必放心还没转正就被解雇、再也不必放心胜任不了工作、再也不必放心面试官问具体开发流程时一脸懵逼了。 这个教程在自学精灵这个网站上,地址是:JavaWeb入门我的项目实战专栏介绍 - 自学精灵。也能够用百度搜自学精灵(搜不到就用必应搜)。 网站截图主页 编辑 Java学习路线 编辑 Java入门我的项目  编辑

September 2, 2023 · 1 min · jiezi

关于java:单点应用Key锁可重入锁

/** * 单机、粒度为key的可重入锁。 * 同一个 key、同一时刻,只能一个线程执行 * @see java.util.concurrent.locks.Lock * @see java.util.concurrent.locks.ReentrantLock */public interface KeyLock<T> { /** * 加锁 */ void lock(T key); boolean tryLock(T key, long time, TimeUnit unit); /** * 解锁 */ void unlock(T key);}@Slf4jpublic class DefaultKeyLock<T> implements KeyLock<T> { private final Map<T, ReentrantLock> lockMap = new ConcurrentHashMap<>(); @Override public void lock(T key) { Preconditions.checkArgument(Objects.nonNull(key), "key can not be null "); ReentrantLock lock = lockMap.computeIfAbsent(key, k -> new ReentrantLock()); lock.lock(); } @SneakyThrows(value = {InterruptedException.class}) @Override public boolean tryLock(T key, long time, TimeUnit unit) { Preconditions.checkArgument(Objects.nonNull(key), "key can not be null "); ReentrantLock lock = lockMap.computeIfAbsent(key, k -> new ReentrantLock()); boolean flag = lock.tryLock(time, unit); if (flag) { log.info("get the lock {} success", key); } else { log.info("get the lock {} failure", key); } return flag; } @Override public void unlock(T key) { Preconditions.checkArgument(Objects.nonNull(key), "key can not be null "); ReentrantLock lock = lockMap.get(key); if (Objects.isNull(lock)) { throw new IllegalArgumentException("key: " + key + " does not own a lock "); } if (!lock.isHeldByCurrentThread()) { throw new IllegalStateException("current thread does not oww a lock,key:" + key); } lock.unlock(); log.info("release the lock {} success", key); }}

September 1, 2023 · 1 min · jiezi

关于java:锁分布式redission-SpringAop-SpringEL-OGNL

引言:非单点利用,JDK自带的管程锁(即:监视器锁、Monitor锁,通过synchronized关键字来实现加锁)、或可重入锁(ReentrantLock)已无奈做到对临界资源的加锁,达到同步拜访的目标。 简介:分布式锁基于Redis + SpringAOP来实现,通过申明式注解的形式为具体临界资源加锁,达到同步拜访的目标。 实现:RedissionLock注解类定义:@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface RedissonLock { /** * 锁生效工夫 * 默认-1秒,永恒持有,直到以后锁被开释 */ int expireTime() default -1; /** * 抢锁等待时间,默认30秒,-1示意不期待,胜利或失败都立刻返回 */ int waitTime() default 30; /** * 锁过期工夫单位,默认秒 */ TimeUnit expireTimeUnit() default TimeUnit.SECONDS; /** * 抢锁等待时间单位,默认秒 */ TimeUnit waitTimeUnit() default TimeUnit.SECONDS; //-------------------------------------------------------------------- // redisKey 对 values、expressions、spEL、keyGenerator 进行拼接 //-------------------------------------------------------------------- /** * redisKey */ String[] values() default {}; /** * redisKey * 反对OGNL表达式 */ String[] expressions() default {}; /** * redisKey * Spring Expression Language (SpEL) expression for computing the key dynamically. */ String[] spEL() default {}; /** * The bean name of the custom {@link RedisKeyGenerator} to use. */ String keyGenerator() default ""; /** * 未拿锁时的错误码 * MSG_1000007(1000007, "零碎忙碌,请稍后再试(key=%s)") */ ErrCode errorCode() default ErrCode.MSG_1000007; /** * 等锁超时,是否抛出异样 */ boolean throwExceptionWhenTryLockTimeOut() default true;}RedisKeyGenerator接口定义:@FunctionalInterfacepublic interface RedisKeyGenerator { /** * Generate a key for the given method and its parameters. * @param target the target instance * @param method the method being called * @param params the method parameters (with any var-args expanded) * @return a generated key */ String generate(Object target, Method method, Object... params);}切面定义:/** * 确保此切面执行程序在事务切面之前。事务切面执行程序是 {@link Integer#MAX_VALUE} */@Slf4j@Aspect@Order(0)@Componentpublic class LockAop implements ApplicationContextAware { @Resource private RedissonClient redissonClient; @Pointcut("@annotation(RedissonLock)") private void pointCut() { } private static final String prefix = "c:e:lock:"; @Around(value = "pointCut() && @annotation(redissonLock)") public Object around(ProceedingJoinPoint joinPoint, RedissonLock redissonLock) throws Throwable { String redisKey; // 字符串 StringJoiner joiner = new StringJoiner(":", prefix, StringUtils.EMPTY); String[] values = redissonLock.values(); if (ArrayUtils.isNotEmpty(values)) { for (String value : values) { joiner.add(value); } } // OGNL 表达式 String[] expressions = redissonLock.expressions(); if (ArrayUtils.isNotEmpty(expressions)) { // 根对象 Map<String, Object> rootObject = getVariables(joinPoint); for (String expression : expressions) { joiner.add(String.valueOf(OgnlCache.getValue(expression, rootObject))); } } // Spring EL 表达式 String[] spEL = redissonLock.spEL(); if (ArrayUtils.isNotEmpty(spEL)) { StandardEvaluationContext context = new StandardEvaluationContext(); // 上下文对象中的变量 Map<String, Object> rootObject = getVariables(joinPoint); context.setVariables(rootObject); SpelExpressionParser spelExpressionParser = new SpelExpressionParser(); for (String el : spEL) { Expression expression = spelExpressionParser.parseExpression(el); String value = expression.getValue(context, String.class); joiner.add(value); } } // key 生成器 String keyGenerator = redissonLock.keyGenerator(); if (StringUtils.isNotEmpty(keyGenerator)) { if (applicationContext.containsBean(keyGenerator)) { RedisKeyGenerator bean = applicationContext.getBean(RedisKeyGenerator.class, keyGenerator); MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); String value = bean.generate(joinPoint.getTarget(), methodSignature.getMethod(), joinPoint.getArgs()); joiner.add(value); } } redisKey = joiner.toString(); if (StringUtils.isEmpty(redisKey)) { // MSG_1000008(1000008, "锁key不能为空") throw new ServiceException(ErrCode.MSG_1000008); } // 尝试获取锁 RLock rLock = redissonClient.getLock(redisKey); // 对立过期工夫和等待时间单位为纳秒 long expireTime = redissonLock.expireTime(); long waitTime = redissonLock.waitTime(); if (expireTime != -1) { expireTime = redissonLock.expireTimeUnit().toNanos(expireTime); } if (waitTime != -1) { waitTime = redissonLock.waitTimeUnit().toNanos(waitTime); } boolean tryLock = rLock.tryLock(waitTime, expireTime, TimeUnit.NANOSECONDS); if (!tryLock) { log.info("key=[{}] get the lock failure", redisKey); throw ServiceException.getInstance(redissonLock.errorCode(), redisKey); } log.info("key=[{}] get the lock success", redisKey); Object proceed; try { proceed = joinPoint.proceed(); } finally { if (rLock.isHeldByCurrentThread()) { rLock.unlock(); log.info("key=[{}] release the lock success", redisKey); } } return proceed; } private static Map<String, Object> getVariables(ProceedingJoinPoint joinPoint) { // 切面办法参数 Object[] args = joinPoint.getArgs(); // 拿到办法签名 MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Map<String, Object> map = new HashMap<>(); // 把参数名和参数对象仍入汇合 for (int i = 0; i < methodSignature.getParameterNames().length; i++) { String parameterName = methodSignature.getParameterNames()[i]; Object arg = args[i]; map.put(parameterName, arg); } return map; } private ApplicationContext applicationContext; @Override public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }}OGNL表达式应用参考:所有申请参数会用参数名和参数值存入一个Map中,并设置为根对象。 ...

September 1, 2023 · 3 min · jiezi

关于java:Spring-MVC-五-Spring-MVC的配置和DispatcherServlet初始化过程

明天的内容是SpringMVC的初始化过程,其实也就是DispatcherServilet的初始化过程。 Special Bean TypesDispatcherServlet委托如下一些非凡的bean来解决申请、并渲染正确的返回。这些非凡的bean是Spring MVC框架治理的bean、依照Spring框架的约定解决相干申请,个别状况下是框架内置的,咱们当然也能够定制或扩大他们的性能。 这些非凡bean包含: HandlerMapping:依据肯定的规定把申请映射到对应的HandlerMapping去解决,HandlerMapping能够蕴含一系列拦截器,进行前置或后置解决。框架默认提供了RequestMappingHandlerMapping(解决@RequestMapping注解办法的)和SimpleUrlHandlerMapping两个HandlerMapping。HandlerAdapter:HandlerMapping匹配到申请之后,调用HandlerAdapter具体解决申请。HandlerExceptionResolver:产生异样后的异样处理器。ViewResolver:解决返回LocaleResolver, LocaleContextResolver:本地化处理器ThemeResolver:Theme渲染处理器MultipartResolver:Multipart处理器,文件上传下载的解决。FlashMapManager:跨申请存储和获取“input”和“output”的处理器Web MVC ConfigDispatcherServlet初始化过程中会依据WebApplicationContext的配置(xml或注解形式,后面两篇文章剖析过)实现上述非凡bean的初始化,如果DispatcherServlet在WebApplicationContext中没有发现相应的配置,则采纳DispatcherServlet.properties文件中的默认配置实现初始化。 DispatcherServlet.properties文件在Spring web mvc包下: 咱们猜测Spring MVC框架是通过DispatcherServlet的init办法实现上述各非凡bean的初始化的,上面咱们要详细分析一下具体的初始化过程。 Servlet Config通过注解形式、或通过xml形式初始化DispatcherServlet的具体方法,后面两篇文章曾经做过剖析,此处不在赘述。 DispatcherServlet的初始化家喻户晓,Servlet容器(比方Tomcat)会通过调用Servlet的init办法实现Servlet的初始化。 咱们接下来看一下DispatcherServlet的初始化过程,也就是DispatcherServlet的init办法。 先来看一眼DispatcherServlet的类构造: init办法在他的父类HttpServletBean中: @Override public final void init() throws ServletException { // Set bean properties from init parameters. PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); if (!pvs.isEmpty()) { try { BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); initBeanWrapper(bw); bw.setPropertyValues(pvs, true); } catch (BeansException ex) { if (logger.isErrorEnabled()) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); } throw ex; } } // Let subclasses do whatever initialization they like. initServletBean(); }下面的代码是对以后Servlet属性的解决,与咱们的指标无关,初始化逻辑在最上面的办法initServletBean中,在他的子类(也是DispatcherServlet的间接父类)FrameworkServlet中: ...

September 1, 2023 · 4 min · jiezi

关于java:AREX-Java-Agent-插件开发指南

背景AREX 是一款开源的基于实在申请与数据的自动化回归测试平台,利用 Java Agent 技术与比对技术,通过流量录制回放能力实现疾速无效的回归测试。 AREX Agent 我的项目(arex-agent-java) 当初曾经反对了大部分开源组件的 Mock,但对某些公司外部齐全自研或是基于开源组件做了批改的根底组件还暂不反对,回放时可能会产生预期外的差别,针对这种问题,能够应用插件的模式对 AREX Agent 进行扩大,其余须要扩大或加强的场景相似。 以上面的代码为例,假如公司外部有个本人研发的数据库拜访层组件:DalClient Object result = dalClient.query(key)if (result != null) { return result; // 录制时数据库有值} else { return rpc.search(); // 回放时没值去调用了近程接口}这种场景下尽管能够应用动静类办法 Mock,但动静类反对绝对比较简单,且须要配置老本。 应用插件扩大的形式对 DalClient 组件进行 Mock,能够更灵便地自定义录制回放逻辑,适宜简单的场景。 上面咱们就以 DalClient 组件为例,具体介绍下如何开发对应的插件来对它进行录制回放。 环境搭建将 AREX Agent 的代码下载到本地并执行 mvn install:git clone https://github.com/arextest/arex-agent-java.git mvn clean install -DskipTests //这一步是把 arex-agent-java 相干依赖装置到你本地的 maven 仓库,咱们的插件我的项目可能须要援用创立一个一般的 Java 我的项目,这里抉择 IntelliJ IDEA 的 new project: 创立胜利后在 pom 文件中增加 AREX Agent 相干依赖: ...

September 1, 2023 · 4 min · jiezi

关于java:软件开发常说的CICD是什么

本文翻译自国外论坛 medium,原文地址:本文翻译自国外论坛 medium,原文地址:https://medium.com/gitconnected/basics-of-ci-cd-a98340c60b04 任何软件我的项目的次要指标都是通过业务流程疾速更新迭代来赚钱。咱们越快向客户公布新版本,对咱们的公司就约有益处。但如何疾速实现版本更新迭代呢?咱们能够手动实现。例如能够通过 SSH 连贯到近程服务器。而后咱们能够应用新代码克隆代码库、构建它并应用命令行运行它。只管这个形式的确无效,但这并不是一种便捷的办法。 因而本篇文章咱们将探讨如何将产品公布和开发过程实现自动化。 本文题目所写的 CI 和 CD 是两个缩写,别离代表继续集成和继续交付。CICI:继续集成形容了代码库变更的过程。让咱们看一个简略的模式,它给出了团队开发的示例。 一群人能够同时工作。但所有更改最终都会转移到 master 分支。不管怎样,即便是这样一个简略的模型也会引发一些问题。 咱们如何晓得进入 master 分支的代码能够编译通过?咱们心愿开发人员为代码编写测试。咱们如何验证测试覆盖率没有降落?所有团队成员都应应用指定的代码格调来格式化代码。咱们如何查看可能存在的违规行为?软件开发中,通常会将 master 分支作为主分支。dev 作为本地开发分支。为了实现以上几点,咱们能够把所有形容的要求都进行手动验证。不过这种办法非常复杂,当代码库越来越宏大时,这个形式并不可取。 于是乎 CI 的呈现是为了实现以上所提出的几点倡议并将其自动化。 第一点,咱们如何晓得进入 master 分支的代码能够编译通过? 咱们须要在架构中增加另一个模块,如下图。 大多数 CI 流程都能够依据这个架构来形容。 每次关上 Pull 申请(以及推送新更改)时,Git 服务器都会向 CI 服务器发送一条告诉。CI 服务器克隆代码库,检出谬误分支(例如 bugfix/wrong-sorting 分支),并与主分支合并。而后构建脚本将被启动。例如 ./gradlew 脚本执行构建操作。如果上一步脚本命令返回 0 代码,则构建胜利。否则视为失败。CI 服务器将带有构建后果的申请发送到 Git 服务器。如果构建胜利,则容许合并 Pull 申请。否则合并将被阻止。该过程保障进入主分支的任何代码都不会毁坏进一步的构建。 第二点,咱们心愿开发人员为代码编写测试。咱们如何验证测试覆盖率没有降落? 让咱们把工作变得更简单。假如咱们要设置最小测试覆盖率。任何时刻 master 分支的测试覆盖率都不应低于 50%。 Jacoco 插件能够轻松解决这个问题。如果测试覆盖率值小于可承受的值,咱们只需在构建时返回失败进行配置即可。 JaCoCo 是一个收费的 Java 代码笼罩库,由 EclEmma 团队依据多年来应用和集成现有库的经验教训创立。 JaCoCo 地址:https://www.eclemma.org/jacoco Jacoco 的应用非常简单,只须要在我的项目启动后配置插件就能工作。 设想一下,咱们正在开发一款已有五年历史的产品。自第一次提交以来,始终没有测试覆盖率查看。开发人员随便增加测试,没有任何纪律。但有一天,咱们决定进步测试覆盖率。咱们调整 Jacoco 插件,将最小测试覆盖率进步到 60%。一段时间后,开发人员关上一个新的 Pull 申请。而后他们忽然意识到整个我的项目测试覆盖率只有 30%。因而要胜利实现工作,整个我的项目必须笼罩至多 60% 的代码。正如咱们可能猜到的,对于这个已有五年历史的我的项目来说,这简直是一个无奈解决的问题。 ...

September 1, 2023 · 2 min · jiezi

关于java:Java-内存管理最佳实践

本文翻译自国外论坛 medium,原文地址:https://medium.com/@fullstacktips/best-practices-for-memory-m... 内存治理是编程的一个根本畛域之一,尤其是在 Java 开发中。当不再须要的对象没有失去正确处理时,就会产生内存透露,导致内存使用量一直增长,最终导致性能问题和应用程序解体。因而深刻理解如何在 Java 应用程序中无效应用内存并防止内存透露至关重要。 在这篇文章中,咱们将探讨防止内存透露和优化 Java 内存应用的最佳实际。 Java 应用程序内存透露的常见起因 在深入探讨最佳实际之前,咱们首先理解 Java 应用程序中内存透露的常见起因。以下是内存透露的一些最常见起因。 循环援用:当两个或多个对象以循环形式互相援用时,就会产生内存透露。当对象没有正确开释和垃圾收集时,就会产生这种状况。未敞开的资源:当文件句柄、数据库连贯或网络套接字等资源在应用后未正确敞开时,就会导致内存透露。过多的对象创立:不必要地创立过多的对象也会导致内存透露。Java 应用程序中内存治理的最佳实际为了防止 Java 应用程序中的内存透露并优化内存应用,开发人员应该遵循这些最佳实际。 1. 应用不可变对象不可变对象是指创立后状态无奈更改的对象。应用不可变对象能够帮忙防止循环援用引起的内存透露。不可变对象还能够通过缩小同步开销来进步性能。 例如,思考上面的类。 public final class Employee { private final String name; private final int age; private final Address address; public Employee(String name, int age, Address address) { this.name = name; this.age = age; this.address = address; } public String getName() { return name; } public int getAge() { return age; } public Address getAddress() { return address; }}在下面的示例中,Employee 类是不可变的,因为它的字段是 final 润饰,并且在对象创立后无奈更改。 ...

September 1, 2023 · 2 min · jiezi

关于java:常见的负载均衡策略有哪些

负载平衡策略是实现负载均衡器的要害,而负载均衡器又是分布式系统中不可或缺的重要组件。应用它有助于进步零碎的整体性能、可用性、可靠性和安全性,同时支持系统的扩大和故障容忍性。对于解决大量申请的应用程序和微服务架构来说,负载均衡器是不可或缺的重要工具。 负载平衡分类负载平衡分为服务器端负载平衡和客户端负载平衡。 服务器端负载平衡指的是寄存在服务器端的负载均衡器,例如 Nginx、HAProxy、F5 等。客户端负载平衡指的是嵌套在客户端的负载均衡器,例如 Ribbon。 常见负载平衡策略但无论是服务器端负载平衡和客户端负载平衡,它们的负载平衡策略都是雷同的,因为负载平衡策略实质上是一种思维。 常见的负载平衡策略有以下几个: 轮询(Round Robin):轮询策略依照程序将每个新的申请分发给后端服务器,顺次循环。这是一种最简略的负载平衡策略,实用于后端服务器的性能相近,且每个申请的解决工夫大致相同的状况。随机抉择(Random):随机抉择策略随机抉择一个后端服务器来解决每个新的申请。这种策略实用于后端服务器性能类似,且每个申请的解决工夫相近的状况,但不保障申请的散发是平均的。起码连贯(Least Connections):起码连贯策略将申请分发给以后连接数起码的后端服务器。这能够确保负载平衡在后端服务器的连贯负载上平衡,但须要保护连贯计数。IP 哈希(IP Hash):IP 哈希策略应用客户端的 IP 地址来计算哈希值,而后将申请发送到与哈希值对应的后端服务器。这种策略可用于确保来自同一客户端的申请都被发送到同一台后端服务器,实用于须要会话放弃的状况。加权轮询(Weighted Round Robin):加权轮询策略给每个后端服务器调配一个权重值,而后依照权重值比例来散发申请。这能够用来解决后端服务器性能不平衡的状况,将更多的申请分发给性能更高的服务器。加权随机抉择(Weighted Random):加权随机抉择策略与加权轮询相似,然而依照权重值来随机抉择后端服务器。这也能够用来解决后端服务器性能不平衡的状况,然而散发更随机。最短响应工夫(Least Response Time):最短响应工夫策略会测量每个后端服务器的响应工夫,并将申请发送到响应工夫最短的服务器。这种策略能够确保客户端取得最快的响应,实用于要求低提早的利用。 小结负载平衡分为服务器端负载平衡和客户端负载平衡,但无了是那种负载均衡器,它的罕用策略都是一样的,有轮询、随机抉择、起码连贯 IP 哈希、加权轮询、加权随机和最短响应工夫。 本文已收录到我的面试小站 www.javacn.site,其中蕴含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、音讯队列等模块。

September 1, 2023 · 1 min · jiezi

关于java:如何利用FuncGPT告别繁琐的开源代码调试

作为一名开发人员,您是否已经在浩如烟海的开源社区中搜寻代码,而后破费大量工夫测试、调试,最初才发现这些代码并不合乎您的需要?专一Java生成AI函数的FuncGPT(慧函数)就像您的私人编程助手,只需输出你的需要,就能提供符合要求的函数,让你辞别繁琐的搜寻、测试和调试,迈向高效的开发之旅。 一、传统代码搜寻的窘境 在传统的开发过程中,当你须要实现某个性能时,须要在开源社区中搜寻相干的代码。然而,这些代码可能存在各种问题,比方: 1、Bugs:许多开源代码在撰写时可能没有通过充沛的测试,导致存在各种潜在的谬误和破绽。2、Incompatible API:因为不同的开发环境和需要,某些开源代码所应用的API可能与你的我的项目不兼容。3、Performance issues:一些开源代码可能存在性能问题,比方运行速度慢或者占用过多内存。 面对以上这些问题,您须要破费大量的工夫和精力进行测试、调试和批改。然而,即使如此,也无奈保障这些代码可能完全符合你的理论需要。 二、代替搜索引擎?FuncGPT(慧函数)秒级生成函数 FuncGPT(慧函数),作为飞算SoFlu软件机器人的重要组成部分,反对所有类型函数创立。通过自然语言形容Java函数需要,实时生成高质量、高可读性的Java函数代码。生成代码可间接复制到IDEA,或一键导入Java全自动开发工具函数库。它将自然语言解决与函数生成相结合,为开发人员提供了一种疾速、精确的函数搜寻解决方案。 与传统搜寻形式相比,FuncGPT具备以下劣势:简略易用:只需通过自然语言输出需要,就能迅速提供相应的函数,升高软件开发门槛。精确高效:借助弱小的自然语言解决技术,可能精确了解您的需要,秒级实现并返回文档级函数。品质牢靠:生成的函数代码合乎业界标准、具备具体的正文,具备良好的可读性,合乎最优解。并通过测试用例疾速测试是否合乎开发人员的需要。一站式函数开发利用:函数生成即可间接利用,效率、平安有保障。灵便生成:能够依据开发人员的具体需要生成并反对调整和批改。 FuncGPT(慧函数)实用于多种场景,如: 遇到未知的函数问题:当您在开发过程中遇到未知的函数问题时,只需将问题输出到FuncGPT中,即可疾速取得答案。节俭搜寻工夫:在面对海量的函数时,FuncGPT能够帮忙您疾速筛选出合乎需要的函数,大大节俭了搜寻工夫。进步开发效率:通过FuncGPT,您能够轻松找到适合的函数,缩小不必要的开发工夫,从而进步工作效率。学习新常识:对于高级开发人员来说,FuncGPT能够作为一款学习工具,帮忙他们疾速了解Java函数的用法。 三、FuncGPT(慧函数)案例实操1、下载并装置FuncGPT:拜访云智官网或Gitee搜寻SoFlu软件机器人,下载并装置。2、关上FuncGPT搜寻框,输入您的问题,例如:“计算以后工夫加上特定天数当前的工夫?”3、点击生成函数后,大略24秒您会看到与问题相干的函数解决方案。 // 类名:DateTimeCalculator// 函数名:calculateFutureTime// 函数性能:计算以后工夫加上特定天数当前的工夫// POM依赖包:// <dependency>// <groupId>joda-time</groupId>// <artifactId>joda-time</artifactId>// <version>2.10.10</version>// </dependency>import org.joda.time.DateTime;public class DateTimeCalculator { /** * 计算以后工夫加上特定天数当前的工夫 * @param daysToAdd 要增加的天数 * @return 计算的后果工夫 */ public static DateTime calculateFutureTime(int daysToAdd) { DateTime currentDateTime = DateTime.now(); // 获取以后工夫 DateTime futureDateTime = currentDateTime.plusDays(daysToAdd); // 将特定天数增加到以后工夫 return futureDateTime; }}// 函数示例// 计算以后工夫加上特定天数当前的工夫示例// 入参:daysToAdd,要增加的天数// 出参:futureDateTime,计算的后果工夫// 调用示例:// int daysToAdd = 7;// DateTime futureDateTime = DateTimeCalculator.calculateFutureTime(daysToAdd);// System.out.println(futureDateTime);// 输入后果:例如,以后工夫为:2022-01-01 10:00:00,要增加的天数为:7// 则输入后果为:2022-01-08 10:00:00基于同样的需要,通过网上搜寻、筛选,咱们取得一段开源代码,如下: ...

September 1, 2023 · 1 min · jiezi

关于java:防资损建设

领取数据实时对账,本地领取数据和领取平台数据对账,有实时对账平台付款熔断: 依据桶每天限额,超过熔断。单个用户付款金额限额,超过熔断付款金额和昨日付款金额进行比对,稳定超过30%熔断,包含单人和整个桶熔断后群里发出通知,放行的话,桶放行改配置,集体放行配置白名单付款播报,每日就付款数据发群里日志监控,只有有error日志就告警发群里领取钱包配置是通过配置平台配置的,配置多个进行穿插配置,防止付款信息被他人改了,付款配置更改设置权限,设置更改变更告诉每个桶付款币种不一样,付款时传参币种与币种不统一付款不胜利付款后查问付款记录,查问不到付款记录熔断

September 1, 2023 · 1 min · jiezi

关于java:Java-8-的-Stream-不好调试别逗了IDEA-调试就能轻松搞定

起源:blog.csdn.net/qq_29879799/article/details/105146415 java的stream编程给调试带来了极大的不便,idea 推出了streamtrace性能,能够具体看到每一步操作的关系、后果,十分不便进行调试。 初遇StreamTrace 这里简略将字符串转成它的字符数,并设置断点开启debug模式。 如上图所示,能够看到每一步操作的元素个数、操作的后果、元素转换前后的对应关,十分清晰明了;还能够查看具体的对象内容。 应用StreamTrace StreamTrace只有在debug模式下能力应用,当在Stream代码上设置断点后,启动debug,点击流按钮,如图所示。 点击后,默认Split 模式显示。 能够点击左下方按钮切换到FlatMode模式,当然也能够再切换回去。 实战演示 这里演示一段字符转长度并过滤长度小于5的stream操作 @Test public void TestTrace() { Stream.of("beijing","tianjin","shanghai","wuhan") .map(String::length) .filter(e->e>5) .collect(Collectors.toList()); } 近期热文举荐: 1.1,000+ 道 Java面试题及答案整顿(2022最新版) 2.劲爆!Java 协程要来了。。。 3.Spring Boot 2.x 教程,太全了! 4.别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!! 5.《Java开发手册(嵩山版)》最新公布,速速下载! 感觉不错,别忘了顺手点赞+转发哦!

September 1, 2023 · 1 min · jiezi

关于java:换上-HikariCP-连接池太快了

背景在咱们平时的编码中,通常会将一些对象保存起来,这次要思考的是对象的创立老本。 比方像线程资源、数据库连贯资源或者 TCP 连贯等,这类对象的初始化通常要花费比拟长的工夫,如果频繁地申请和销毁,就会消耗大量的系统资源,造成不必要的性能损失。 并且这些对象都有一个显著的特色,就是通过轻量级的重置工作,能够循环、反复地应用。 这个时候,咱们就能够应用一个虚构的池子,将这些资源保存起来,当应用的时候,咱们就从池子里疾速获取一个即可。 在 Java 中,池化技术利用十分宽泛,常见的就有数据库连接池、线程池等,本文主讲连接池,线程池咱们将在后续的博客中进行介绍。 专用池化包 Commons Pool 2咱们首先来看一下 Java 中专用的池化包 Commons Pool 2,来理解一下对象池的个别构造。 依据咱们的业务需要,应用这套 API 可能很容易实现对象的池化治理。 <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 --><dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.11.1</version></dependency>GenericObjectPool 是对象池的外围类,通过传入一个对象池的配置和一个对象的工厂,即可疾速创建对象池。 public GenericObjectPool( final PooledObjectFactory<T> factory, final GenericObjectPoolConfig<T> config)举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practice案例Redis 的罕用客户端 Jedis,就是应用 Commons Pool 治理连接池的,能够说是一个最佳实际。下图是 Jedis 应用工厂创建对象的次要代码块。 对象工厂类最次要的办法就是makeObject,它的返回值是 PooledObject 类型,能够将对象应用 new DefaultPooledObject<>(obj) 进行简略包装返回。 redis.clients.jedis.JedisFactory,应用工厂创建对象。 @Overridepublic PooledObject<Jedis> makeObject() throws Exception { Jedis jedis = null; try { jedis = new Jedis(jedisSocketFactory, clientConfig); //次要的耗时操作 jedis.connect(); //返回包装对象 return new DefaultPooledObject<>(jedis); } catch (JedisException je) { if (jedis != null) { try { jedis.quit(); } catch (RuntimeException e) { logger.warn("Error while QUIT", e); } try { jedis.close(); } catch (RuntimeException e) { logger.warn("Error while close", e); } } throw je; }}咱们再来介绍一下对象的生成过程,如下图,对象在进行获取时,将首先尝试从对象池里拿出一个,如果对象池中没有闲暇的对象,就应用工厂类提供的办法,生成一个新的。 ...

September 1, 2023 · 3 min · jiezi

关于java:Tomcat的ClassLoader打破双亲委派源码解读

java加载类的时候须要应用类加载器,开发人员能够定制类的加载器,比方tomcat就扩大了本人的类加载器。这篇文章联合代码钻研一下jdk类的加载器和tomcat的类加载 jdk类的加载先上图温习一下 来看一下jdk的ClassLoader的代码 protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 本类加载器从缓存外面拿取曾经加载过的ClassLoader Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { // 父类为BootStrapClassLoader的classLoader 的parent变量为空 if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } .......... }留神看一下外围代码,实际上parent只有不为空就由parent来加载,因而当类未加载的时候,总是由下级来优先加载。 ...

August 31, 2023 · 2 min · jiezi

关于java:Java获取IP归属地

前言最近网站有个新需要,获取用户ip所在归属地,于是在网上搜寻了好多材料并胜利实现,其中遇到了不长坑以及胜利解决,现记录下来分享给大家。 筹备获取ip归属地有第三方的也有Java版本的实现,大家能够依据本人理论状况来实现。1、第三方API查问实现(第三方实现前提是要晓得具体的IP)。2、Java实现(本文就是应用Java来实现的)。 Java实现我应用的是ip2region来实现的,这里留神一下,ip2region老版本是应用.db库,而新版本应用的是.xdb库,具体区别这里有个文章能够看看。 1、下载.xdb数据库,并保留到/src/resources目录下 2、引入ip2region包依赖 <dependency> <groupId>org.lionsoul</groupId> <artifactId>ip2region</artifactId> <version>2.7.0</version></dependency>3、获取ip地址 这里咱们应用X-Forwarded-For来获取客户端的ip,如下所示: IpUtils.java public static String getIpAddr(ServerHttpRequest request){ String ipAddress = null; try { List<String> xForwardedForHeader = request.getHeaders().get("X-Forwarded-For"); log.info("----------- xForwardedForHeader={}", xForwardedForHeader); if (xForwardedForHeader != null && !xForwardedForHeader.isEmpty()) { ipAddress = xForwardedForHeader.get(0); if(ipAddress.indexOf(",") != -1) { ipAddress = ipAddress.split(",")[0]; } } if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { List<String> proxyClientIPHeader = request.getHeaders().get("Proxy-Client-IP"); ipAddress = (proxyClientIPHeader != null && !proxyClientIPHeader.isEmpty()) ? proxyClientIPHeader.get(0) : null; } if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { List<String> wlProxyClientIPHeader = request.getHeaders().get("WL-Proxy-Client-IP"); ipAddress = (wlProxyClientIPHeader != null && !wlProxyClientIPHeader.isEmpty()) ? wlProxyClientIPHeader.get(0) : null; } if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { List<String> httpClientIPHeader = request.getHeaders().get("HTTP_CLIENT_IP"); ipAddress = (httpClientIPHeader != null && !httpClientIPHeader.isEmpty()) ? httpClientIPHeader.get(0) : null; } if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddress().getAddress().getHostAddress(); } }catch (Exception e) { log.error("IPUtils ERROR ",e); } return ipAddress; }4、解析ip归属地 ...

August 31, 2023 · 2 min · jiezi

关于java:再见了-Shiro

1、前言作为一名后盾开发人员,权限这个名词应该算是特地相熟的了。就算是java里的类也有 public、private 等“权限”之分。之前我的项目里始终应用shiro作为权限治理的框架。说实话,shiro确实挺弱小的,然而它也有很多不好的中央。shiro默认的登录地址还是login.jsp,前后端拆散模式应用shiro还要重写好多类;手机端存储用户信息、放弃登录状态等等,对shiro来说也是一个难题。 在分布式我的项目里,比方电商我的项目,其实不太须要明确的权限划分,说白了,我认为没必要做太麻烦的权限治理,所有从简。何况shiro对于springCloud等各种分布式框架来说,几乎就是“劫难”。每个子系统里都要写点shiro的货色,缓缓的,越来越恶心。zuul网关就在这里大显神通了,管制用户的登录,鉴定用户的权限等等。zuul网关管制用户登录,鉴权当前再详说。以上高见。 而后最近我发现了另一个权限框架jcasbin,尽管网上还没有很多对于博客,然而我看了一会就能够应用了。 github地址:https://github.com/casbin/jcasbin2、筹备Spring Boot 根底就不介绍了,举荐看这个实战我的项目: https://github.com/javastacks/spring-boot-best-practice1、mavan仓库引入 <dependency> <groupId>org.casbin</groupId> <artifactId>jcasbin</artifactId> <version>1.1.0</version></dependency><dependency> <groupId>org.casbin</groupId> <artifactId>jdbc-adapter</artifactId> <version>1.1.0</version></dependency>2、配置文件 jcasbin把用户的角色、权限信息(拜访门路)搁置在配置文件里,而后通过输出流读取配置文件。次要有两个配置文件:model.conf 和 policy.csv。简略的应用GitHub里都讲了,在此就不再赘述了。 其实也能够读取数据库的角色权限配置。所以咱们能够把对于数据库的信息提取进去,能够进行动静设置。 @Configuration@ConfigurationProperties(prefix = org.jcasbin)public class EnforcerConfigProperties { private String url; private String driverClassName; private String username; private String password; private String modelPath; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getDriverClassName() { return driverClassName; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getModelPath() { return modelPath; } public void setModelPath(String modelPath) { this.modelPath = modelPath; } @Override public String toString() { return EnforcerConfigProperties [url= + url + , driverClassName= + driverClassName + , username= + username + , password= + password + , modelPath= + modelPath + ]; } }这样咱们就能够在application.properties里进行相干配置了。model.conf是固定的文件,之间复制过去放在新建的和src同级的文件夹下即可。policy.csv的内容是能够从数据库读取的。 ...

August 31, 2023 · 3 min · jiezi

关于java:FactoryBean-和它的兄弟SmartFactoryBean

之前松哥写过一篇文章,跟小伙伴们介绍了咱们在面试中十分常见的一道面试题: Spring 中 BeanFactory 和 FactoryBean 有何区别?在这篇文章中,松哥也和各位小伙伴演示了了 FactoryBean 的一些具体用法,然而对于 FactoryBean 的一些具体实际,这篇文章中没有讲,那么明天我就来和大家聊一聊这个话题,顺便再来说说 FactoryBean 的兄弟 SmartFactoryBean。 1. 应用差异FactoryBean 的用法我就不再反复了,这里来看下 SmartFactoryBean。 FactoryBean 有很多实现类,然而继承自 FactoryBean 的接口却只有 SmartFactoryBean 一个。 SmartFactoryBean 接口的定义如下: public interface SmartFactoryBean<T> extends FactoryBean<T> { default boolean isPrototype() { return false; } default boolean isEagerInit() { return false; }}能够看到,SmartFactoryBean 就是在 FactoryBean 的根底之上多了两个办法: isPrototype:这个办法就是返回以后 Bean 是否是多实例。初看这个办法,有的小伙伴可能会感觉到惊讶,因为在 FactoryBean 中实际上有一个跟它性能相似的办法叫做 isSingleton,isSingleton 的意思就是说这个 Bean 是否是单例的,那么为什么当初还多了一个 isPrototype 办法呢?在后面的视频中松哥和大家讲过,Spring 中 Bean 的 scope 一共有六种,singleton 和 prototype 只是其中的两种,所以,isSingleton 为 true 就示意是单例,然而为 false 并不能示意就是 prototype,同理,isPrototype 为 true 就示意是多实例,然而 isPrototype 为 false 并不能示意就是 singleton,因而,这两个办法是不抵触的。isEagerInit:这个办法就好了解了,办法名示意是否要提前初始化 Bean。当咱们应用 FactoryBean 的时候,默认状况下,Spring 在初始化 Bean 的时候,初始化的是工厂 Bean,例如咱们有一个 UserFactoryBean,那么默认状况下,Spring 容器初始化的是 UserFactoryBean,而 UserFactoryBean 中 getObject 办法真正要返回的 User 则在第一次应用的时候,才会被初始化,人不知;鬼不觉中,指标 Bean 的初始化就被提早了。如果不应用 SmartFactoryBean 的话,那咱们得通过 Bean 的提前注入等形式去实现 Bean 的提前初始化,如果应用 SmartFactoryBean 的话,那么就能够通过配置 isEagerInit 办法返回 true 来实现目标 Bean 提前初始化了。对于第二个办法 isEagerInit,我举个例子给大家演示一下。 ...

August 31, 2023 · 6 min · jiezi

关于java:java堆栈之栈

背景:以前拿着本人的简历去面试的时候, 被问过堆栈的问题, 就查了下材料, 只知其一;不知其二,背了一下. 当初作为一面面试官, 上头安顿面他人,并且领导说二面问到了堆栈相干的,于是就在昨天夜里,月黑风高,灵机一动, 拆解了一下 栈一些系统的知识点:办法栈,线程栈,后进先出,StackOverFlow栈溢出拆解 后进先出,网上查了栈这个汉字的本意, 最最原始的意思是"现代用竹木条横排编成车箱的轻便车子",作为黄淮地区农村人,大略就是相似"平车"一样的货色了.简略了解就是 那块平板就是栈,加上轮子就是车.平板大略是 两根竹子,每根都是一头绑住,而后劈开直径,拿竹片塞到劈开的缝隙,塞到差不多长度后就再略微绑一下. 那么要取其中的竹片,只能从 "略微绑一下"的这头一个一个取,也就是后进先出了.牵强了点,就酱.拆解 办法栈,线程栈, 依照下面的解释, 办法栈就是一片竹片,外面放着办法用到的内存,办法用到的内存根本就是根本数据的值 + 对象援用的地址.所以才不须要多大空间.一个个办法的调用,就让调用链有了深度,就像 一个个竹片塞到竹缝隙里,所以, 就能了解到 线程栈和办法栈是一对多的关系.拆解StackOverFlow,首先内存是有大小限度的,堆内存也好占内存也罢,操作系统给jvm过程一个内存大小,jvm给线程栈设置一个最大的内存大小,栈内存不够就有了StackOverFlow,也就是缝隙塞满了竹片,下一个竹片就像给水杯倒水一样"溢出了".再拆解StackOverFlow, 依据5,根本的概念理解了.那么,是什么导致栈溢出呢, 查资料会发现,递归深度过深灰导致栈溢出.那么整体的逻辑就是, 某个线程执行到递归时,第一次执行, 把以后执行的递归办法里的变量做一个快照,放到一个栈帧(竹片)里,压入栈,而后再次调用该办法(递归了开始),又生成一个栈帧,再递归,就把上一个栈帧压入栈,而后生成一个新的栈帧.循环上来,当最初一次调用该办法,并返回后,该办法对应的栈帧就从 栈顶 去除并开释.而后顺次开释前面的栈帧.那么,如果递归次数过多,就会导致超过配置的线程栈内存大小,就会StackOverFlow了.思考StackOverFlow,大学时,做过一个题目,大略是已知入栈的程序是12345,下列哪个不是可能得出栈程序.这个题目的精华就是办法栈帧 在 线程的栈上的进出规定了.比方先入123,此时能够取出3,也能够再取出2和1,然而不能间接取出2.而12345这些数字,就是所谓的"栈帧"了,也是办法栈.就这?就这.有的文章说,办法要小,也就是代码行数少,一个大办法,最好是一个在这个办法管制整体流程,而后用小办法做各个细节逻辑.也就是大工作拆成小工作.之前始终不了解为啥,有的人说是为了可读性,但我感觉不全是,对熟悉业务逻辑的人来说,可读性更好了,因为你晓得小办法里干了啥.但对不熟悉业务的人来说,比方交接不谨严的团队,相熟代码就是在办法中跳来跳去,还不如一个大办法可读性好.但如果从栈内存优化方面来思考,小办法就是牵强附会的存在了.假如一个大办法占用1m内存,假如设置的占内存是900k,那么间接运行这个大办法会栈溢出.把大办法拆小,就能拿立即回收掉完结的小办法的栈内存,而后反复利用,就不会栈溢出.

August 31, 2023 · 1 min · jiezi