关于java:自定义拦截器

1、创立用户操作标识枚举 @Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface UserOperateLog { String value(); String valueEn();}2、创立枚举拦截器,用来记录用户操作行为 @Component@Aspectpublic class UserOperateLogAspect { @Around("@annotation(UserOperateLog)") @SneakyThrows public Object aroundAspect(ProceedingJoinPoint joinPoint){ //拼接用户操作日志模型 //理论申请 Object o =joinPoint.proceed(); //填充模型 //异步写入数据库 return o; }}3、测试案例 public class TestModel { @UserOperateLog(value = "测试操作",valueEn="test") public void test1() { } public String test2() { return ""; }}4、数据库字段 1、id2、用户操作形容(UserOperateLog.value)3、申请url4、申请参数5、返回后果6、耗时7、用户id8、用户名9、创立工夫10、申请后果是否失败11、异样信息12、英文形容(UserOperateLog.valueEn)

March 27, 2023 · 1 min · jiezi

关于java:非常小的一个东西Spring依赖注入Bean类型的8种情况

明天来讲一个可能看似没有用然而理论又有点用的一个小东西,那就是@Autowired反对注入哪些Bean的类型。 为啥要讲这个呢? 故事说起来可能就比拟长了。 不过长话能够短说,仅仅就是忽然想起来之前有一个妹子问过我这个问题! 1、一般对象这没什么好说的,大家都这么用的,比方须要用到UserService,间接@Autowired就能够了。 @Autowiredprivate UserService userService;2、Collection及其子接口除了反对注入一个繁多的对象之外,@Autowired还反对注入一个Collection对象。 比如说,当初有个音讯告诉的接口MessageNotifier。 这种接口个别都会有不同的实现,比如说通过邮件告诉,或者app,短信等等,所以就有多种实现,此时如果须要注入MessageNotifier,就能够应用注入Collection的形式,比方 @Autowiredprivate List<MessageNotifier> messageNotifiers;不过这种形式有个规定,那就是注入的类型必须是Collection及其子接口,如果你间接注入一个ArrayList,那么此时是不反对的。 3、数组同理,@Autowired可实现了注入一个数组的性能。 @Autowiredprivate MessageNotifier[] messageNotifiers;代码如下: 4、Map同样的,@Autowired还能够注入一个Map。 @Autowiredprivate Map<String, MessageNotifier> messageNotifierMap;此时注入的map,key的类型就是bean的名称,这种形式能够配合策略模式应用。 不过,这种形式只反对注入的是Map接口,不反对子类型接口,代码如下。 5、@Lazy当一个注入的字段加了@Lazy注解之后,那么此时就代表这个字段是提早注入。 @Autowired@Lazyprivate MessageNotifier messageNotifier;提早注入并不是不注入,而是注入指标对象类型的代理对象,真正的指标是当须要用到的时候在创立。 如图所示,当注入的MessageNotifier时加了@Lazy注解,那么此时注入的其实是MessageNotifier的代理对象,而真正的MessageNotifier对象并没有创立,图中代理对象我称为MessageNotifierProxy。 因为注入的是对象是代理对象MessageNotifierProxy,那么真正被应用的就是MessageNotifierProxy,一旦调用了MessageNotifierProxy的办法,此时MessageNotifierProxy会去Spring容器中查找真正的MessageNotifier对象,而后再调用MessageNotifier对象的办法。 代码如下: 这就是@Lazy提早注入的原理。并不是不注入,而是注入一个代理对象,能够了解为一个占位符,一个空壳子,先占着地位,等用到这个壳子的时候,这个壳子会去查找到真正的对象,调用真正对象的办法。 @Lazy的一个应用场景就是用来解决Spring无奈解决的循环依赖场景,比方应用了@Async注解的循环依赖的场景 6、OptionalOptional是JDK1.8提供的一个api,能够优雅的解决判空的问题。 @Autowired也反对了注入Optional类型。 @Autowiredprivate Optional<MessageNotifier> messageNotifier;代码如下: 注入Optional这种形式能够解决注入的对象不存在的导致异样问题,也就是平安注入。 比如说,MessageNotifier这个对象Spring容器中并没有,如果间接注入,此时会抛NoSuchBeanDefinitionException异样 而间接通过注入Optional的形式就能够解决这个问题。 除了通过Optional的形式之外,也能够间接把@Autowired的required的属性设置为false来解决注入对象不存在的问题。 那Optional存在的作用是啥? 其实Optional的作用仅仅是不必写为空的判断,这也是Optional这个类的作用作用,除了这个,跟间接@Autowired对象并没有其它区别。 注入Optional这种形式其实用的不多,在我的映像中,我在源码中简直没有看见这种注入形式。 7、ObjectFactory和ObjectProviderObjectFactory和ObjectProvider是Spring提供的两接口 ObjectProvider继承了ObjectFactory @Autowired也能够间接注入这两个接口。 @Autowiredprivate ObjectFactory<MessageNotifier> messageNotifierObjectFactory;@Autowiredprivate ObjectProvider<MessageNotifier> messageNotifierObjectProvider;代码如下: 从这段代码也能够看出,最终注入的其实是DependencyObjectProvider实现。 ObjectFactory也是用来做提早注入的操作,跟@Lazy作用差不多,然而实现原理不一样。 用下面的例子来说,注入ObjectFactory的时候并有创立MessageNotifier对象。 当须要应用MessageNotifier的时候须要通过ObjectFactory的getObject办法获取,此时才会真正创立MessageNotifier对象。 MessageNotifier messageNotifier = messageNotifierObjectFactory.getObject();所以@Async注解导致的循环依赖异样不仅能够通过@Lazy注解解决,也能够通过注入ObjectFactory的形式解决。 ...

March 27, 2023 · 1 min · jiezi

关于java:面试突击MVCC-和间隙锁有什么区别

MVCC 和间隙锁是两种齐全不同的机制,但它们的目标都是雷同的,都是用来保障数据库并发拜访的,咱们先来看二者的定义。 MVCC 定义MVCC 是多版本并发管制(Multi-Version Concurrency Control)的缩写,是一种并发管制的办法。 在 MVCC 中,每个读操作会看到一个固定版本的数据库记录,即便在并发环境中,也不会呈现读取到了其余事务还未提交的数据的状况。 MVCC 通过保留数据在某个工夫点的快照来实现这一点。在读取数据时,只会读取在该工夫点之前提交的数据。在写入数据时,会为每个写入操作创立一个新版本的数据,而不是间接笼罩原有的数据。这样,读操作就能够读取旧版本的数据,而写操作则能够写入新版本的数据,从而实现了并发管制。 在 MySQL 中,InnoDB 存储引擎就是应用 MVCC 来实现并发管制的。 间隙锁定义间隙锁是一种锁定索引范畴而非理论数据的锁,它能够锁定一个范畴,避免其余事务在这个范畴内插入数据,从而保障了范畴内的数据的唯一性。在 MySQL 中,InnoDB 存储引擎反对间隙锁。当应用 SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE 语句时,InnoDB 存储引擎会主动应用间隙锁来锁定索引范畴。 如果一个事务在一个间隙上持有了锁,那么其余事务就不能在这个间隙上插入数据,然而能够在这个间隙之前或之后的地位插入数据。 为什么要有 MVCC?既然曾经有锁能够避免并发拜访了,那为什么还须要 MVCC 呢? MVCC 的诞生次要是出于性能的思考,因为 MVCC 中没有用到锁,它是通过多版本并发管制的伎俩来实现数据库并发拜访的,这样相比于加锁性能就会好很多。 MVCC 实现原理MVCC 居然这么强,那它是怎么实现的呢?简略来说 MVCC 是通过以下 3 大组件实现的: 暗藏字段:每个执行的 SQL 命令都有几个暗藏的字段,其中有一个事务 ID 字段,很重要。undo log(回滚日志):外面记录了 SQL 命令执行的历史数据。Read View(读视图):蕴含快照读(一个快照,保留了数据库某个时刻的数据)和一些重要的属性。它的实现原理简略来说,是通过 SQL 中暗藏的字段事务 ID(本人的版本号)和 Read View 中的属性版本号进行比照,比照之后决定应用 Read View 中的快照或 undo log 中的历史数据(比照的规定是 MVCC 机制的规定,本文不展开讨论),最初再将合乎的数据返回。 ...

March 26, 2023 · 1 min · jiezi

关于java:面试篇Java面试中xx与xx之间有什么区别汇总详解

前言/背景据说往年面试压力特地大,不知真假~ 不论面试压力大不大,温习好,该把握的技术点都熟练掌握,珍惜每一次面试机会 明天给大家分享一篇根底的面试题,不要输在这些根底且又常见的问题上 材料总结/刷题指南 这里先自荐一个面试刷题的小程序吧,大家能够收费去刷题,心愿能够帮忙到你。 大家能够扫码返回,也能够微信搜寻【Java面试 | 笑小枫】小程序。继续更新中,后续会上一些资源、简历模板、面试分享内容 面试流程 老面:&和&&有什么区别?笑小枫:&可用于位运算,当左右两边的条件不是布尔型,而是数字时,它会进行位运算; 当&运算符两侧是是布尔型,且表达式的后果均为真时,整个运算后果才为真;当&&操作符第一个表达式为 false时,后果为 false,并且不再计算第二个表达式,具备短路性能。 老面:||、&&、! 有什么区别?笑小枫:‘||’是 逻辑或的意思,就是或者,有一个对的就是对的。a||b,示意a表达式或b表达式有一个返回true,则a||b整个表达式返回true。 例: 1==1 || 1==1 //返回true1==1 || 1==2 //返回true1==2 || 1==2 //返回false‘&&’是逻辑且的意思,就是并且,有一个是错的就是错的。a&&b,示意a表达式或b表达式有一个返回false ,则a&&b整个表达式返回false。如果a表达式为false,则间接返回false,不会再判断b表达式。 例: 1==1 && 1==1 //返回true1==1 && 1==2 //返回false1==2 && 1==2 //返回false‘!’是逻辑非的意思,就是反转,原来是的对的,加上!后,就变成错的,原来是错的,加上!后,就变成了对的。 !true 返回false !false 返回true 例: ! (1==1) //返回false! (1==2) //返回true老面:== 与 equals有什么区别?笑小枫:能够从性能、定义和运行速度上来说: 性能不同== 既能够比拟根本类型也能够比拟援用类型;对于根本类型,== 比拟的是值;对于援用类型,== 比拟的是地址;equals不能用于根本类型的比拟;如果没有重写equals,equals就相当于==;如果重写了equals办法,equals比拟的是对象的内容。 留神:重写equals办法的同时,也要重写hashCode,不然同一个对象比拟,可能会呈现hashCode不同,equals比拟的时候先判断hashCode是否雷同,而后再比拟值,如果hashCode不同,则间接认为这两个对象不同。 定义不同equals在JAVA中是一个办法;== 在JAVA中只是一个运算合乎。运行速度不同== 比equals运行速度快,因为 == 只是比拟援用。老面:String、StringBuffer 和 StringBuilder 有什么区别?笑小枫:能够从可变性、线程安全性、性能三方面来说: 可变性String 类中应用 final 关键字字符数组保留字符串,所以 String 对象是不可变的。而 StringBuilder 与StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是应用字符数组保留字符串 char[]value 然而没有用 final 关键字润饰,所以这两种对象都是可变的。 ...

March 26, 2023 · 1 min · jiezi

关于java:学习Linux命令的正确姿势

大家好,我是良许。 大家应该留神到了,最近我的公众号文章开端都挂着本人录制的《Linux命令从小白到大神》课程。 这个课程我从开始录制到制作实现,足足花了一个半月。如果加上后期的材料收集与教案筹备,必定有将近三个月。 首先跟大家讲讲我为什么要开发这门课程。 咱们晓得,Linux 的精华就是命令,只有你跟 Linux 打交道,你必定须要敲很多很多的命令。 所以,想学好 Linux ,第一步必定要先学好命令。 当年我刚开始学 Linux 的时候,那一串串简单的命令总是让我十分头疼,所以我迫切想系统学一遍命令。然而我找来找去,在网络上就是没有找到零碎介绍命令的课程。 而且,就算是放到当初,网络上仍然没有这类型的课程,顶多就是介绍一些罕用的命令,十分十分不零碎,而且基本上每个命令都只是一带而过。 所以,我感觉十分有必要去开发一套这样的课程,来帮忙想学或者正在学 Linux 命令的同学。 学习命令百度一下就好? 有些人可能会说,当初互联网这么发达,碰到要用什么命令,间接某度一搜不就什么都有了吗? 我在直播的时候,也常常有小伙伴提出这样的疑难: 之前我也这么感觉。 然而,我在学命令的过程中,搜寻进去的文字版的教程,要么十分不零碎,要么就是排版很乱,影响学习,甚至还有很多的谬误。 而且,那些文字版的教程,基本上看不到命令执行后果,须要咱们本人入手敲一遍,还不肯定是咱们想要的成果,减少了咱们学习及试错的老本。 另外,你想查某个命令,前提是你须要晓得有这个命令的存在,否则怎么查呢? 比方校验文件的 md5 值有个命令是 md5sum ,我之前始终不晓得这个命令,而是本人入手写了个程序来校验 md5 值 。 前面我才晓得有 md5sum 这个命令,要是早点晓得我就不会节约这个工夫了。 再比方,如果要进行文本处理的时候,你除了晓得 grep 、sed、awk 这三剑客外,还有什么命令能够应用的? 如果你没有系统学过一遍 Linux 命令,你兴许不晓得还有 cut、sort、paste、split、uniq、join、tr 等等命令。 这就像你要做一张桌子,你要晓得有锯子、刨刀、电钻、磨砂机等等工具,而后你才能够去百度它们的用法,再去应用它们。 否则你就只能傻愣在那边,心里有个需要,但不晓得用什么工具实现,这些工具也不会应用。 基于此,我就特地想做一个Linux命令课程,帮忙跟我有一样困扰的小伙伴。 接下来,我跟大家介绍一下咱们这套课程有哪些特色。 首先,咱们全程应用思维导图,没有任何 PPT,所以咱们的课程跟那些只会念 PPT 的课程不一样,是一个实操型的课程。 并且应用思维导图会更加直观,学习起来成果更好。 其次,我总结演绎了 150 个高频应用的命令,蕴含了 40 个打星标的超高频应用命令,以及110 个次高频命令,并且依照类型进行分类,学习起来会更加零碎。 否则一个个命令孤零零拿进去学习,很容易遗记,也不晓得它跟其它命令有什么关联。 并且呢,除非两个命令关联性太强了,否则对于大多数命令,一节课我只讲一个命令,这样也不便大家检索学习,哪个命令不懂就学哪个。 而且,每个命令我都尽量做到不波及其它命令,这样学习起来就不会受到没学过的命令的阻挡了。 而后,每个命令我都尽量收集了足够多的案例,而不是网络上那些文字版教程那样,一带而过。我尽量把每个命令的最罕用的选项都讲透,让大家一次就把握这个命令。 而且,在解说的过程当中,我全程手敲命令,并且一边敲一边跟大家讲这条命令为什么要这么写,每局部代表了什么意思,同时也间接让你们看到命令运行的成果,学习起来效率更高。 最初,这150个命令,均匀下来每个命令解说4分钟,总时长超过10小时,甚至都能够媲美那些上千元的大课了。 ...

March 26, 2023 · 1 min · jiezi

关于java:面向接口编程Service-Provider-Interface是什么Interface

什么是SPIService provider interface (SPI) is an API intended to be implemented or extended by a third party. It can be used to enable framework extension and replaceable components.直译过去SPI是一个能被第三方继承或者实现的API,个别用于框架扩张或者可变组件。可能这个了解起来还是比拟难,再找一个图来看看看起来如同比较简单一点了,然而对于我在刚接触SPI的时候还是比拟难懂,所以我画了一个我感觉比拟适宜老手同学的图能够看到我用3个色彩来标注3个解决接口方,惯例状况下,这3方个别是隶属于3个组织,或者1个组织的3个部门,转化成具体的代码就是这3方个别是属于3个工程的。SPI实际有了以上的基础知识,接下来再用一个例子来加深大家的理解,大体的步骤如下:定义一个Interface标准有两个工程实现这个Interface再定义一个应用Interface的工程具体的工程目录如下:接口定义方整个模块啥也不干,单纯地定义一个接口接口实现方接口实现方如果想实现下面定义的接口,第一步首先必定是在pom文件中引入java-api-service 这个模块接着也是啥也不干,单纯地实现定义的接口即可,上面是接口实现方1的代码为了大家看得更分明一点,我特意在一个接口实现方中定义了两个具体实现类XxlServiceLoaderXxlOtherServiceLoader接口实现方2的代码也是相似的CuteyServiceLoader留神:这两个接口实现方是附属不同module,然而独特依赖了接口定义方留神:这两个接口实现方是附属不同module,然而独特依赖了接口定义方留神:这两个接口实现方是附属不同module,然而独特依赖了接口定义方然而实现了接口还不行,要想实现SPI还得有一个公共的约定配置文件,在META-INF目录下新建一个services目录,有些工程创立的时候可能没有META-INF,那就得在resource目录下先新建META-INF。接着在services目录中新增一个文本文件,文件名为接口定义的全限定类名,比方下面的例子实现的接口是InterfaceService ,那文本文件名称就必须是com.cutey.none.spi.service.InterfaceService 。留神,这里的文本文件并不是指文件格式txt,而是单纯文本文件。文本文件的内容为具体实现类的全限定类名,针对下面的例子,不同实现的文本文件内容如下:接口实现方1com.cutey.none.spi.serviceloader.XxlOtherServiceLoadercom.cutey.none.spi.serviceloader.XxlServiceLoader接口实现方2com.cutey.none.spi.serviceloader.CuteyServiceLoader理论文件目录及内容如图接口应用方有了以上接口定义和接口实现,接下来看看应用方是怎么应用的,首先应用方要应用这个接口,那必定也是要依赖接口定义方,接着要应用具体的实现,那同样也须要依赖接口实现方。整个工程是比较简单的,外面只有一个相似Main的办法App类外面的内容如下,类外面的读取SPI是用java.util.ServiceLoader 看下输入是什么能够看到在应用方中没有写任何接口实现的代码,仅仅是导入了2个依赖jar,就能应用依赖jar包中的具体实现,感兴趣的同学能够试试如果只依赖上述的独自1个jar会不会是你想的预期。工程中的SPI下面用一个简略的例子帮大家疾速体验了下什么是SPI,当初再来简略看看身边有哪些应用SPI的例子。由wikipedia能够看到有这些应用了SPI,接下来咱们挑耳熟能详的数据库和spring.factories来看看。数据库略微相熟一点的同学都晓得以前是应用Class.forName("com.mysql.cj.jdbc.Driver"); 去加载驱动类的。对于mysql而言mysql8更改了驱动类的包门路,而后引入了mysql8后发现代码跑不通了还专门去网上搜为什么。所以这种形式必定是有弊病的,浅举3个须要手动编写驱动类地址,不论是硬编码还是配置文件的模式,都须要咱们在应用的时候编写驱动类全限定类名更改驱动类不不便,须要找到定义的中央,而后再去替换当类名发生变化后须要应用方去适配,如果存在信息差那会导致程序运行不了而在有了spi后,曾经不必以上形式去加载驱动类了,而是应用DriverManager.getConnection() 去连贯数据库,能够看到,连驱动类是啥都曾经不关注了。当然,无论哪种模式必定都要援用数据库的jar包,这是大前提。因为这里不是讲SPI的原理,就不深究DriverManager外面干了啥,这里就贴一张图表明确实用到了spi,感兴趣的同学能够自行钻研源码。为了让各位同学更简略直白的看到这个成果,咱新建一个工程,而后pom文件中引入mysql和oracle的依赖,编写个main办法去加载,看能不能取到两个数据库驱动类的全限定类名。工程目录如下好不客气地说是啥都没有,而后减少Main类中的办法接着打断点进行代码调试,看下providerNames是不是真的有咱们引入的依赖jar包了。具体怎么做到的呢,在最开始spi实际咱们本人实现的时候就晓得是在src/main/resources/META-INF/services 目录下有个以接口作为文件名的文本文件,那当初就去mysql和oracle中的jar包中验证下。能够看到的确如此,看到这里就能领会到一个最最最显著的益处,那就是哪怕当前mysql的接口实现类产生了变动,咱们也不必关注,因为在它自身的jar包中就提供了驱动实现类的全限定类名。spring.factories写在后面,spring.factories是SpringBoot的个性,而非是Spring,而后是用于主动拆卸(目前我理解到的是只用于这个)。所谓主动拆卸,说得再简略,那就是在不侵入式批改代码的状况下可能加载其余jar包内的bean。上面演示代码的整体概要:有两个模块,java-spi-springboot-provider 和 java-spi-springboot前者蕴含Student的bean,后着蕴含Teacher的beanjava-spi-springboot要应用java-spi-springboot-provider 里的bean两个bean所在的包门路不一样,Student的全限定类名为com.xxl.cutey.none.javaspispringbootprovider.Student ,Teacher的全限定类名为com.cutey.none.xxl.javaspispringboot.Teacher java-spi-springboot依赖java-spi-springboot-provider整体的工程目录图如下各位小伙伴先别想着spring.factories,就失常状况下,咱们是怎么应用别的jar包外面的bean的。也就是在非provider中应用Student这个bean,那首先必是要先加@Component 注解。java-spi-springboot-provider新建一个Student类,而后在主启动类中读取这个bean主启动类留神,在主启动类和bean不在同一个包门路下的时候,是须要用scanBasePackage扫包能力把bean注入到IOC容器中。接下来看下输入,没问题。java-spi-springboot新建一个Teacher和主启动类都和下面一样就不再赘述,当初是想用下面申明的bean,那就只有一个办法,批改scanBasePackages,要么是扫两个Bean的公共包,还记得吗,Student和Teacher我特意把全限定类名改得不懂;要么是具体写完这两个Bean的全限定类名。看下输入,留神:如果Student的包名没写对,那必定是获取不到Student的bean的,因为它是在别的jar包上面。 问题来了,如果我想要再引别的组织的包呢,要晓得在实在开发中,不同部门,不同组织,甚至不同公司之间互相援用切实是太失常了,难道每次援用一个都得这么加吗,这就引出了spring.factories。咱们革新的是java-spi-springboot-provider接下来咱们再批改下java-spi-springboot中的包,把扫描的student的包去掉咱们能够神奇的发现,还是能读取进去bean让咱们浅浅看Spring用是不是真的用到了SPI诶,如同没看到跟数据库一样用到了jdk中的ServiceLoader呀,是不是骗你们了捏,其实不是,其实SpringFactoriesLoader就是类是jdk中的ServiceLoader。说白了,spring应用的SPI的思维,而SPI精确来说也不是一个接口,而是面向接口编程的其中一种思维,是接口应用方和接口定义方约定一种面向编程的思维。参考文献Service provider interface - Wikipedia10分钟让你彻底明确Java SPI,附实例代码演示#安员外很有码哔哩哔哩bilibiliJava SPI (Service Provider Interface) 机制详解 - 腾讯云开发者社区-腾讯云 (tencent.com)

March 26, 2023 · 1 min · jiezi

关于java:Java20的新特性

Java语言个性系列Java5的新个性Java6的新个性Java7的新个性Java8的新个性Java9的新个性Java10的新个性Java11的新个性Java12的新个性Java13的新个性Java14的新个性Java15的新个性Java16的新个性Java17的新个性Java18的新个性Java19的新个性Java20的新个性Java21的新个性序本文次要讲述一下Java20的新个性 版本号java -versionopenjdk version "20" 2023-03-21OpenJDK Runtime Environment (build 20+36-2344)OpenJDK 64-Bit Server VM (build 20+36-2344, mixed mode, sharing)从version信息能够看出是build 20+36个性列表JEP 429: Scoped Values (Incubator)ScopedValue是一种相似ThreadLocal的线程内/父子线程传递变量的更优计划。ThreadLocal提供了一种无需在办法参数上传递通用变量的办法,InheritableThreadLocal使得子线程能够拷贝继承父线程的变量。然而ThreadLocal提供了set办法,变量是可变的,另外remove办法很容易被疏忽,导致在线程池场景下很容易造成内存泄露。ScopedValue则提供了一种不可变、不拷贝的计划,即不提供set办法,子线程不须要拷贝就能够拜访父线程的变量。具体应用如下: class Server { public final static ScopedValue<User> LOGGED_IN_USER = ScopedValue.newInstance(); private void serve(Request request) { // ... User loggedInUser = authenticateUser(request); ScopedValue.where(LOGGED_IN_USER, loggedInUser) .run(() -> restAdapter.processRequest(request)); // ... }}通过ScopedValue.where能够绑定ScopedValue的值,而后在run办法里能够应用,办法执行结束自行开释,能够被垃圾收集器回收JEP 432: Record Patterns (Second Preview)JDK19的JEP 405: Record Patterns (Preview)将Record的模式匹配作为第一次previewJDK20则作为第二次preview针对嵌套record的推断,能够这样 record Point(int x, int y) {}enum Color { RED, GREEN, BLUE }record ColoredPoint(Point p, Color c) {}record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {}static void printColorOfUpperLeftPoint(Rectangle r) { if (r instanceof Rectangle(ColoredPoint(Point p, Color c), ColoredPoint lr)) { System.out.println(c); }}整体而言,模式匹配有如下几种: ...

March 25, 2023 · 5 min · jiezi

关于java:简历模板极简Markdown程序员简历模板

前言最近在找工作,一份好的简历是敲门砖,所以跟大家分享下简洁明了慷慨MarkDown的简历模板和在线编辑工具 在线工具冷熊 Java工程师简历模板下载点击下载 预览个人信息xxx/男/1993.05本科/xxxx大学-计算机科学与技术学院工作年限:5年工作单位: xxx公司-至今技术博客:https://blog.javadog.netGithub:https://github.com/javadog-netCSDN: https://javadog.blog.csdn.net/掘金: https://juejin.cn/user/2172290706716775微信公众号: JavaDog程序狗冀望职位:Java工程师,前端工程师,全栈工程师以后薪资: 扣除五险一金后11k冀望薪资:税前月薪11k+联系方式手机:xxxxxxxxxxxEmail:xxxxxxxxxxx@aliyun.com / xxx@javadog.net微信号:xxxxxxxxxxx 技能清单后端技术栈:有较好的Java根底,相熟SpringBoot,SpringCloud,springCloud Alibaba等支流技术,Redis内存数据库、RocketMq、dubbo等,相熟JUC多线程后端模板引擎:thymeleaf、volocity前端技术栈:熟练掌握ES5/ES6/、NodeJs、Vue、React、Webpack、gulp其余技术栈: 相熟python+selenium、electron数据库:相熟MySQL、SQL Server、MongoDB等支流数据库前端UI:纯熟应用Element UI、 Ant Design of Vue前端工具:纯熟应用VSCode、 webStorm、HBuilder X、微信开发者工具后端工具:纯熟应用IDEA、Postman、MobaXterm等版本治理:纯熟应用Svn/Git接口文档:VuePress、Markdown、rap2自动化部署工具:Docker+Jenkins云服务器:纯熟应用阿里云ECS服务器、利用部署等,linux命令纯熟工作经验外包-xxx有限公司 ( 2021年10~ 2021年12月 )xx门户网站技术栈SpringBoot、MySql、Redis、MyBatis-Plus、 我的项目形容xxx团体有限公司,公司始创于1993年,次要从事挂锁、智能锁、门锁、车锁等锁具产品研发、设计、生产、销售、服务,计算机软件及网络技术、物联网设施、智能家居软硬件、通讯设备的技术开发、技术服务,此我的项目为xxx门户网站。 责任形容负责代码编写工作,后盾开发+前端开发。 外包-xxx公司 ( 2021年08~ 2021年9月 )xxx衰弱小屋公众号+治理端+医生端技术栈SpringBoot、MySql、Redis、MyBatis、Elasticsxarch、MongoDB、RocketMQ、Vue、Element UI、stomp、websocket 我的项目形容在xx智慧养老计划中,老年人即便足不出户,也能随时获悉身材健康状况。在家中只需应用配置的居家生理检测套装,就能测量血压、血氧、心电、体温等惯例身材参数,而且数据可上传云端并建设档案,线上依据查看后果提供衰弱生存的布局领导等服务。 责任形容负责代码编写工作,后盾开发。次要开发医生端在线聊天模块。 参考网站公众号:xxx 外包-xxx公司 ( 2021年01~ 2021年7月 )企业自研零碎框架技术栈SpringCloud Alibaba、SpringBoot、MySql、Redis、MyBatis-Plus、Elasticsearch、RabbitMQ、Vue、Element UI 我的项目形容次要波及公司外部框架,一站式的对外服务。不便建站及二次开发,集成根本根底模块,如CMS,商城,领取,订单等根底可选模块,用于对外营销及外部麻利开发,并反对Saas服务。 责任形容负责代码编写工作,后盾开发+前端开发。 参考网站xxx 外包-xxx公司 ( 2020年5月~ 2020年12月 )xxxx医疗公众号我的项目技术栈SpringBoot、MySql、Redis、MyBatis-Plus、uni-app 我的项目形容xx我的项目次要是疾病相关公众号,蕴含cms零碎,积分,商品等模块。患者医生等角色,包含疾病的预防及波及病理常识,有助于患者和医生线上交换及病理探讨。 责任形容负责代码编写工作,后盾开发。 参考网站公众号:xxx 外包-xxx公司 ( 2020年1月~ 2020年11月 )xx二期技术栈SpringBoot、MySql、Redis、MyBatis、LayUI 我的项目形容xxx二期是在企业购电商一期的根底上退出店中店的模块降级,对接快捷通领取,用户能够在线上进行局部交易。对接用户核心,产品核心,快捷通,MDM,销售样表等零碎。 责任形容负责代码编写工作,前端后盾开发。 参考网站xxx 外包-xxx公司 ( 2019年9月~ 2019年11月 )xxx公众号技术栈artTemplate 、Gulp打包工具、 Sass ...

March 25, 2023 · 1 min · jiezi

关于java:Redis中的BigKey问题排查与解决思路

本文已收录至Github,举荐浏览 Java随想录微信公众号:Java随想录 摘要Redis是一款性能强劲的内存数据库,然而在应用过程中,咱们可能会遇到Big Key问题,这个问题就是Redis中某个key的value过大,所以Big Key问题实质是Big Value问题,导致Redis的性能降落或者解体。本文将向大家介绍如何排查和解决这个问题。 Big Key问题介绍在Redis中,每个key都有一个对应的value,如果某个key的value过大,就会导致Redis的性能降落或者解体,比玄学更玄学,因为Redis须要将大key全副加载到内存中,这会占用大量的内存空间,会升高Redis的响应速度,这个问题被称为Big Key问题。不要小看这个问题,它可是能让你的Redis霎时变成“乌龟”,因为Redis单线程的个性,操作Big Key的通常比拟耗时,也就意味着阻塞Redis可能性越大,这样会造成客户端阻塞或者引起故障切换,有可能导致“慢查问”。 一般而言,上面这两种状况被称为大 key: String 类型的 key 对应的value超过 10 MB。list、set、hash、zset等汇合类型,汇合元素个数超过 5000个。以上对 Big Key 的判断规范并不是惟一,只是一个大体的规范。在理论业务开发中,对 Big Key的判断是须要依据具体的应用场景做不同的判断。比方操作某个 key 导致申请响应工夫变慢,那么这个 key 就能够断定成 Big Key。在Redis中,大key通常是由以下几种起因导致的: 对象序列化后的大小过大存储大量数据的容器,如set、list等大型数据结构,如bitmap、hyperloglog等如果不及时处理这些大key,它们会逐步耗费Redis服务器的内存资源,最终导致Redis解体。 Big Key问题排查当呈现Redis性能急剧下降的状况时,很可能是因为存在大key导致的。在排除大key问题时,能够思考采取以下几种办法: 应用BIGKEYS命令Redis自带的 BIGKEYS 命令能够查问以后Redis中所有key的信息,对整个数据库中的键值对大小状况进行统计分析,比如说,统计每种数据类型的键值对个数以及均匀大小。此外,这个命令执行后,会输入每种数据类型中最大的 bigkey 的信息,对于 String 类型来说,会输入最大 bigkey 的字节长度,对于汇合类型来说,会输入最大 bigkey 的元素个数 BIGKEYS命令会扫描整个数据库,这个命令自身会阻塞Redis,找出所有的大键,并将其以一个列表的模式返回给客户端。 命令格局如下: $ redis-cli --bigkeys返回示例如下: # Scanning the entire keyspace to find biggest keys as well as# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec# per 100 SCAN commands (not usually needed).[00.00%] Biggest string found so far 'a' with 3 bytes[05.14%] Biggest list found so far 'b' with 100004 items[35.77%] Biggest string found so far 'c' with 6 bytes[73.91%] Biggest hash found so far 'd' with 3 fields-------- summary -------Sampled 506 keys in the keyspace!Total key length in bytes is 3452 (avg len 6.82)Biggest string found 'c' has 6 bytesBiggest list found 'b' has 100004 itemsBiggest hash found 'd' has 3 fields504 strings with 1403 bytes (99.60% of keys, avg size 2.78)1 lists with 100004 items (00.20% of keys, avg size 100004.00)0 sets with 0 members (00.00% of keys, avg size 0.00)1 hashs with 3 fields (00.20% of keys, avg size 3.00)0 zsets with 0 members (00.00% of keys, avg size 0.00)须要留神的是,因为BIGKEYS命令须要扫描整个数据库,所以它可能会对Redis实例造成肯定的累赘。在执行这个命令之前,请确保您的Redis实例有足够的资源来解决它,倡议在从节点执行。 ...

March 24, 2023 · 3 min · jiezi

关于java:chatgpt周刊第三期

一周资讯微软 Bing 在线绘图性能上线,可通过文字描述生成图片内容微软 Bing 在线 AI 绘图性能上线,由 Open AI 的 DALL-E 驱动,可通过文字描述生成图片内容.Bing 绘图目前仅反对英文,应用“形容词 + 名词 + 动词 + 格调”的格局能够生成高质量图片.官网指出,当零碎检测到提醒语可能会生成危害性的图像时,Bing 会阻止该提醒语并对用户进行正告。官网还会明确指出,图像创立器的图像是由 AI 生成,并在每个图像的左下角增加一个 Bing Logo。体验地址:https://cn.bing.com/images/create?FORM=GENILP 百度:文心一言云服务将于 3 月 27 日上线个人用户能够进入文心一言官网参加排队试用。企业用户能够进入百度智能云官网,申请预约文心一言 API 接口调用服务测试。百度智能云行将面向企业客户凋谢文心一言 API 接口调用服务。3 月 16 日起正式凋谢预约,搜寻“百度智能云”进入官网,可申请加入文心一言云服务测试。 斯坦福大学复制出ChatGPT人工智能 训练老本不到600美元斯坦福大学的Alpaca人工智能是一个基于开源LLaMA 7B语言模型的低成本复制品,能够与ChatGPT在许多工作上相媲美。该团队应用ChatGPT生成了大概52000个指令/输入对,用于前期训练LLaMA模型,总成本不到600美元。他们在Github上公布了他们的数据和代码,但没有对模型进行平安微调,因而存在滥用的危险。 李开复发表筹组中文版ChatGPT公司“Project Al 2.0”翻新工场董事长兼CEO李开复在朋友圈发表,正在亲自筹组Project Al 2.0,这是翻新工场塔尖孵化的第7家公司,致力打造Al 2.0全新平台和Al-first生产力利用的全球化公司。李开复在朋友圈写到,“Project Al2.0不仅仅要做中文版ChatGPT”。新公司的资金、算力陆续到位,当初正式开启团队组建,首批广召大模型、多模态、NLP、AI算法工程与钻研、分布式计算/Infrastructure 等方向的顶级人才 OpenAI:ChatGPT等AI聊天技术可能会对美国19%工作岗位产生重大影响OpenAI钻研人员预计,ChatGPT这样的AI聊天机器人有能力写作文、营销计划、编程代码和剖析财务报告,可能会对美国19%的工作岗位产生重大影响。与此同时,美国80%的劳动力可能会看到至多10%的工作工作在某种程度上受到ChatGPT的影响。此外,钻研人员发现,工资较高的工作可能更容易受到由AI驱动的聊天机器人的潜在影响。对于ChatGPT对劳动力的影响,OpenAI首席执行官山姆·奥特曼(Sam Altman)最近抵赖,它可能会“取代”许多现有工作岗位。 英伟达在 GTC 大会上推出了专为 ChatGPT 打造的 H100 NVLINK,提速 10 倍大会上最重磅的公布,就是针对 ChatGPT 打造的 NVIDIA H100 NVLINK。因为算力需要微小,针对 ChatGPT 等 LLM 的推理,英伟达推出了新款 Hopper GPU,装备双 GPU NVLINK 的 PCIE H100,具备 94B 内存。 不仅能使计算速度晋升 40 倍,而且功耗也能够升高 9 倍之多。「咱们正处于 AI 的 iPhone 时刻」,在 GTC 大会上,老黄也是冲动地把这句话反复了三遍。 ...

March 24, 2023 · 2 min · jiezi

关于java:如何通过Java程序提取Word中的文本

提取Word文档中的文本是一种常见的需要,咱们能够间接复制并粘贴保留到指定文件中。但这一办法更为实用于文本内容较少时。除了费时费力地手动保留以外,咱们能够通过编程语言编写代码来一次性提取Word文档中的大量内容。在这里我将介绍如何通过 Java程序来实现这个性能。所用到的产品是Free Spire.Doc for Java。具体操作和代码请参考下文。 程序环境在进行操作之前,请先将jar导入到Java程序中,请参考以下两种导入办法:办法一:如果您应用的是 maven,能够通过增加以下代码到我的项目的 pom.xml 文件中,将 jar文件导入到应用程序中。 <repositories> <repository> <id>com.e-iceblue</id> <name>e-iceblue</name> <url>https://repo.e-iceblue.cn/repository/maven-public/</url> </repository></repositories><dependencies> <dependency> <groupId>e-iceblue</groupId> <artifactId>spire.doc.free</artifactId> <version>5.2.0</version> </dependency></dependencies>办法二:如果您没有应用 maven,则能够从此链接下载Free Spire.Doc for Java,找到lib文件夹下的Spire.doc.jar并进行解压;而后在IDEA中创立一个新我的项目,顺次点击“文件”(File),“我的项目构造”(Project Structure),“组件”(Modules),“依赖项”(Dependencies),再点击右方绿色“+”下的第一个选项“jar文件或门路”(JARs or Directories),找到解压后的Spire.doc.jar 文件,点击确认,将其导入到我的项目中。 具体办法和示例代码• 创立一个Document对象来加载Word文档。• 应用getText()办法获取文档中的文本。• 调用writeStringToTxt办法将文本写入名为ExtractedText.txt的txt文件中。 import com.spire.doc.Document;import java.io.FileWriter;import java.io.IOException;public class ExtractText { public static void main(String[] args) throws IOException { //加载Word文档 Document document = new Document(); document.loadFromFile("sample.docx"); //获取文档中的文本保留为String String text=document.getText(); //将String写入Txt文件 writeStringToTxt(text,"ExtractedText.txt"); } public static void writeStringToTxt(String content, String txtFileName) throws IOException { FileWriter fWriter= new FileWriter(txtFileName,true); try { fWriter.write(content); }catch(IOException ex){ ex.printStackTrace(); }finally{ try{ fWriter.flush(); fWriter.close(); } catch (IOException ex) { ex.printStackTrace(); } } }} ...

March 24, 2023 · 1 min · jiezi

关于java:建议收藏7000字的TIDB保姆级简介你见过吗

TIDB简介 什么是TIDBTiDB 是一个分布式 NewSQL 数据库。它反对程度弹性扩大、ACID 事务、规范 SQL、MySQL 语法和 MySQL 协定,具备数据强统一的高可用个性,是一个不仅适宜 OLTP 场景还适宜 OLAP 场景的混合数据库。TiDB 是 PingCAP 公司自主设计、研发的开源分布式关系型数据库,是一款同时反对在线事务处理与在线剖析解决 (Hybrid Transactional and Analytical Processing, HTAP)的交融型分布式数据库产品,具备程度扩容或者缩容、金融级高可用、实时 HTAP、云原生的分布式数据库、兼容 MySQL 5.7 协定和 MySQL 生态等重要个性。指标是为用户提供一站式 OLTP (Online Transactional Processing)、OLAP (Online Analytical Processing)、HTAP 解决方案。TiDB 适宜高可用、强统一要求较高、数据规模较大等各种利用场景。 什么是NewSQL数据库倒退至今曾经有3代了:SQL,传统关系型数据库,例如 MySQLnoSQL,例如 MongoDB,RedisnewSQL传统SQL的问题互联网在本世纪初开始迅速倒退,互联网利用的用户规模、数据量都越来越大,并且要求7X24小时在线。传统关系型数据库在这种环境下成为了瓶颈,通常有2种解决办法: 降级服务器硬件尽管晋升了性能,但总有天花板。 数据分片应用分布式集群构造对单点数据库进行数据分片,寄存到由便宜机器组成的分布式的集群里,可扩展性更好了,但也带来了新的麻烦。 以前在一个库里的数据,当初跨了多个库,利用零碎不能自己去多个库中操作,须要应用数据库分片中间件。 分片中间件做简略的数据操作时还好,但波及到跨库join、跨库事务时就很头疼了,很多人罗唆本人在业务层解决,复杂度较高。 NoSQL 的问题起初 noSQL 呈现了,放弃了传统SQL的强事务保障和关系模型,重点放在数据库的高可用性和可扩展性。 长处高可用性和可扩展性,主动分区,轻松扩大不保障强一致性,性能大幅晋升没有关系模型的限度,极其灵便毛病不保障强一致性,对于一般利用没问题,但还是有不少像金融一样的企业级利用有强一致性的需要。不反对 SQL 语句,兼容性是个大问题,不同的 NoSQL 数据库都有本人的 api 操作数据,比较复杂。NewSQL 个性NewSQL 提供了与 noSQL 雷同的可扩展性,而且仍基于关系模型,还保留了极其成熟的 SQL 作为查询语言,保障了ACID事务个性。 简略来讲,NewSQL 就是在传统关系型数据库上集成了 NoSQL 弱小的可扩展性。 传统的SQL架构设计基因中是没有分布式的,而 NewSQL 生于云时代,天生就是分布式架构。 ...

March 24, 2023 · 4 min · jiezi

关于java:java-如何实现短函数调用

在Java中,能够应用lambda表达式来实现短函数调用。Lambda表达式是一个匿名函数,它能够传递给办法或存储在变量中,以便在须要时应用。不多说废话!!上面间接给大家示范一下,如何应用Lambda表达式实现短函数调用:在下面这段代码中:首先咱们自定义一个函数接口TestInterface;在这个接口中蕴含了一个参数为字符串类型的办法helloWord;而后咱们创立一个TestInterface接口的实例,并应用Lambda表达式来实现该接口的办法;最初咱们调用helloWord的办法,并应用管制语句输入字符串:“Hello Word!!!”所以当初大家学会了吗?应用lambda表达式,能够疾速简便地实现短函数调用,特地是在处理函数式编程方面。而我应用lambda表达式来实现短函数调用其实是有很多益处的例如: ● lambda表达式通常能够在一行内实现函数定义,比传统的函数定义更为简洁明了。 ● 应用lambda表达式能够让代码更加紧凑,易于浏览和了解。此外,lambda表达式能够用作匿名函数,这意味着不须要为函数命名,使得代码更加简洁明了。 ● ambda表达式能够作为参数传递给其余函数,这样能够更不便地传递函数对象,防止了为简短函数独自定义函数的繁琐过程。 ● 在Python中,函数是一等公民,这意味着函数能够像其余对象一样传递、返回和存储。应用lambda表达式能够不便地实现一些高阶函数,比方map()、filter()、reduce()等,从而让代码更加简洁、优雅。Lambda表达式作为Java 8的新个性之一,也是因为它能够帮忙咱们写出更简洁、更灵便的代码,所以当下,Lambda表达式曾经是很多开发人员的心头爱了,所以大家赶快练习起来吧

March 24, 2023 · 1 min · jiezi

关于java:面向对象三大特征之多态

前言 咱们晓得,面向对象有三大特色:封装、继承和多态。当初咱们曾经理解了封装和继承,接下来在本文中,给大家带来面向对象的第三大特色:多态。 在这篇文章中,咱们要弄清楚多态的含意、特点、作用,以及如何用代码进行实现。全文大概【6000】字,不说废话,只讲能够让你学到技术、明确原理的纯干货!本文带有丰盛的案例及配图,让你更好地了解和使用文中的技术概念,并能够给你带来具备足够启迪的思考 一. 多态简介 概念多态(polymorphism)原本是生物学里的概念,示意地球上的生物在状态和状态方面的多样性。 而在java的面向对象中,多态则是指同一个行为能够有多个不同表现形式的能力。也就是说,在父类中定义的属性和办法,在子类继承后,能够有不同的数据类型或体现出不同的行为。这能够使得同一个属性或办法,在父类及其各个子类中,可能会有不同的体现或含意。比方针对同一个接口,咱们应用不同的实例对象可能会有不同的操作,同一事件产生在不同的实例对象上会产生不同的后果。 当然,如果咱们只是看这样水灵灵的概念,可能大家还是有点懵,给大家举个栗子。 咱们都听过“龙生九子”的故事。长子是囚牛,喜爱搞音乐;次子是睚眦,喜爱打架。前面还有喜爱冒险登高的嘲风,爱大喊大叫的蒲牢,喜爱吸烟的狻猊,喜好举重的霸下,好打官司的狴犴,喜爱斯文的负屃,会灭火的螭吻。他们都是龙的儿子,天然也都是龙,但每个龙都有不同的共性和技能。如果有一天玉帝对龙王说,“让你的儿子来给我秀个技能”。大家说这个工作的执行后果会怎么样?这是不是得看龙王让哪个儿子来秀了!如果是让老大来表演,就是演奏音乐;如果是让老二来表演,就是表演打架 从这个故事中,咱们就能够感触到,九个龙子尽管都继承了独特的父类,但子类在运行某个办法时却可能会有不同的后果,这就是多态! 作用 依据多态的概念可知,多态机制能够在不批改父类代码的根底上,容许多个子类进行性能的扩大。比方父类中定义了一个办法A,有N个子类继承该父类,这几个子类都能够重写这个A办法。并且子类的办法还能够将本人的参数类型改为父类办法的参数类型,或者将本人的返回值类型改为父类办法的返回值类型。这样就能够动静地调整对象的调用,升高对象之间的依存关系,打消类型之间的耦合,使程序有良好的扩大,并能够对所有类的对象进行通用解决,让代码实现更加的灵便和简洁。 分类 Java中的多态,分为编译时多态和运行时多态。 ● 编译时多态:次要是通过办法的重载(overload)来实现,Java会依据办法参数列表的不同来辨别不同的办法,在编译时就能确定该执行重载办法中的哪一个。这是动态的多态,也称为动态多态性、动态绑定、前绑定。但也有一种非凡的办法重写的状况,属于编译时多态。在办法重写时,当对象的援用指向的是以后对象本人所属类的对象时,也是编译时多态,因为在编译阶段就能确定执行的办法到底属于哪个对象。 ● 运行时多态:次要是通过办法的重写(override)来实现,让子类继承父类并重写父类中已有的或形象的办法。这是动静的多态,也称为”后绑定“,这是咱们通常所说的多态性。一句话,如果咱们在编译时就能确定要执行的办法属于哪个对象、执行的是哪个办法,这就是编译时多态,否则就是运行时多态! 个性 依据多态的要求,Java对象的类型能够分为编译类型和运行类型,多态有如下个性: ● 一个对象的编译类型与运行类型能够不统一; ● 编译类型在定义对象时就确定了,不能扭转,而运行类型却是能够变动的; ● 编译类型取决于定义对象时 =号的右边,运行类型取决于 =号的左边 所以咱们在应用多态形式调用办法时,首先会查看父类中是否有该办法,如果没有,则会产生编译谬误;如果有,再去调用子类中的同名办法。即编译时取决于父类,运行时取决于子类。 必要条件 咱们要想实现多态,须要满足3个必要条件: ● 继承:多态产生在继承关系中,必须存在有继承关系的父类和子类中,多态建设在封装和继承的根底之上; ● 重写:必须要有办法的重写,子类对父类的某些办法从新定义; ● 向上转型:就是要将父类援用指向子类对象,只有这样该援用才既能调用父类的办法,又能调用子类的办法。 只有满足了以上3个条件能力实现多态,开发人员也能力在同一个继承构造中,应用对立的代码实现来解决不同的对象,从而执行不同的行为。 二. 多态的实现 实现形式 在Java中,多态的实现有如下几种形式: ● 办法重载:重载能够依据理论参数的数据类型、个数和秩序,在编译时确定执行重载办法中的哪一个。 ● 办法重写:这种形式是基于办法重写来实现的多态; ● 接口实现:接口是一种无奈被实例化但能够被实现的形象类型,是对形象办法的汇合。定义一个接口能够有多个实现,这也是多态的一种实现模式,与继承中办法的重写相似。 实现过程 2.1 需要剖析当初咱们有一个需要:有一个客户要求咱们给他生产设施器材,他须要的产品类型比拟多,可能要圆形的器材,也可能须要三角形、矩形等各种形态的器材,咱们该怎么生产实现? 如果是依照咱们之前的教训,能够别离创立圆形类、三角形类、矩形类等,外面各自有对应的生产办法,负责生产出对应的产品。然而如果这样设计,其实不合乎面向对象的要求。当前客户可能还会有很多其余的需要,如果针对每一个需要都设计一个类和办法,最终咱们的我的项目代码就会很啰嗦。 实际上,在客户的这些需要中,有很多要求是具备共性的!比方,无论客户须要什么形态的器材,咱们都要进行”绘制生产“,在绘制生产的过程中,可能用到的资料都是一样的,无非就是形态不同!就好比生产巧克力,有圆的方的奇形怪状的,不论怎么样,根底原料都是巧克力。既然如此,咱们总不能针对每一种形态的器材都从头到尾搞一遍吧? 所以既然它们有很多内容都一样,咱们就能够定义一个独特的父类,在父类中实现共性的性能和特色,而后由子类继承父类,每个子类再扩大实现本人个性化的性能。如下图所示: 这样就是合乎面向对象特色的代码设计了!接下来壹哥就通过一些代码案例,来给大家演示该如何实现这个需要。 2.2 代码实现接下来会采纳实现接口的形式来演示多态的代码实现过程。办法重载和办法重写的形式,其实咱们在后面的文章中曾经有所解说,这里不再赘述。 2.2.1 定义Shape接口咱们首先定义出一个Shape接口,这个接口就是一个父类。在Java中,子类能够继承父类,也能够实现接口。一个子类只能继承一个父类,然而却能够实现多个接口。这些接口,属于是子类的”间接父类“,你能够了解为是子类的”干爹“或者爷爷等祖辈。对于接口的内容,会在前面的文章中专门解说,敬请期待哦,此处大家先会应用即可。 2.2.2 定义Circle类定义一个Circle子类,实现Shape接口,留神咱们这里应用了implements关键字! 述(最多18字2.2.3 定义Traingle类而后再定义一个Traingle子类,也实现Shape接口。 2.2.4 定义Square类最初定义一个Square子类,同样实现Shape接口。 述(2.4.5 定义测试类父子关系确定好之后,接下来咱们再定义一个额定的测试类。在这个测试类中,咱们创立出以上三个图形对象。留神,在=等号左侧,变量的类型都是Shape父类;=等号右侧,变量的值是具体的子类!这种变量的定义过程,其实就是合乎了多态的第三个必要条件,也就是所谓的”向上转型,父类援用指向子类对象“。 咱们能够看到上述代码,满足了多态的3个必要条件:继承、从新、向上转型!有子类继承父类,有办法重写,有向上转型。而且依据这个案例,咱们能够进一步了解多态的含意和特点。在多态中,针对某个类型的办法调用,其真正执行的办法取决于运行期间理论类型的办法!本案例最终的执行后果如下图所示: 2.3 后果剖析在上述案例中,咱们有如下一行代码: 上述代码中,咱们理论的类型是Circle、Traingle、Square,他们独特的父类,其援用类型是Shape变量。当咱们调用shape.draw()时,大家能够想一下,执行的是父类Shape的draw()办法还是具体子类的draw()办法?大多数同学应该可能想进去,执行的应该是具体子类的draw()办法! 基于以上这个案例,咱们能够得出一个论断: Java实例办法的调用,是基于运行时理论类型的动静调用,而非申明的变量类型!艰深地说,就是咱们调用的到底是哪个对象的办法,不是由=号左侧申明的援用变量来决定的,而是由=号右侧的理论对象类型来决定的! 这也是多态的一个重要特色!所以咱们说在多态中,针对某个类型的办法调用,其真正执行的办法取决于运行期间理论类型的办法!即只有在运行期,能力动静决定调用哪个子类的办法。这种不确定性的办法调用,到底有什么作用呢?其实次要就是容许咱们可能增加更多类型的子类,实现对父类性能的扩大,而不须要批改父类的代码。 三. 扩大补充 办法重写时的编译时多态当对象的援用指向的是以后对象所属类的对象,即便是办法重写,仍然属于编译时多态。 1.1 定义父类咱们先定义一个Father父类,外部定义一个eat()办法。 ...

March 24, 2023 · 1 min · jiezi

关于java:阿里又开源一款数据同步工具-DataX稳定又高效好用到爆

作者:愿许浪尽咫尺 \链接:https://juejin.cn/post/7077744714954309669 前言咱们公司有个我的项目的数据量高达五千万,然而因为报表那块数据不太精确,业务库和报表库又是跨库操作,所以并不能应用 SQL 来进行同步。过后的打算是通过 mysqldump 或者存储的形式来进行同步,然而尝试后发现这些计划都不切实际: mysqldump:不仅备份须要工夫,同步也须要工夫,而且在备份的过程,可能还会有数据产出(也就是说同步等于没同步) 存储形式:这个效率太慢了,要是数据量少还好,咱们应用这个形式的时候,三个小时才同步两千条数据 ... 前面在网上查看后: 发现 DataX 这个工具用来同步不仅速度快,而且同步的数据量基本上也相差无几。一、DataX 简介DataX 是阿里云 DataWorks 数据集成 的开源版本,次要就是用于实现数据间的离线同步。 DataX 致力于实现包含关系型数据库(MySQL、Oracle 等)、HDFS、Hive、ODPS、HBase、FTP 等 各种异构数据源(即不同的数据库) 间稳固高效的数据同步性能。 为了 解决异构数据源同步问题,DataX 将简单的网状同步链路变成了星型数据链路,DataX 作为两头传输载体负责连贯各种数据源;当须要接入一个新的数据源时,只须要将此数据源对接到 DataX,便能跟已有的数据源作为无缝数据同步。 1.DataX3.0 框架设计DataX 采纳 Framework + Plugin 架构,将数据源读取和写入形象称为 Reader/Writer 插件,纳入到整个同步框架中。 角色作用Reader(采集模块)负责采集数据源的数据,将数据发送给 Framework。Writer(写入模块)负责一直向 Framework 中取数据,并将数据写入到目标端。Framework(中间商)负责连贯 Reader 和 Writer,作为两者的数据传输通道,并解决缓冲,流控,并发,数据转换等核心技术问题。2.DataX3.0 外围架构DataX 实现单个数据同步的作业,咱们称为 Job,DataX 接管到一个 Job 后,将启动一个过程来实现整个作业同步过程。DataX Job 模块是单个作业的中枢治理节点,承当了数据清理、子工作切分、TaskGroup 治理等性能。 DataX Job 启动后,会依据不同源端的切分策略,将 Job 切分成多个小的 Task (子工作),以便于并发执行。接着 DataX Job 会调用 Scheduler 模块,依据配置的并发数量,将拆分成的 Task 重新组合,组装成 TaskGroup(工作组) ...

March 24, 2023 · 6 min · jiezi

关于java:ContiPerf性能测试

性能测试依赖 <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>test</scope> </dependency> <dependency> <groupId>org.databene</groupId> <artifactId>contiperf</artifactId> <version>2.1.0</version> <scope>test</scope> </dependency>测试/** * 主要参数介绍 * 1、PerfTest参数 * @PerfTest(invocations = 300):执行300次,和线程数量无关,默认值为1,示意执行1次; * @PerfTest(threads=30):并发执行30个线程,默认值为1个线程; * @PerfTest(duration = 20000):反复地执行测试至多执行20s。 * 2、Required参数 * @Required(throughput = 20):要求每秒至多执行20个测试; * @Required(average = 50):要求均匀执行工夫不超过50ms; * @Required(median = 45):要求所有执行的50%不超过45ms; * @Required(max = 2000):要求没有测试超过2s; * @Required(totalTime = 5000):要求总的执行工夫不超过5s; * @Required(percentile90 = 3000):要求90%的测试不超过3s; * @Required(percentile95 = 5000):要求95%的测试不超过5s; * @Required(percentile99 = 10000):要求99%的测试不超过10s; * @Required(percentiles = "66:200,96:500"):要求66%的测试不超过200ms,96%的测试不超过500ms。 */@PerfTest(invocations = 1000, threads = 40)@Required(max = 1200, average = 250, totalTime = 60000)public class ContiPerfTest { @Rule public ContiPerfRule i = new ContiPerfRule(); @Test public void test1() throws Exception { System.out.println(Thread.currentThread().getName()); Thread.sleep(1300); System.out.println(Thread.currentThread().getName()); }}执行完生成html文件查看详情 ...

March 24, 2023 · 1 min · jiezi

关于java:Try-out-Google-Bard-Will-Google-Bard-beat-the-ChatGPT

Try out Google Bard, Will Google Bard beat the ChatGPT?Give a try on Google BardGoogle has begun opening up the Google Bard(An AI Chat Solution) to public. I joined the waitlist and soon got the chance to have a try on Google Bard. Just open the page: https://bard.google.com/ We can see it still under development as an experimental product. Let ask some questions: (1) How to get a job in Google? ...

March 24, 2023 · 11 min · jiezi

关于java:一个基于GPT模型实现的Git-Commit信息自动生成工具

每次提交代码的时候,你是否有为如何写Commit Message而迟迟按不下提交的时刻呢?而后,死磨硬泡写了一些并提交后,又被review的小伙伴吐槽了呢?置信很多小伙伴有过这样的经验吧? 趁着最近ChatGPT那么火,就来棘手举荐一个能够用于解决这个问题的VS Code插件:vscode-gptommit 该插件能够帮忙咱们主动的生成提交信息,而且生产内容也是八九不离十。 它会依据你的文件变动信息来产生提交音讯,所以产出的内容还是十分具备可读性,比方上面的例子: 如何应用第一步:在VS Code的插件市场里搜寻“vscode-gptcommit”,并装置它 第二步:通过VS Code的快捷键Ctrl+Shift+P或者Cmd+Shift+P唤出命令输入框来生成提交音讯 你也能够通过Git面板的这个按钮来生成: 当然了,很重要的一点,您还须要配置好openai的api key,具体如何获取,这里就不具体说啦,大家能够自行搜寻去获取 我的项目地址:https://github.com/pwwang/vscode-gptcommit 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

March 23, 2023 · 1 min · jiezi

关于java:写点算法题剑指-Offer-30-包含min函数的栈

class MinStack { private Stack<Integer> dataStack; // 用于存储数据的栈 private Stack<Integer> minStack; // 用于存储最小值的栈 /** 初始化MinStack */ public MinStack() { dataStack = new Stack<>(); // 初始化存储数据的栈 minStack = new Stack<>(); // 初始化存储最小值的栈 } /** 将元素x推到栈顶 */ public void push(int x) { dataStack.push(x); // 数据栈间接将x推到栈顶 if (minStack.isEmpty() || x <= minStack.peek()) { // 如果最小值栈为空或者x<=最小值栈顶,将x推到最小值栈顶 minStack.push(x); } } /** 删除栈顶元素 */ public void pop() { if (!dataStack.isEmpty()) { // 如果数据栈不为空 int top = dataStack.pop(); // 删除数据栈顶并获取栈顶元素值 if (top == minStack.peek()) { // 如果删除的元素是最小值栈顶元素 minStack.pop(); // 将最小值栈顶元素也删除 } } } /** 返回栈顶元素 */ public int top() { if (!dataStack.isEmpty()) { // 如果数据栈不为空 return dataStack.peek(); // 间接返回数据栈顶元素 } return -1; // 其余状况返回-1,也能够抛出异样 } /** 返回栈的最小元素 */ public int min() { if (!minStack.isEmpty()) { // 如果最小值栈不为空 return minStack.peek(); // 返回最小值栈顶元素 } return -1; // 其余状况返回-1,也能够抛出异样 }}

March 23, 2023 · 1 min · jiezi

关于java:JDK20正式发布了GA版本短期维护支持以及JDK21预览

最近,Oracle公布了JDK20,相比对于Java开发者来说,JDK的发版是比拟收关注的事件了,小简也来和大家一起理解理解JDK20产生了什么变动呢? 首先,JDK20是一个短周期版本,有6个月的保护工夫,据开发者打算,下一个LTS也就长期保护版本将会在2023年9月份公布到来,也就是JDK21了。 目前JDK21也是推出了晚期预览版本。 JDK 20 提供了来自 OpenJDK 我的项目 Amber 的语言改良(Switch 的记录模式和模式匹配),OpenJDK巴拿马我的项目的加强性能,以互连Java虚拟机(JVM)和本机代码(内部函数和内存API和矢量API),以及与 Project Loom 相干的性能(作用域值、虚构线程和结构化并发),这些性能将大大简化编写、保护和察看高吞吐量并发应用程序的过程。 Oracle 通过可预测的公布打算每六个月公布一次新的 Java 性能。这种节奏提供了源源不断的翻新,同时不断改进平台的性能、稳定性和安全性,有助于进步 Java 在各种规模的组织和行业中的普遍性。变动Language Updates and Improvements JEP 432: Record Patterns (Second Preview): Enhances the Java language by allowing users to nest record patterns and type patterns to create a powerful, declarative, and composable form of data navigation and processing. This helps increase developer productivity by enabling them to extend pattern matching to allow for more sophisticated and composable data queries.JEP 433: Pattern Matching for Switch (Fourth Preview): By extending pattern matching to switch, an expression can be tested against a number of patterns—each with a specific action—so that complex data-oriented queries can be expressed concisely and safely. Expanding the expressiveness and applicability of switch expressions and statements helps increase developer productivity.Project Loom Preview/Incubator Features ...

March 23, 2023 · 3 min · jiezi

关于java:Springboot条件注解

March 23, 2023 · 0 min · jiezi

关于java:三天吃透MongoDB面试八股文

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址:https://github.com/Tyson0314/Java-learning mongodb是什么?MongoDB 是由 C++语言编写的,是一个基于分布式文件存储的开源数据库系统。 再高负载的状况下,增加更多的节点,能够保障服务器性能。 MongoDB 旨在给 WEB 利用提供可扩大的高性能数据存储解决方案。 MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。 MongoDB 文档相似于 JSON 对象。字段值能够蕴含其余文档,数组及文档数组。 mongodb有哪些特点?(1)MongoDB 是一个面向文档存储的数据库,操作起来比较简单和容易。 (2)你能够在 MongoDB 记录中设置任何属性的索引 (如: FirstName="Sameer",Address="8 Gandhi Road")来实现更快的排序。 (3)你能够通过本地或者网络创立数据镜像,这使得 MongoDB 有更强的扩展性。 (4)如果负载的减少(须要更多的存储空间和更强的解决能力) ,它能够散布在计算机网络中的其余节点上这就是所谓的分片。 (5)Mongo 反对丰盛的查问表达式。查问指令应用 JSON 模式的标记,可轻易查问文档中内嵌的对象及数组。 (6)MongoDb 应用 update()命令能够实现替换实现的文档(数据)或者一些指定的数据字段 。 (7)Mongodb 中的 Map/reduce 次要是用来对数据进行批量解决和聚合操作。 (8)Map 和 Reduce。 Map 函数调用 emit(key,value)遍历汇合中所有的记录,将 key 与 value 传给 Reduce 函数进行解决。 (9)Map 函数和 Reduce 函数是应用 Javascript 编写的,并能够通过 db.runCommand 或 mapreduce 命令来执行 MapReduce 操作。 (10)GridFS 是 MongoDB 中的一个内置性能,能够用于寄存大量小文件。 (11) MongoDB 容许在服务端执行脚本, 能够用 Javascript 编写某个函数,间接在服务端执行,也能够把函数的定义存储在服务端,下次间接调用即可。 ...

March 23, 2023 · 2 min · jiezi

关于java:java-node-递归链表

应用java实现正向链表 Node类 public class Node { public Object data; public Node next; public Node(Object data) { super(); this.data = data; }NodeLink类 public class NodeLink { Node head; Node last; public void getLastNode(Node node){ if(node.next!=null){ getLastNode(node.next); }else if(node.next==null){ last=node; } } public Node addNode(Node another){ if(head==null){ head=another; }else{ getLastNode(head); System.out.println(last.data); last.next=another; } return head; } public void print(Node node){ System.out.print(node.data+"-->"); if(node.next!=null){ this.print(node.next); } }加几个办法就能变成双向链表PS. 和机构,菜单的递归简直一样测试 public static void main(String[] args) { NodeLink link=new NodeLink(); Node a=new Node("a"); Node b=new Node("b"); Node c=new Node("c"); Node d=new Node("d"); link.addNode(a); link.addNode(b); link.addNode(c); System.out.println();// System.out.println(a.next);// System.out.println(b.next);// System.out.println(c.next); link.addNode(d); System.out.println("-------------"); link.print(link.head); }

March 22, 2023 · 1 min · jiezi

关于java:你可能不那么知道的Tomcat生命周期管理-博学谷狂野架构师

Tomcat生命周期治理 各种组件如何对立治理Tomcat的架构设计是清晰的、模块化、它领有很多组件,退出在启动Tomcat时一个一个组件启动,很容易脱漏组件,同时还会对前面的动静组件拓展带来麻烦。如果采纳咱们传统的形式的话,组件在启动过程中如果产生异样,会很难治理,比方你的下一个组件调用了start办法,然而如果它的下级组件还没有start甚至还没有init的话,Tomcat的启动会十分难治理,因而,Tomcat的设计者提出一个解决方案:用Lifecycle治理启动,进行、敞开。 生命周期对立接口Tomcat外部架构中各个外围组件有蕴含与被蕴含关系,例如:Server蕴含了Service.Service又蕴含了Container和Connector,这个构造有一点像数据结构中的树,树的根结点没有父节点,其余节点有且仅有一个父节点,每一个父节点有0至多个子节点。所以,咱们能够通过父容器启动它的子容器,这样只有启动根容器,就能够把其余所有的容器都启动,从而达到了对立的启动,进行、敞开的成果。 所有所有组件有一个对立的接口——Lifecycle,把所有的启动、进行、敞开、生命周期相干的办法都组织到一起,就能够很方便管理Tomcat各个容器组件的生命周期。 Lifecycle其实就是定义了一些状态常量和几个办法,次要办法是init,start,stop三个办法。 例如:Tomcat的Server组件的init负责遍历调用其蕴含所有的Service组件的init办法。 留神:Server只是一个接口,实现类为StandardServer,有意思的是,StandardServer没有init办法,init办法是在哪里,其实是在它的父类LifecycleBase中,这个类就是对立的生命周期治理。 COPYpublic class StandardService extends LifecycleMBeanBase implements Service public abstract class LifecycleMBeanBase extends LifecycleBase implements JmxEnabledLifecycleBaseCOPYpublic abstract class LifecycleBase implements Lifecycle { @Override public final synchronized void init() throws LifecycleException { //这个就是为了避免 组件启动的程序不对 if (!state.equals(LifecycleState.NEW)) { invalidTransition(Lifecycle.BEFORE_INIT_EVENT); } try { //只打印外围组件 if(this.getClass().getName().startsWith("org.apache.catalina.core")||this.getClass().getName().startsWith("org.apache.catalina.connector")){ System.out.println(this.getClass()+"--init()"); } setStateInternal(LifecycleState.INITIALIZING, null, false); //调用子类的initInternal办法 initInternal(); setStateInternal(LifecycleState.INITIALIZED, null, false); } catch (Throwable t) { handleSubClassException(t, "lifecycleBase.initFail", toString()); } } }所以StandardServer最终只会调用到initInternal办法,这个办法会初始化子容器Service的init办法 ...

March 22, 2023 · 5 min · jiezi

关于java:面试官ThreadLocal-为什么会内存泄漏吗是怎么产生的面试必问

原文:blog.csdn.net/qunqunstyle99/article/details/94717256 ThreadLocal是什么ThreadLocal是一个本地线程正本变量工具类。次要用于将公有线程和该线程寄存的正本对象做一个映射,各个线程之间的变量互不烦扰,在高并发场景下,能够实现无状态的调用,特地实用于各个线程依赖不通的变量值实现操作的场景。 下图为ThreadLocal的外部结构图 从下面的结构图,咱们曾经窥见ThreadLocal的外围机制: 每个Thread线程外部都有一个Map。Map外面存储线程本地对象(key)和线程的变量正本(value)然而,Thread外部的Map是由ThreadLocal保护的,由ThreadLocal负责向map获取和设置线程的变量值。所以对于不同的线程,每次获取正本值时,别的线程并不能获取到以后线程的正本值,造成了正本的隔离,互不烦扰。 举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practiceThreadLocalMap ThreadLocalMap是ThreadLocal的外部类,没有实现Map接口,用独立的形式实现了Map的性能,其外部的Entry也独立实现。 和HashMap的最大的不同在于,ThreadLocalMap构造非常简单,没有next援用,也就是说ThreadLocalMap中解决Hash抵触的形式并非链表的形式,而是采纳线性探测的形式。(ThreadLocalMap如何解决抵触?) 在ThreadLocalMap中,也是用Entry来保留K-V构造数据的。然而Entry中key只能是ThreadLocal对象,这点被Entry的构造方法曾经限定死了。 static class Entry extends WeakReference<ThreadLocal> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; }}留神了!!Entry继承自WeakReference(弱援用,生命周期只能存活到下次GC前),但只有Key是弱援用类型的,Value并非弱援用。(问题马上就来了) 因为ThreadLocalMap的key是弱援用,而Value是强援用。这就导致了一个问题,ThreadLocal在没有内部对象强援用时,产生GC时弱援用Key会被回收,而Value不会回收。 当线程没有完结,然而ThreadLocal曾经被回收,则可能导致线程中存在ThreadLocalMap<null, Object>的键值对,造成内存泄露。(ThreadLocal被回收,ThreadLocal关联的线程共享变量还存在)。 如何防止透露 为了避免此类情况的呈现,咱们有两种伎俩。 1、应用完线程共享变量后,显示调用ThreadLocalMap.remove办法革除线程共享变量; 既然Key是弱援用,那么咱们要做的事,就是在调用ThreadLocal的get()、set()办法时实现后再调用remove办法,将Entry节点和Map的援用关系移除,这样整个Entry对象在GC Roots剖析后就变成不可达了,下次GC的时候就能够被回收。 2、JDK倡议ThreadLocal定义为private static,这样ThreadLocal的弱援用问题则不存在了。 文章参考: www.jianshu.com/p/98b68c97df9bwww.cnblogs.com/coshaho/p/5127135.html近期热文举荐: 1.1,000+ 道 Java面试题及答案整顿(2022最新版) 2.劲爆!Java 协程要来了。。。 3.Spring Boot 2.x 教程,太全了! 4.别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!! 5.《Java开发手册(嵩山版)》最新公布,速速下载! 感觉不错,别忘了顺手点赞+转发哦!

March 22, 2023 · 1 min · jiezi

关于java:Spring-Boot-如果防护-XSS-SQL-注入攻击-一文带你搞定

1. XSS跨站脚本攻打①:XSS破绽介绍跨站脚本攻打XSS是指攻击者往Web页面里插入歹意Script代码,当用户浏览该页之时,嵌入其中Web外面的Script代码会被解析执行,从而达到歹意攻打用户的目标。XSS攻打针对的是用户层面的攻打! ②:XSS破绽分类存储型XSS: 存储型XSS,长久化,代码是存储在服务器中的,如在个人信息或发表文章等中央,插入代码,如果没有过滤或过滤不严,那么这些代码将贮存到服务器中,用户拜访该页面的时候触发代码执行。这种XSS比拟危险,容易造成蠕虫,偷盗cookie 反射型XSS: 非长久化,须要坑骗用户本人去点击链接能力触发XSS代码(服务器中没有这样的页面和内容),个别容易呈现在搜寻页面 DOM型XSS: 不通过后端,DOM-XSS破绽是基于文档对象模型(Document Objeet Model,DOM)的一种破绽,DOM-XSS是通过url传入参数去管制触发的,其实也属于反射型XSS。 ③:防护倡议限度用户输出,表单数据规定值得类型,例如年龄只能是int,name为字母数字组合。对数据进行html encode解决。过滤或移除非凡的html标签。过滤javascript事件的标签。2. SQL注入攻打①:SQL注入破绽介绍SQL注入(SQLi)是一种注入攻打,能够执行歹意SQL语句。它通过将任意SQL代码插入数据库查问,使攻击者可能齐全管制Web应用程序前面的数据库服务器。攻击者能够应用SQL注入破绽绕过应用程序安全措施;能够绕过网页或Web应用程序的身份验证和受权,并检索整个SQL数据库的内容;还能够应用SQL注入来增加,批改和删除数据库中的记录 SQL注入破绽可能会影响应用SQL数据库(如MySQL,Oracle,SQL Server或其余)的任何网站或Web应用程序。犯罪分子可能会利用它来未经受权拜访用户的敏感数据:客户信息,集体数据,商业秘密,知识产权等。SQL注入攻打是最古老,最风行,最危险的Web应用程序破绽之一。 ②:防护倡议应用mybatis中#{}能够无效避免sql注入 应用#{}时:<select id="getBlogById" resultType="Blog" parameterType=”int”> select id,title,author,content from blog where id=#{id}</select>打印出执行的sql语句,会看到sql是这样的: select id,title,author,content from blog where id = ?不论输出什么参数,打印出的sql都是这样的。这是因为mybatis启用了预编译性能,在sql执行前,会先将下面的sql发送给数据库进行编译,执行时,间接应用编译好的sql,替换占位符“?”就能够了。因为sql注入只能对编译过程起作用,所以像#{}这样预编译成?的形式就很好地防止了sql注入的问题。 mybatis是如何做到sql预编译的呢? 其实在框架底层,是jdbc中的PreparedStatement类在起作用,PreparedStatement是咱们很相熟的Statement的子类,它的对象蕴含了编译好的sql语句。这种“筹备好”的形式不仅能进步安全性,而且在屡次执行一个sql时,可能提高效率,起因是sql已编译好,再次执行时无需再编译。 应用${}时<select id="orderBlog" resultType="Blog" parameterType=”map”> select id,title,author,content from blog order by ${orderParam}</select>仔细观察,内联参数的格局由“#{xxx}”变为了${xxx}。如果咱们给参数“orderParam”赋值为”id”,将sql打印进去,是这样的: select id,title,author,contet from blog order by id显然,这样是无奈阻止sql注入的,参数会直接参与sql编译,从而不能防止注入攻打。但波及到动静表名和列名时,只能应用“${}”这样的参数格局,所以,这样的参数须要咱们在代码中手工进行解决来避免注入。 3. SpringBoot中如何避免XSS攻打和sql注入话不多说,上代码 Spring Boot 根底就不介绍了,举荐看这个收费教程: https://github.com/javastacks/spring-boot-best-practice对于Xss攻打和Sql注入,咱们能够通过过滤器来搞定,可依据业务须要排除局部申请 ①:创立Xss申请过滤类XssHttpServletRequestWraper 代码如下: public class XssHttpServletRequestWraper extends HttpServletRequestWrapper { Logger log = LoggerFactory.getLogger(this.getClass()); public XssHttpServletRequestWraper() { super(null); } public XssHttpServletRequestWraper(HttpServletRequest httpservletrequest) { super(httpservletrequest); } //过滤springmvc中的 @RequestParam 注解中的参数 public String[] getParameterValues(String s) { String str[] = super.getParameterValues(s); if (str == null) { return null; } int i = str.length; String as1[] = new String[i]; for (int j = 0; j < i; j++) { //System.out.println("getParameterValues:"+str[j]); as1[j] = cleanXSS(cleanSQLInject(str[j])); } log.info("XssHttpServletRequestWraper污染后的申请为:==========" + as1); return as1; } //过滤request.getParameter的参数 public String getParameter(String s) { String s1 = super.getParameter(s); if (s1 == null) { return null; } else { String s2 = cleanXSS(cleanSQLInject(s1)); log.info("XssHttpServletRequestWraper污染后的申请为:==========" + s2); return s2; } } //过滤申请体 json 格局的 @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(inputHandlers(super.getInputStream ()).getBytes ()); return new ServletInputStream() { @Override public int read() throws IOException { return bais.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; } public String inputHandlers(ServletInputStream servletInputStream){ StringBuilder sb = new StringBuilder(); BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(servletInputStream, Charset.forName("UTF-8"))); String line = ""; while ((line = reader.readLine()) != null) { sb.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (servletInputStream != null) { try { servletInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return cleanXSS(sb.toString ()); } public String cleanXSS(String src) { String temp = src; src = src.replaceAll("<", "<").replaceAll(">", ">"); src = src.replaceAll("\\(", "(").replaceAll("\\)", ")"); src = src.replaceAll("'", "'"); src = src.replaceAll(";", ";"); //bgh 2018/05/30 新增 /**-----------------------start--------------------------*/ src = src.replaceAll("<", "& lt;").replaceAll(">", "& gt;"); src = src.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41"); src = src.replaceAll("eval\\((.*)\\)", ""); src = src.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\""); src = src.replaceAll("script", ""); src = src.replaceAll("link", ""); src = src.replaceAll("frame", ""); /**-----------------------end--------------------------*/ Pattern pattern = Pattern.compile("(eval\\((.*)\\)|script)", Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(src); src = matcher.replaceAll(""); pattern = Pattern.compile("[\\\"\\'][\\s]*javascript:(.*)[\\\"\\']", Pattern.CASE_INSENSITIVE); matcher = pattern.matcher(src); src = matcher.replaceAll("\"\""); // 减少脚本 src = src.replaceAll("script", "").replaceAll(";", "") /*.replaceAll("\"", "").replaceAll("@", "")*/ .replaceAll("0x0d", "").replaceAll("0x0a", ""); if (!temp.equals(src)) { // System.out.println("输出信息存在xss攻打!"); // System.out.println("原始输出信息-->" + temp); // System.out.println("解决后信息-->" + src); log.error("xss攻打查看:参数含有非法攻打字符,已禁止持续拜访!!"); log.error("原始输出信息-->" + temp); throw new CustomerException("xss攻打查看:参数含有非法攻打字符,已禁止持续拜访!!"); } return src; } //输入 public void outputMsgByOutputStream(HttpServletResponse response, String msg) throws IOException { ServletOutputStream outputStream = response.getOutputStream(); //获取输入流 response.setHeader("content-type", "text/html;charset=UTF-8"); //通过设置响应头管制浏览器以UTF-8的编码显示数据,如果不加这句话,那么浏览器显示的将是乱码 byte[] dataByteArr = msg.getBytes("UTF-8");// 将字符转换成字节数组,指定以UTF-8编码进行转换 outputStream.write(dataByteArr);// 应用OutputStream流向客户端输入字节数组 } // 须要减少通配,过滤大小写组合 public String cleanSQLInject(String src) { String lowSrc = src.toLowerCase(); String temp = src; String lowSrcAfter = lowSrc.replaceAll("insert", "forbidI") .replaceAll("select", "forbidS") .replaceAll("update", "forbidU") .replaceAll("delete", "forbidD").replaceAll("and", "forbidA") .replaceAll("or", "forbidO"); if (!lowSrcAfter.equals(lowSrc)) { log.error("sql注入查看:输出信息存在SQL攻打!"); log.error("原始输出信息-->" + temp); log.error("解决后信息-->" + lowSrc); throw new CustomerException("sql注入查看:参数含有非法攻打字符,已禁止持续拜访!!"); } return src; }}②:把申请过滤类XssHttpServletRequestWraper增加到Filter中,注入容器@Componentpublic class XssFilter implements Filter { Logger log = LoggerFactory.getLogger(this.getClass()); // 疏忽权限查看的url地址 private final String[] excludeUrls = new String[]{ "null" }; public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) arg0; HttpServletResponse response = (HttpServletResponse) arg1; String pathInfo = req.getPathInfo() == null ? "" : req.getPathInfo(); //获取申请url的后两层 String url = req.getServletPath() + pathInfo; //获取申请你ip后的全副门路 String uri = req.getRequestURI(); //注入xss过滤器实例 XssHttpServletRequestWraper reqW = new XssHttpServletRequestWraper(req); //过滤掉不须要的Xss校验的地址 for (String str : excludeUrls) { if (uri.indexOf(str) >= 0) { arg2.doFilter(arg0, response); return; } } //过滤 arg2.doFilter(reqW, response); } public void destroy() { } public void init(FilterConfig filterconfig1) throws ServletException { }}上述代码曾经能够实现 申请参数、JSON申请体 的过滤,但对于json申请体还有其余的形式实现,有趣味的请看上面的扩大! ...

March 22, 2023 · 4 min · jiezi

关于java:不存在百分百的安全该给你的系统上个保险了

故障,是每个技术人都不愿遇到,但却总会遇到的事件。程序Bug、安全漏洞、黑客攻击、服务器宕机、网络中断等诸多因素都有可能引发系统故障,使咱们的业务面临瘫痪的困境。这样的例子,国内外都在一直的产生,比方:2020年,因为重大的全澳性IT故障,Coles的收银机全副不能联网,down机瘫痪。收银员扫不了货品顾客也不能结账,澳洲每家Coles超市都被迫临时敞开。2018年,上海的医疗保险信息系统就突发故障,波及上海各大医院的结算零碎,以致大量市民在就医时无奈失常应用医保卡,泛滥医院的排队窗口前纷纷大排长龙,局面凌乱。事发之后就有不少网友质疑,涉及面如此之广的医保信息系统,“难道没有应急措施?”这些活生生的实在案例都在揭示咱们,技术赋能业务产生更高效率、获取更多价值的同时,保障系统稳固运行也至关重要。一旦零碎呈现大范畴、长时间故障,以致业务中断的结果可能间接磨灭技术赋能带来的收益,甚至还可能带来经济损失、品牌受损等严重后果。 所以,有必要给咱们的零碎上一份“保险”——构建高可用的零碎架构,这是每个技术团队都在致力的外围指标。 什么是高可用那么怎么样的零碎是否具备高可用能力的呢?我认为次要考量两个方面:容错与容灾。 容错能力指的是当故障来长期,业务零碎是否能够不中断,持续服务的能力。惯例措施就是集群化部署,同样业务的利用部署多台服务器,即时有个别服务坏了,其余服务仍然能够提供业务反对。这就像飞机配置多台引擎一样,即时有一台坏了,剩下的仍然能够撑持它航行到指定地点平安着陆。 容灾能力指的是当重大劫难来长期,容错能力曾经全副生效了,但咱们仍然有能力通过一些伎俩让业务从新复原。惯例措施就是备份,当某个机房产生了重大的故障,所有服务器都无奈失常工作了,但数据备份还在,那咱们就能够从新加载它们并让零碎从新运行起来。这就好比飞机上的引擎全副坏了,但为了保障航行工作当前还能执行,必须提供爱护飞行员逃生的安装,比方通过弹射跳伞的形式令其能够幸存下来,之后又持续再其余飞机上继续执行工作。 高可用零碎的构建筹备首先,在构建高可用零碎之前,咱们要对故障有几个根本的意识:没有任何一个设施是100%安全可靠的。所以,一个零碎在设计高可用架构的时候,复杂度随波及的设施的数量增多而变高。 其次,咱们须要尽可能的精简运维体系。简略的说,上云是大部分企业的最佳抉择。除非本身团队在同估算的状况下,可能在基建保护上达到雷同乃至更高的可用性。不然你机房建设、服务器、网络等基础设施的保护可能都将要你半条命。 再者,必须平常心看待可用性保障,这个情理就不多说了。意外总是在产生,翻翻过来的那些故障,是不是都还历历在目: 2022年6月,Cloudflare的意外中断导致大量热门网站拜访呈现问题2021年12月,AWS大面积故障导致大量网站无奈服务,亚马逊电商也蒙受重创2021年5月,IBM Cloud在短短5天里间断产生两次重大的中断事变2020年3月,Google Cloud多个地区的云服务瘫痪,工夫长达14小时2019年2月,Google Cloud因光纤受损呈现网络问题,工夫长达10小时2018年4月,Azure因受雷雨天气影响导致电压激增而中断服务,工夫长达28小时然而。正因为没有100%的无故障,咱们才要用高可用,因为这是惟一解救你造成微小财产损失的机会。 最初,咱们不得不正视一个云服务用户的常见误区。当咱们抉择云服务商的时候,须要明确云厂商到底给咱们提供了哪些高可用能力,而剩下的高可用能力笼罩是须要咱们本人设计和实现的。咱们要晓得,一个高可用零碎的构建是贯通基础设施、中间件、服务端、客户端等多方面的。对稳定性高度敏感的企业肯定要平常心对待故障 ,用好高可用。 (下图展现了云服务厂商和用户的高可用上的责任模型:云服务商提供的次要是根底硬件服务的高可用能力。而咱们之前所提到的业务容错(负载架构)、容灾(保障数据备份)能力都是在用户侧的。供参考) 所以,如果在上云的时候,对本身业务零碎不做额定的高可用保障,那就很可能呈现文章开始咱们提到的那些业务困境。 总结明天跟大家聊了聊零碎上云时,容易被疏忽的高可用问题,以及如何做好云上高可用架构的办法。对此你有什么想法呢?留言区一起聊一聊。 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

March 22, 2023 · 1 min · jiezi

关于java:MyBatis-学习笔记MyBatis-启动流程

MyBatis 通过应用 SqlSessionFactoryBuilder ,以创立 SqlSessionFactory 对象来进行 MyBatis 的启动,无论是否集成 Spring 的模块。 SqlSessionFactoryBuilder 蕴含以下办法: SqlSessionFactoryBuilder#build(java.io.Reader)SqlSessionFactoryBuilder#build(java.io.Reader,java.lang.String)SqlSessionFactoryBuilder#build(java.io.Reader,java.util.Properties)SqlSessionFactoryBuilder#build(java.io.Reader,java.lang.String,java.util.Properties)SqlSessionFactoryBuilder#build(java.io.InputStream)SqlSessionFactoryBuilder#build(java.io.InputStream,java.lang.String)SqlSessionFactoryBuilder#build(java.io.InputStream,java.util.Properties)SqlSessionFactoryBuilder#build(java.io.InputStream,java.lang.String,java.util.Properties)SqlSessionFactoryBuilder#build(org.apache.ibatis.session.Configuration)除了最初了一个须要传入 Configuration 参数的办法外,其余底层都是通过 XMLConfigBuilder#parse() 办法来启动 MyBaits 。 起因也很简略,除了须要传入 Configuration 参数的办法外,其余的办法都是要传入 Reader 或者 InputStream 文件流参数来进行文件读写。 而 XMLConfigBuilder 类是用来读取 mybatis-config.xml 文件的来进行 MyBatis 的全局配置和启动,那么它天然就须要通过文件流参数来读取配置文件。 SqlSessionFactoryBuilder 源码/** * 暗藏了局部源码,只保留次要局部 */public class SqlSessionFactoryBuilder { /** * 通过第一个参数的 Reader 对象读取 MyBatis-config.xml 文件,进行 MyBatis 的初始化,并返回 SqlSessionFactory 对象。 * SqlSessionFactoryBuilder 除了该办法之外,还有另外一个办法反对 InputStream 文件流来读取 MyBatis-config.xml 文件。 */ public SqlSessionFactory build(Reader reader, String environment, Properties properties) { try { // 创立 XMLConfigBuilder 对象 XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); // 调用 XMLConfigBuilder#parse() 办法,该办法进行 MyBatis 的初始化工作。 // 最终失去了 Configuration 对象,并调用 build(Configuration) 办法,返回 SqlSessionFactory 的默认实现。 return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException e) { } } } public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }}XMLConfigBuilder在 SqlSessionFactoryBuilder#build(Reader, String, Properties) 办法中,咱们看到它实质上是通过 XMLConfigBuilder 对象来实现 MyBatis 的初始化,那么 XMLConfigBuilder#parse() 办法是咱们要关注的内容。 它次要干了以下几个事件: ...

March 22, 2023 · 19 min · jiezi

关于java:k8s-kubernetesadmin用户权限解析

k8s kubernetes-admin用户权限解析本篇次要介绍一下 在k8s中 默认的 ~/.kube/config 中admin管理员权限得解析 ,看看为什么kubernetes-admin用户领有所有权限 1.k8s 默认 kubernetes-admin管理员用户集群装置实现后 会有默认的配置文件在 原始目录在/etc/kubernetes/上面 个别会copy到 ~/.kube/config 上面 关上就能够看到外面有个 user:kubernetes-admin 上面来看看它的权限是有哪些 2.查问clusterrolebindings咱们晓得 k8s 中用户分为2种 一种是Normal Users 一种是Service Account , k8s不治理Users ,只有证书通过即可拜访集群, 下面的kubernetes-admin就是属于 Users 一种 , 然而用户能够操作的权限是在 关联 rolebinding / clusterrolebinding , 所以 kubernetes-admin必定也有绑定的角色, 上面来看看 kubectl get clusterrolebindings -A 能够看到 cluster-admin 很像给 admin 的绑定权限 具体查看 clusterrolebindings cluster-admin [root@master1 .kube]# kubectl get clusterrolebindings cluster-admin -A -o yamlapiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: annotations: rbac.authorization.kubernetes.io/autoupdate: "true" creationTimestamp: "2023-03-13T08:02:38Z" labels: kubernetes.io/bootstrapping: rbac-defaults name: cluster-admin resourceVersion: "148" uid: 1e950454-3849-4306-84a8-5e4a6ee59cbfroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects:- apiGroup: rbac.authorization.k8s.io kind: Group name: system:masters ...

March 22, 2023 · 1 min · jiezi

关于java:Redis-实现分布式锁执行lua脚本

Redis 实现分布式锁+执行lua脚本本篇来看看Redis 实现分布式锁的 步步演进过程 ,包含 setnx -> set -> 过期工夫 -> 误删锁 -> uuid管制锁误删-> lua脚本管制删锁的原子性 分布式锁,即分布式系统中的锁。在单体利用中咱们通过锁解决的是管制共享资源拜访的问题,而分布式锁,就是解决了分布式系统中管制共享资源拜访的问题。与单体利用不同的是,分布式系统中竞争共享资源的最小粒度从线程升级成了过程。 假如当初在redis中有 5000个 iphone14商品 上面来通过扣减这5000个iphone的案例 来一步步欠缺分布式的实现,让咱们可能更加了解这些改良的起因. set iphone14 50001.无 分布式锁管制无锁管制的时候 多个线程获取会同时获取到库存 而后进行扣减 会导致并发问题 String stock = stringRedisTemplate.opsForValue().get("iphone14");if (stock != null) { // 3.比拟并且扣减库存 long stockCount = Long.parseLong(stock); if (stockCount > 0) { // 4.设置库存 stringRedisTemplate.opsForValue().set("iphone14", String.valueOf(--stockCount)); }}ab测试后发现重大的超卖问题 ab -c 100 -n 5000 http://127.0.0.1:10010/deduct 2.应用 setnx 命令能够通过 redis 的 setnx 命令 来增加锁, 这个命令的意思是 如果key不存在 才设置, 这就模仿了如果他人没抢到锁我就加锁的意思 ...

March 22, 2023 · 4 min · jiezi

关于java:Java后端实现将jsonArray转成string以文件形式保存到本地

上代码看思路 private String writeFile(JSONArray jsonArray) { String filename=""; //写文件 try { //创立文件 File writeName = new File("abc.json").getAbsoluteFile(); // 相对路径,如果没有则要建设一个新的output.txt文件 if(!writeName.exists()) { writeName.createNewFile(); // 创立新文件,有同名的文件的话间接笼罩 } //获取文件门路 filename=writeName.getPath(); //new一个文件写者,指定写的门路 FileWriter writer = new FileWriter(filename); //给文件写者调配一个缓存写者 BufferedWriter out = new BufferedWriter(writer); //先将数据写在缓存区 out.write(jsonArray.toString()); // 把缓存区内容压入文件 out.flush(); out.close(); writer.close(); } catch (IOException e) { e.printStackTrace(); } return filename; }具体过程已正文到代码中,简要步骤可详情 jsonarray->string创立文件写文件开释写者

March 21, 2023 · 1 min · jiezi

关于java:从数据库获取数据转成json格式java后端

先上代码 private JSONArray getJsonArray(){ QueryWrapper<KltSoftExamineEntity> kltSoftExamineQueryWrapper=new QueryWrapper<>(); kltSoftExamineQueryWrapper.select("platform").groupBy("platform"); List<KltSoftExamineEntity> platForms=kltSoftExamineMapper.selectList(kltSoftExamineQueryWrapper); JSONArray jsonArray=new JSONArray(); JSONObject jsonPlatObject =new JSONObject(); platForms.forEach(platForm->{ jsonPlatObject.put("plateformCode",platForm.getPlatform());//1 jsonPlatObject.put("plateformName","platformName");//2 //获取serverList JSONArray jsonServerListArray=new JSONArray(); QueryWrapper<KltSoftExamineEntity> kltSoftExamineQueryWrapper1=new QueryWrapper<>(); kltSoftExamineQueryWrapper1.select("server_ip").groupBy("server_ip").eq("platform",platForm.getPlatform()); List<KltSoftExamineEntity> serverIps=kltSoftExamineMapper.selectList(kltSoftExamineQueryWrapper1); JSONObject jsonServerObject =new JSONObject(); AtomicInteger i= new AtomicInteger(); serverIps.forEach(serverIp->{ jsonServerObject.put("serverName","licens-server"+i);//2.1 i.getAndIncrement(); jsonServerObject.put("serverIp",serverIp.getServerIp());//2.2 //获取softList JSONArray jsonSoftListArray=new JSONArray(); QueryWrapper<KltSoftExamineEntity> kltSoftExamineQueryWrapper2=new QueryWrapper<>(); kltSoftExamineQueryWrapper2.select("soft_name").groupBy("soft_name").eq("server_ip",serverIp.getServerIp()); List<KltSoftExamineEntity> softNames=kltSoftExamineMapper.selectList(kltSoftExamineQueryWrapper2); JSONObject jsonSoftObject =new JSONObject(); softNames.forEach(softName->{ jsonSoftObject.put("softName",softName.getSoftName());//3.1 //获取featureList JSONArray jsonFeatureListArray=new JSONArray(); QueryWrapper<KltSoftExamineEntity> kltSoftExamineQueryWrapper3=new QueryWrapper<>(); kltSoftExamineQueryWrapper3.select("feature_name").groupBy("feature_name").eq("soft_name",softName.getSoftName()); List<KltSoftExamineEntity> featureNames=kltSoftExamineMapper.selectList(kltSoftExamineQueryWrapper3); featureNames.forEach(featureName->{ JSONObject jsonFeatureObject =new JSONObject(); jsonFeatureObject.put("featureName",featureName.getFeatureName());//4.1 jsonFeatureListArray.add(jsonFeatureObject); }); jsonSoftObject.put("featureList",jsonFeatureListArray);//3.2 jsonSoftListArray.add(jsonSoftObject); }); jsonServerObject.put("softList",jsonSoftListArray);//2.3 jsonServerListArray.add(jsonServerObject); }); //serverList是JSONArray jsonPlatObject.put("serverList",jsonServerListArray);//3 jsonArray.add(jsonPlatObject); }); return jsonArray; }上述对数据库的操作都是在一张表下面取的 ...

March 21, 2023 · 1 min · jiezi

关于java:屎上最全vuepdfSpringboot与asposewords整合开箱即用

前言⏲️本文浏览时长:约10分钟次要指标:1.实现Springboot与aspose-words整合,填充word模板并转化PDF;2.前端vue整合vue-pdf实现PDF预览及下载word模板重点(详见图示)1.单属性赋值2.List循环赋值3.图片插入4.对勾特殊符号插入 干货代码源码https://gitee.com/javadog-net/boot-apose.git 文件夹形容boot-aposejava后盾vue-apose前端vue对应工具下载工具形容地址aspose-words-19.1word三方库https://download.csdn.net/download/baidu_25986059/85390408javadog-vue-pdf因原版vue-pdf有兼容谬误,此版本为自己订正自用版https://www.npmjs.com/package/javadog-vue-pdf后果预览 模板填充前空word模板 代码填充后word模板 web端vue预览的html的pdf 最终填充后下载的pdf 技术波及♂️后端框架技术名称参考网站Spring BootMVC框架https://spring.io/projects/spring-bootMaven我的项目构建http://maven.apache.orgaspose-words本地依赖word工具包https://download.csdn.net/download/baidu_25986059/85390408lombokJava库https://projectlombok.org/hutool工具类http://hutool.mydoc.io♀️前端框架技术名称参考网站VUEMVVM框架https://cn.vuejs.org//Element UIUI库https://element.eleme.cn/2.0/#/zh-CNjavadog-vue-pdfPDF文件在线预览库(集体修复兼容版)https://www.npmjs.com/package/javadog-vue-pdfaxios基于promise网络申请库http://www.axios-js.com/注释尽管节约的工夫有点多,不过磨刀不误砍柴工前置条件后盾springboot根底我的项目vue根底我的项目⭐ 如没有根底代码能够间接下载狗哥Gitee源码步骤解析后盾1.下载对应的aspose-words-19.1-jdk16.jar,退出POM本地依赖因原版免费且会有水印等不确定因素,间接下载jar包本地依赖或者上传私服 <!-- 本地依赖 aspose-words--> <dependency> <groupId>com.aspose</groupId> <artifactId>aspose-words</artifactId> <classifier>jdk16</classifier> <scope>system</scope> <version>1.0</version> <systemPath>${project.basedir}/src/main/resources/lib/aspose-words-19.1-jdk16.jar</systemPath> </dependency>2.搁置模板文件到资源门路下 3.controller读取模板文件并填充数据读取模板并将输出流转为doc,并设置文件名及返回类型 定位【照片】书签地位,插入图片 定位【等级】书签地位,插入对应字符书签插入参考如下 找到须要插入的图片的中央,鼠标焦点聚焦点击【插入】找到书签并点击,而后录入书签名,并点击增加查看书签是否增加胜利 更新doc 将根底数据填充后并转为PDF 详见如下代码package apose.javadog.net.controller;import apose.javadog.net.entity.BaseInfo;import apose.javadog.net.entity.Education;import apose.javadog.net.entity.Interview;import apose.javadog.net.entity.WorkExperience;import cn.hutool.core.util.CharsetUtil;import com.aspose.words.Document;import com.aspose.words.DocumentBuilder;import com.aspose.words.ReportingEngine;import com.aspose.words.SaveFormat;import lombok.extern.slf4j.Slf4j;import org.springframework.core.io.ClassPathResource;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletResponse;import java.io.InputStream;import java.net.URLEncoder;import java.util.ArrayList;import java.util.List;@RestController@RequestMapping("/word")@Slf4jpublic class WordController { @GetMapping("/pdf") void pdf(HttpServletResponse response){ // 获取资源doc门路下的简历interview.doc模板 final ClassPathResource classPathResource = new ClassPathResource("doc\\interview.doc"); // 组装数据 final Document doc; try (InputStream inputStream = classPathResource.getInputStream(); ServletOutputStream outputStream = response.getOutputStream()) { // 文件名称 String fileName = URLEncoder.encode("帅锅的简历.pdf", CharsetUtil.UTF_8); response.reset(); response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); response.setHeader("Access-Control-Allow-Origin", "*"); response.setContentType("application/octet-stream;charset=UTF-8"); // 将输出流转为doc doc = new Document(inputStream); // doc构建 DocumentBuilder builder = new DocumentBuilder(doc); // 定位书签地位 builder.moveToBookmark("AVATAR"); // 插入图片 builder.insertImage("https://portrait.gitee.com/uploads/avatars/user/491/1474070_javadog-net_1616995139.png!avatar30"); // 定位LANGUAGE_LEVEL4书签地位 builder.moveToBookmark("LANGUAGE_LEVEL4"); // 设置字符名称 builder.getFont().setName("Wingdings"); // 设置字符大小 builder.getFont().setSize(14); // 对号字符 builder.write("\uF0FE"); // 定位LANGUAGE_LEVEL6书签地位 builder.moveToBookmark("LANGUAGE_LEVEL6"); // 设置字符名称 builder.getFont().setName("Wingdings"); builder.getFont().setSize(20); builder.write("□"); doc.updateFields(); final ReportingEngine engine = new ReportingEngine(); // 将数据填充至模板 engine.buildReport(doc, getInterviewData(), "data"); // 转pdf doc.save(outputStream, SaveFormat.PDF); } catch (Exception e) { log.error("生成报告异样,异样信息:{}", e.getMessage(), e); e.printStackTrace(); } } private Interview getInterviewData(){ Interview interview = new Interview(); this.getBaseInfo(interview); this.getEducations(interview); this.getWorkExperiences(interview); return interview; } /** * @Description: 组装根本数据 * @Param: [interview] * @return: [apose.javadog.net.entity.Interview] * @Author: hdx * @Date: 2022/5/10 15:39 */ private void getBaseInfo(Interview interview){ // 根本数据 BaseInfo baseInfo = new BaseInfo(); List<String> listStr = new ArrayList<>(); listStr.add("后端技术栈:有较好的Java根底,相熟SpringBoot,SpringCloud,springCloud Alibaba等支流技术,Redis内存数据库、RocketMq、dubbo等,相熟JUC多线程"); listStr.add("后端模板引擎:thymeleaf、volocity"); listStr.add("前端技术栈:熟练掌握ES5/ES6/、NodeJs、Vue、React、Webpack、gulp"); listStr.add("其余技术栈: 相熟python+selenium、electron"); baseInfo.setName("狗哥") .setBirth("1993年5月14日") .setHeight("180") .setWeight("70") .setNation("汉") .setSex("男") .setNativePlace("济南") .setMarriage("已婚") .setSpecialtys(listStr); interview.setBaseInfo(baseInfo); } /** * @Description: 组装教育经验 * @Param: [interview] * @return: [apose.javadog.net.entity.Interview] * @Author: hdx * @Date: 2022/5/10 15:40 */ private void getEducations(Interview interview){ // 高中 List<Education> educations = new ArrayList<>(); Education education = new Education(); education.setStartEndTime("2009-2012") .setSchool("山东省试验中学") .setFullTime("是") .setProfessional("文科") .setEducationalForm("普高"); educations.add(education); // 大学 Education educationUniversity = new Education(); educationUniversity.setStartEndTime("2012-2016") .setSchool("青岛农业大学") .setFullTime("是") .setProfessional("计算机科学与技术") .setEducationalForm("本科"); educations.add(educationUniversity); interview.setEducations(educations); } /** * @Description: 组装工作经验 * @Param: [interview] * @return: [apose.javadog.net.entity.Interview] * @Author: hdx * @Date: 2022/5/10 15:40 */ private void getWorkExperiences(Interview interview){ // 工作记录 List<WorkExperience> workExperiences = new ArrayList<>(); WorkExperience workExperience = new WorkExperience(); workExperience.setStartEndTime("2009-2012") .setWorkUnit("青岛XXX") .setPosition("开发") .setResignation("有更好的学习空间,向医疗畛域拓展学习纬度"); workExperiences.add(workExperience); interview.setWorkExperiences(workExperiences); }}前端1.下载对应的依赖包npm install2.在vue.config.js中配置代理const { defineConfig } = require('@vue/cli-service')module.exports = defineConfig({ devServer: { port: 1026, proxy: { '/': { target: 'http://localhost:8082', //申请本地 须要ipps-boot后盾我的项目 ws: false, changeOrigin: true } } }})npm install3.在main.js引入所需插件import Vue from 'vue'import App from './App.vue'Vue.config.productionTip = falseimport axios from 'axios'Vue.prototype.$http = axiosimport ElementUI from 'element-ui';import 'element-ui/lib/theme-chalk/index.css';Vue.use(ElementUI);new Vue({ render: h => h(App),}).$mount('#app')4.页面引入vue-pdf组件 <pdf v-if="showPdf" ref="pdf" :src="pdfUrl" :page="currentPage" @num-pages="pageCount=$event" @page-loaded="currentPage=$event" @loaded="loadPdfHandler"> </pdf>5.页面中应用axios调取接口获取数据留神responseType类型为blob ...

March 21, 2023 · 4 min · jiezi

关于java:为什么Tomcat架构要这么设计这篇文章告诉你答案

Tomcat体系架构 Tomcat我的项目构造 bin目录bin目录次要是用来寄存tomcat的命令,次要有两大类,一类是以.sh结尾的(linux命令),另一类是以.bat结尾的(windows命令)。 很多环境变量的设置都在此处,例如能够设置JDK门路、tomcat门路 startup文件:次要是查看catalina.bat/sh 执行所需环境,并调用catalina.bat 批处理文件。启动tomcat。catalina文件:真正启动Tomcat文件,能够在外面设置jvm参数。前面性能调优会重点讲shutdown文件:敞开Tomcat脚本version.sh、startup.sh、shutdown.sh、configtest.sh都是对catalina.sh的包装,内容大同小异,差别在于性能介绍和调用catalina.sh时的参数不同。Version:查看以后tomcat的版本号,Configtest:校验tomcat配置文件server.xml的格局、内容等是否非法、正确。Service:装置tomcat服务,可用net start tomcat 启动conf目录conf目录次要是用来寄存tomcat的一些配置文件。 server.xml:能够设置端口号、设置域名或IP、默认加载的我的项目、申请编码web.xml:能够设置tomcat反对的文件类型context.xml:能够用来配置数据源之类的tomcat-users.xml:用来配置管理tomcat的用户与权限在Catalina目录下能够设置默认加载的我的项目server.xmlCOPY<?xml version="1.0" encoding="UTF-8"?><!-- Server代表一个 Tomcat 实例。能够蕴含一个或多个 Services,其中每个Service都有本人的Engines和Connectors。 port="8005"指定一个端口,这个端口负责监听敞开tomcat的申请 --><Server port="8005" shutdown="SHUTDOWN"><!-- 监听器 --><Listener className="org.apache.catalina.startup.VersionLoggerListener" /><Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /><Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /><Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /><Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /><!-- 全局命名资源,定义了UserDatabase的一个JNDI(java命名和目录接口),通过pathname的文件失去一个用户受权的内存数据库 --><GlobalNamingResources><Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /></GlobalNamingResources><!-- Service它蕴含一个<Engine>元素,以及一个或多个<Connector>,这些Connector元素共享用同一个Engine元素 --><Service name="Catalina"><!-- 每个Service能够有一个或多个连接器<Connector>元素, 第一个Connector元素定义了一个HTTP Connector,它通过8080端口接管HTTP申请;第二个Connector元素定 义了一个JD Connector,它通过8009端口接管由其它服务器转发过去的申请. --><Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /><Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /><!-- 每个Service只能有一个<Engine>元素 --><Engine name="Catalina" defaultHost="localhost"><Realm className="org.apache.catalina.realm.LockOutRealm"><Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/></Realm><!-- 默认host配置,有几个域名就配置几个Host,然而这种只能是同一个端口号 --><Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <!-- Tomcat的拜访日志,默认能够敞开掉它,它会在logs文件里生成localhost_access_log的拜访日志 --><Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /></Host><Host name="www.hzg.com" appBase="webapps" unpackWARs="true" autoDeploy="true"><Context path="" docBase="/myweb1" /><Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="hzg_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /></Host></Engine></Service></Server>patter解释无效的日志格局模式能够参见上面内容,如下字符串,其对应的信息由指定的响应内容取代:%a - 近程IP地址%A - 本地IP地址%b - 发送的字节数,不包含HTTP头,或“ - ”如果没有发送字节%B - 发送的字节数,不包含HTTP头%h - 近程主机名%H - 申请协定%l (小写的L)- 近程逻辑从identd的用户名(总是返回’ - ‘)%m - 申请办法%p - 本地端口%q - 查问字符串(在后面加上一个“?”如果它存在,否则是一个空字符串%r - 第一行的要求%s - 响应的HTTP状态代码%S - 用户会话ID%t - 日期和工夫,在通用日志格局%u - 近程用户身份验证%U - 申请的URL门路%v - 本地服务器名%D - 解决申请的工夫(以毫秒为单位)web.xmlTomcat中所有利用默认的部署形容文件,次要定义了根底的Servlet和MIME映射(mime-mapping 文件类型,其实就是Tomcat解决的文件类型),如果部署的利用中不蕴含Web.xml,那么Tomcat将应用此文件初始化部署形容,反之,Tomcat会在启动时将默认形容与定义形容配置进行合并。 ...

March 21, 2023 · 2 min · jiezi

关于java:美团某动态线程池框架是官方开源的么

最近,有很多同学在微信上问我这么一个问题: Hippo4j 动静线程池框架是美团开源的么? 相似于这样的问题还挺多,在这里对立回复下: 美团官网并没有开源任何对于动静线程池的框架。 美团官网对于对动静线程池框架的惟一产出,来自于大家基本上看过或者有印象的一篇博客。 Java线程池实现原理及其在美团业务中的实际 如果不理解动静线程池概念的同学能够深刻理解下。文章深入浅出,讲的很透彻,同时也是美团罪受欢迎的文章之一。 在此之后,美团官网并没有基于动静线程池这个 IDEA 做任何的产出。不过,开源社区基于美团这篇文章做了很多开源框架,比方笔者开源的 Hippo4j,以及另外一位开源作者 DynamicTP 框架等。 说完 Hippo4j 是否美团动静线程池开源后,接下来和大家聊两件和平时工作无关并且有意思的事。 公众号:马丁玩编程,关注回复:材料,支付后端技术专家成长手册。 美团动静线程池框架为什么没有开源依据我的想法,如果当初美团推出动静线程池概念后,趁势推出一款开源框架,必定会“爆火”。 毕竟,对于工作这么多年的开发来说,谁的线上环境还没有被线程池“坑”过呢。 然而,理论却没有依照这种构想倒退,我就找了在美团工作的敌人聊了聊,上面依据我的理解说下是怎么回事。 1. 依赖办公软件大象动静参数告诉和线程池运行中报警,都须要通过办公通信软件或者邮件进行告诉。 通过下面提到的美团动静线程池文章可知,在线程池变更告诉和过载告警性能上,依赖了美团办公通信软件大象。 <img src="https://images-machen.oss-cn-beijing.aliyuncs.com/image-20230214214820444.png" style="zoom:50%;" /> 如果要开源,如何进行革新呢? 基于告诉报警计划,其实很好解决,形象进来一个告诉接口以及外围参数,并提供 SPI 加载形式,基本上就能实现开源兼容适配。 2. 依赖监控工具 Cat美团线程池反对查看外部工作级别的执行状况,进行细粒度工作级别监控。 外围原理是通过 Cat Transaction 打点进行的反对,下图表就是从 Cat 上汇总进行展现。 Cat 这种依赖,不太好替换,因为会对原有业务代码进行侵入。如果说开源计划的话,可能就须要就义一部分功能性或者针对动静线程池框架底层实现这一性能。 3. 依赖音讯队列 Kafka通过美团文章中看到线程池框架应用了 Kafka 音讯队列,这里暂且当一个存疑点,动静线程池中哪局部业务须要应用 Kafka 呢? 如果说应用动静线程池性能,还须要依赖音讯队列,这可能对于大部分场景来说是说不通用的。 如果要进行开源,我的倡议和想法是将这里设置为可替换项。也就是说默认不反对 MQ 性能,同时对市场上支流 MQ 进行适配。如果客户端我的项目想用的话,可依据我的项目理论抉择。 比拟常见的是 Seata 和 SkyWalking 的做法,以 SkyWalking 举例,链路数据存储反对 H2、MySQL、ElasticSearch 等数据库,让用户依据场景以及服务体量灵便抉择。 4. 动静线程池是监控体系中的“小”模块之前有和美团的一位技术敌人沟通过,为什么美团的动静线程池框架没有开源进去? 他给我的回复是,动静线程池框架只是美团监控体系下一个“小”模块。 而且,依据不可靠消息,仿佛外部该框架的实现不止一个,如果有美团的哥们看到能够评论下。 ...

March 20, 2023 · 1 min · jiezi

关于java:初窥函数式接口不会取标题没有噱头全是干货

什么是函数式接口援用两个中央的定义来尝试地解答下什么是函数式接口 An Interface that contains exactly one abstract method is known as functional interface. It can have any number of default, static methods but can contain only one abstract method. It can also declare methods of object class. Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces. It is a new feature in Java, which helps to achieve functional programming approach. 下面是javapoint)网站的定义,总结下几点 只能有一个形象函数的接口能够有任一多默认的动态的办法能够有Object类曾经申明的办法,因为所有的类都是Object的子类An informative annotation type used to indicate that an interface type declaration is intended to be a functional interface as defined by the Java Language Specification. Conceptually, a functional interface has exactly one abstract method. Since default methods have an implementation, they are not abstract. If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface's abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere. ...

March 19, 2023 · 2 min · jiezi

关于java:深入理解Spring的事件通知机制

 Spring作为一个优良的企业级利用开发框架,不仅提供了泛滥的功能模块和工具,还提供了一种灵便高效的事件告诉机制,用于解决组件之间的松耦合通信。本文将具体介绍Spring的事件告诉机制的原理、应用办法以及示例,心愿对大家深刻了解Spring框架有所帮忙。 事件告诉机制的原理 Spring的事件告诉机制是基于观察者模式实现的,次要分为三个外围元素:事件、监听器和事件公布器。 事件(ApplicationEvent) Spring的事件是围绕ApplicationEvent类实现的,该类继承了JDK提供的EventObject抽象类,能够用来示意事件的数据。在Spring中,如果要自定义事件,只须要继承ApplicationEvent类即可,并在子类中增加自定义的属性或办法。例如,能够定义一个MyEvent类来示意自定义事件,它可能蕴含一些用于解决的数据。监听器(ApplicationListener) 在Spring中,能够通过实现ApplicationListener接口来定义事件监听器,ApplicationListener接口只定义了一个办法onApplicationEvent,该办法会在某个事件产生时被调用,能够在其中处理事件内容。除此之外,Spring还提供了一个更简便的办法,就是应用@EventListener注解,只须要在实现办法上加上该注解即可。事件公布器(ApplicationContext) Spring容器是事件的发布者,是指在ApplicationContext中,如果某个事件产生了,容器会主动调用对应的监听器。具体实现是通过一个事件播送器实现的。其外围是应用了Spring的事件公布机制ApplicationEventMulticaster类,它负责保护所有的监听器,并通过事件播送器将事件告诉到所有的监听器中。 在ApplicationContext启动时,会主动创立该类的实例,并注册到容器中作为一个单例bean,在容器敞开时销毁。总的来说,Spring事件告诉机制通过定义事件、监听器和事件公布器来实现松耦合的通信,升高了组件之间的依赖性,使得应用程序更加灵便。 事件告诉机制的应用办法 Spring事件的应用办法非常简单,能够通过下列三个步骤来实现: 定义事件类:开发人员能够自定义事件对象,继承Spring的ApplicationEvent类,实现事件的结构和解决逻辑。定义事件监听器:开发人员能够通过实现ApplicationListener接口,并在对应类中定义onApplicationEvent办法解决接管的事件,实现事件监听器的性能。注册监听器:开发人员能够通过在配置文件中配置或应用@EventListener注解的形式向Spring容器注册事件监听器,以便Spring治理监听器的生命周期以及主动进应用。以下是一个简略的 Spring 事件告诉机制的代码示例: 首先定义事件类 MyEvent.java: import org.springframework.context.ApplicationEvent;public class MyEvent extends ApplicationEvent { private String message; public MyEvent(Object source, String message) { super(source); this.message = message; } public String getMessage() { return message; }}定义事件监听器 MyListener.java: import org.springframework.context.ApplicationListener;@Componentpublic class MyListener implements ApplicationListener<MyEvent> { @Override public void onApplicationEvent(MyEvent myEvent) { System.out.println("Received MyEvent: " + myEvent.getMessage()); }}定义事件公布类 MyPublisher.java: import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationEventPublisher;import org.springframework.stereotype.Component;@Componentpublic class MyPublisher { @Autowired private ApplicationEventPublisher publisher; public void publish() { MyEvent event = new MyEvent(this, "Hello, world!"); publisher.publishEvent(event); }} 当Spring运行后,在任何中央调用myPublisher.publish(),将输入 "Received MyEvent: Hello, world!",示意自定义事件已胜利被监听器接管。 ...

March 19, 2023 · 1 min · jiezi

关于java:JAVAJDK11新特性个人分析

历史背景2018年9 月 26 日,Oracle 官网发表 Java 11 正式公布。这个版本中一共蕴含 17 个 JEP(JDK Enhancement Proposals,JDK 加强提案)。 JDK 11 是一个长期反对版本(LTS, Long-Term-Support),在编写本文的工夫节点下和JDK17一样被用于编写我的项目代码的支流版本。 本文联合了各方材料整顿出JDK11的新个性,工作上应用高版本JDK的机会的确不多,然而本人体验的过程中的确切身体会到JDK降级的益处。 降级JDK11的意义大量的新个性、Bug 修复,例如,容器环境反对,GC 等根底畛域的加强。平安协定更新,比方废除TLS1.2中不平安的加密算法,局部反对TLS1.3协定。JVM的零老本优化。划时代的垃圾收集器ZGC,要害目标是实现GC工夫不超过10ms。G1垃圾收集器的收费降级 并行的 Full GC(JDK11之前Oracle没有思考过G1须要并行Full GC)疾速的 CardTable 扫描自适应的堆占用比例调整(IHOP)在并发标记阶段的类型卸载JVM自带工具加强 JEP 328: Flight Recorder(JFR),商用版工具JFR转为开源。JEP 331: Low-Overhead Heap Profiling 实现底层老本堆剖析JVM扩大TLS协定精简 欠缺Java规范HTTP类库上的扩大能力。JEP 332: Transport Layer Security (TLS) 1.3,齐全反对TLS 1.3(协定局部局部反对,加密算法局部根本满足要求)。HTTP/2 Client API 欠缺了Java语言本身进行Http Client的能力等同于把HttpClient官网化(好听点就是搬来了)<s>只有不写作者,谁也不晓得本人写的还是抄的谁的</s>废除Nashorn JavaScript引擎 实际上是全力推动Graal VM虚拟机的开发。降级内容上面就是依据"JEP(JDK Enhancement Proposals,JDK 加强提案)"进行介绍。对于原始的提案名称,这里放到了“附录”局部。 新个性JEP 309: Dynamic Class-File Constants 类文件新构造属于JVM层面的优化,简略理解即可。上面是收集到的的一些国外网站的解释: Dynamic class-file constantsJEP 309 extends the existing Java class-file format, creating CONSTANT_Dynamic. This is a JVM feature and doesn't depend on the higher software layers. The loading of CONSTANT_Dynamic delegates the creation of a bootstrap method. When comparing it to the invokedynamic call, you will see how it delegates linking to a bootstrap method.One of the main goals of dynamic class-file constants is to make it simple to create new forms of materializable class-file constants, which provides language designers and compiler implementers with broader options for expressivity and performance. This is achieved by creating a new constant pool form that can be parameterized using a bootstrap method with static arguments.上面是简略概括和理解: ...

March 19, 2023 · 10 min · jiezi

关于java:周期性任务线程池-ScheduledThreadPoolExecutor-DelayedWorkQueue

ScheduledThreadPoolExecutor是ThreadPoolExecutor的扩大类,用来实现提早执行的工作、或者周期性执行的工作。 一般来讲,周期性工作或者定时工作蕴含两大组件:一个是执行工作的线程池,一个是存储工作的存储器。还记得Quartz吗?企业级定时工作框架,最重要的内容其实也是这两局部:SimpleThreadPool和JobStore。 ScheduledThreadPoolExecutor也不例外,由线程池和工作队列组成。线程池继承自ThreadPoolExecutor,工作队列DelayedWorkQueue,理解了ThreadPoolExecutor和DelayedWorkQueue,也就根本理解了ScheduledThreadPoolExecutor。 此外,ScheduledThreadPoolExecutor的非凡之处还在于他所执行的工作必须是ScheduledFutureTask,ScheduledFutureTask是“将来要执行的工作”,“将来”由delay指定。即便是通过ScheduledThreadPoolExecutor提交“立刻”而不是“将来”要执行的工作,也要通过指定delay时长为0的ScheduledFutureTask来提交。ScheduledFutureTask工作提交之后退出阻塞队列DelayedWorkQueue期待调度。 ScheduledThreadPoolExecutor的创立提供了四个构造方法,都是通过调用父类ThreadPoolExecutor的构造方法实现ScheduledThreadPoolExecutor对象的创立: public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue()); }public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory); }public ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), handler); }public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory, handler); }corePoolSize通过构造方法的参数指定,maximumPoolSize在构造方法中都固定设置为Integer.MAX_VALUE,也就是不受限制。 keepAliveTime设置为0,前面咱们会晓得其实ScheduledThreadPoolExecutor的线程数不会超过corePoolSize,而且如果allowCoreThreadTimeOut放弃默认的话(false),那其实这个keepAliveTime是没有意义的。 四个构造方法均设置阻塞队列为new DelayedWorkQueue(),即仅反对DelayedWorkQueue。 ScheduledThreadPoolExecutor的线程池治理ScheduledThreadPoolExecutor是ThreadPoolExecutor的扩大,线程池治理局部没有做扩大,保留了ThreadPoolExecutor的原有性能。 每次工作退出队列后会调用ensurePrestart(ThreadPoolExecutor实现)办法创立并启动一个线程,ThreadPoolExecutor的ensurePrestart办法: void ensurePrestart() { int wc = workerCountOf(ctl.get()); if (wc < corePoolSize) addWorker(null, true); else if (wc == 0) addWorker(null, false); }如果线程数小于corePoolSize则调用addWorker(null, true)创立外围线程线程,否则如果线程数为0(设置corePoolSize=0则可能走到这个分支)创立非核心线程。 ...

March 19, 2023 · 2 min · jiezi

关于java:计算机毕业设计基于-SpringBoot-的大学生体质测试管理系统附源码和论文

简介本次设计工作是要设计一个大学生体质测试管理系统,通过这个零碎可能满足大学生体质测试管理系统性能。零碎的次要性能包含首页、集体核心、用户治理、老师治理、体质测试治理、测试报告治理、测试问题治理、留言板、系统管理等性能。 管理员能够依据零碎给定的账号进行登录,登录后能够进入大学生体质测试管理系统对大学生体质测试所有模块进行治理。包含查看和批改本人的个人信息以及登录明码,用户信息等。 该零碎为每一个用户都调配了一个用户账号,用户通过账号的登录能够在零碎中查看大学生体质测试信息及对个人信息进行批改等性能 效果图零碎首页模块大学生体质测试管理系统,在零碎首页能够查看首页、体质测试、布告资讯、留言板、集体核心、后盾治理等内容进行具体操作,如图5-1所示。 体质测试,在体质测试页面能够查看测试名称、测试编号、测试阐明、测试文件、公布日期、老师工号等内容进行测试等操作,如图5-2所示。 用户注册,通过填写用户账号、明码、确认明码、用户姓名、班级、联系方式等内容进行注册等操作,如图5-3所示。 集体核心,在集体核心页面通过填写用户账号、明码、用户姓名、性别、班级、联系方式、图片等内容进行更新信息等操作;如图5-4所示。 管理员功能模块管理员登录,管理员通过输出用户,明码,抉择角色等信息进行零碎登录,如图5-5所示。 管理员登录进入大学生体质测试管理系统能够查看首页、集体核心、用户治理、老师治理、体质测试治理、测试报告治理、测试问题治理、留言板、系统管理等内容进行具体操作,如图5-6所示。 用户治理,在用户治理页面能够对索引、用户账号、用户姓名、性别、班级、联系方式、头像等内容详情、批改或删除等操作,如图5-7所示。 体质测试治理,在体质测试治理页面能够对索引、测试编号、测试名称、测试文件、图片、公布日期、老师工号、老师姓名等内容进行详情、批改或删除等操作,如图5-8所示。 老师治理,在老师治理页面能够对老师工号、老师姓名、性别、职称、联系电话、头像等内容进行详情、批改或删除等操作,如图5-9所示。 测试报告治理,在测试报告治理页面能够对索引、测试编号、测试名称、老师工号、老师姓名、报告文件、提交日期、用户账号、用户姓名、班级等内容进行详情、批改或删除等具体的操作,如图5-10所示。 测试问题治理,在测试问题治理页面能够对索引、测试编号、、测试名称、老师工号、老师姓名、测试评分、测试评级、评分工夫、用户账号、用户姓名、班级等内容进行详情、批改或删除等具体的操作,如图5-11所示。 留言板,在留言板页面能够对索引、用户名、留言内容、留言图片、回复内容、回复图片等内容进行详情、批改、回复或删除等操作,如图5-12所示。 系统管理,在布告资讯页面中能够对索引、题目、图片等内容进行详情、批改或删除等操作,也能够对轮播图治理进行相应的操作,如图5-13所示。 用户功能模块用户进入大学生体质测试管理系统能够查看首页、集体核心、测试报告治理、测试问题治理等内容进行具体操作,如图5-14所示。 测试报告治理,在测试报告治理页面中能够对索引、测试编号、测试名称、老师工号、老师姓名、报告文件、提交日期、用户账号、用户姓名、班级等内容进行详情或删除等具体的操作,如图5-15所示。 老师功能模块老师注册,通过填写老师工号、明码、确认明码、老师姓名、职称、联系电话等内容进行注册,如图5-16所示。 进入老师页面中能够查看首页、集体核心、体质测试治理、测试报告治理、测试问题治理等内容进行相应的操作,如图5-17所示。 体质测试治理,在体质测试治理页面中能够对索引、测试编号、测试名称、测试文件、图片、公布日期、老师工号、老师姓名等内容进行具体等操作,如图5-18所示。 测试报告治理,在测试报告治理页面中能够对索引、测试编号、测试名称、老师工号、老师姓名、报告文件、提交日期、用户账号、用户姓名、班级等内容进行具体等操作,如图5-19所示。 局部源码/** * 测试报告 * * @author * @email * @date 2022-03-11 14:04:32 */public interface CeshibaogaoDao extends BaseMapper<CeshibaogaoEntity> { List<CeshibaogaoVO> selectListVO(@Param("ew") Wrapper<CeshibaogaoEntity> wrapper); CeshibaogaoVO selectVO(@Param("ew") Wrapper<CeshibaogaoEntity> wrapper); List<CeshibaogaoView> selectListView(@Param("ew") Wrapper<CeshibaogaoEntity> wrapper); List<CeshibaogaoView> selectListView(Pagination page,@Param("ew") Wrapper<CeshibaogaoEntity> wrapper); CeshibaogaoView selectView(@Param("ew") Wrapper<CeshibaogaoEntity> wrapper); }源码下载地址大学生体质测试管理系统包含前后端的所有代码,还有论文,如果有需要的话,能够点击这里征询 ...

March 17, 2023 · 1 min · jiezi

关于java:chatgpt周刊

一周资讯OpenAI颁布GPT-4:更强更牢靠 可在考试中超过90%的人类3月14日),人工智能钻研公司OpenAI颁布了其大型语言模型的最新版本——GPT-4。该公司示意,GPT-4在许多业余测试中体现出超过绝大多数人类的程度。在外部评估中,相较于GPT-3.5,GPT-4产生正确回应的可能性要高出40%。GPT-4 实现了以下几个方面的飞跃式晋升:弱小的识图能力;文字输出限度晋升至 2.5 万字;答复准确性显著进步;可能生成歌词、创意文本,实现格调变动。GPT-4在模仿律师资格考试的问题在考生中排名前10%左右,在SAT浏览考试中排名前7%左右,在SAT数学考试中排名前11%左右。ChatGPT+Plus的成员能够应用的GPT-4版本。 Meta发表推出其大型语言模型LLaMA(Large Language Model Meta AI)LLaMA旨在帮忙钻研人员推动工作,并在文本生成、问题答复、书面材料总结以及更简单的工作(如主动数学定理证实和蛋白质构造预测)方面具备微小的后劲。Meta目前提供四种参数大小的LLaMA模型:7B、33B、65B和650B。所有LLaMA模型都至多通过了1T(1万亿)个tokens的训练,这比其余同样大小的模型要多得多。在一些测试中,130B参数的LLaMA模型的性能超过了1750B参数的GPT-3,并且能够在单个GPU上运行。650B参数的LLaMA模型能够与700B参数的Chinchilla和5400B参数的PaLM相媲美。 微软称已破费数亿美元为OpenAI组装超级计算机 用于开发ChatGPT微软走漏,此前公司已帮忙OpenAI组装一台AI超级计算机,由此OpenAI得以开发出ChatGPT。这台超算应用了数万个英伟达A100芯片,这使得OpenAI可能训练越来越弱小的AI模型。微软云计算和AI业务执行副总裁Scott Guthrie暗示,该我的项目破费数亿美元。 微软高管走漏新必应搜索引擎曾经在应用GPT-4微软公司副总裁兼消费者首席营销官尤素福-迈赫迪在布告中写道:"咱们很快乐地确认,新的必应正在GPT-4上运行,咱们曾经为搜寻进行了定制。如果你在过来五周的任何时候应用过新必应预览版,你曾经体验到了这种弱小模式的晚期版本。 微软必应 ChatGPT 聊天每日次数限度扩充至 150 次微软公司副总裁兼消费者首席营销官 Yusuf Mehdi 示意,每日聊天次数限度曾经从 120 次扩充到 150 次。他补充说,每个会话的轮次限度也曾经从 10 改为 15。 商汤科技公布多模态通用大模型“书生 2.5”:领有 30 亿参数,反对问答、识图、以文生图等书生 2.5”的图文跨模态凋谢工作解决能力可为主动驾驶、机器人等通用场景工作提供高效精准的感知和理解能力反对。“书生 2.5”同时具备 AIGC“以文生图”的能力。可依据用户提出的文本创作需要,利用扩散模型生成算法,生成高质量、天然的写实图像。“书生 2.5”还可依据文本疾速检索出视觉内容。 谷歌发表凋谢其人工智能语言模型PaLM API 挑战OpenAI谷歌公布博客文章发表,正式凋谢其PaLM是一个大型语言模型API。这家搜寻巨头在推出PaLM的API的同时推出了一些人工智能企业工具,称其将帮忙企业「从简略的自然语言提醒中生成文本、图像、代码、视频、音频等」。开发人员能够通过API拜访谷歌的根底模型,并能够应用开箱即用的模板,在几分钟或几小时内启动生成式应用程序的创立. 媲美 ChatGPT,由前 OpenAI 员工开办的 Anthropic 公司推出聊天机器人 ClaudeAnthropic 公司由多位前 OpenAI 员工独特创建,公司于明天推出了 Claude,这是一款能够媲美 ChatGPT 的聊天机器人。Claude 能够执行跨文档搜寻、总结、写作和编码,以及答复无关特定主题的问题等工作。 百度正式推出大语言模型“文心一言”百度于北京总部召开新闻发布会,主题围绕新一代大语言模型、生成式 AI 产品文心一言。百度正式推出大语言模型文心一言,并展现了文心一言在多个应用场景中的综合能力。文心一言某种程度上具备了对人类用意的理解能力。文心一言还具备了肯定的思维能力,可能学会数学推演及逻辑推理等绝对简单工作。文心一言甚至可能生成四川话等方言语音;文心一言的视频生成能力则因老本较高,现阶段还未对所有用户凋谢,将来会逐渐接入。 开源我的项目【dromara/ChatGPT】ChatGPT JetBrains 开源插件我的项目是一个反对在 JetBrains 系列 IDE 上运行的 ChatGPT 的插件。集成到IDE当前,能够可查代码,可问问题,可查找bug, 可写测试case 在开发方面一个很好的助手。目前插件曾经有 127K 的下载量 ...

March 17, 2023 · 1 min · jiezi

关于java:VS-Code-将推出更多-AI-功能给-Java-开发者

大家好,欢送来到咱们的二月更新!咱们将为您带来与 JUnit 5 并行测试相干的新性能以及用于 Spring Boot Dashboard 的过滤性能。另外,OpenAI 和 ChatGPT 是最近的热点,所以在 GitHub Copilot 方面也有一些令人激动的音讯,让咱们开始吧! GitHub Copilot AI 技术升级,目前已生成 61% 的 Java 代码最近发表在 Visual Studio Code 杂志上的一篇文章中走漏,GitHub Copilot 曾经在应用它的编辑器中生成了 61% 的 Java 代码(在所有编程语言中的均匀数字为46%)。只管 Java 是一种绝对啰嗦的编程语言,但它依然表明 Java 开发人员正在拥抱 GitHub Copilot 和 AI 技术的力量。除了数据方面的剖析之后,这篇文章还提到了 GitHub Copilot 产品方面的晋升,其中包含了算法的增强和平安性能的改善等等。 随着 Microsoft 和 OpenAI 之间的扩大合作伙伴关系,Visual Studio Code 对于 Java 开发者也将领有更多令人兴奋 AI 相干的性能,来提供开发者的编码效率,请期待2023年咱们的更新。 JUnit 5 并行测试反对JUnit 5 是 Java 开发人员的风行测试框架,以其对单元、集成和功能测试的全面反对而闻名。JUnit 5 的重大改良之一是它可能并行执行测试,从而使测试更快、更高效。并行执行将测试用例散布在多个线程中,容许它们同时运行,并比程序运行测试更快地交付后果。 在咱们的最新版本中,咱们在 Visual Studio Code Java 中反对了并行测试性能。要应用此性能,您须要应用以下行设置 junit-platform.properties 文件: ...

March 17, 2023 · 1 min · jiezi

关于java:Java-枚举实现单例模式线程安全又优雅

起源:https://liuchenyang0515.blog.csdn.net/article/details/121049426 1. 双重校验锁单例(DCL)public class Singleton { private static volatile Singleton singleton; private Singleton(){ } public static Singleton getInstance(){ if (singleton == null){ synchronized (Singleton.class){ if (singleton == null){ singleton = new Singleton(); } } } return singleton; }}这种DCL写法的长处:不仅线程平安,而且提早加载。 1.1 为什么要double check?去掉第二次check行不行?当然不行,当2个线程同时执行getInstance办法时,都会执行第一个if判断,因为锁机制的存在,会有一个线程先进入同步语句,而另一个线程期待,当第一个线程执行了new Singleton()之后,就会退出synchronized的爱护区域,这时如果没有第二重if判断,那么第二个线程也会创立一个实例,这就毁坏了单例。 1.2 singleton为什么要加上volatile关键字?次要起因就是 singleton = new Singleton();不是一个原子操作。 在JVM中,这句语句至多做了3件事 给Singleton的实例分配内存空间;调用Singleton()的构造函数,初始化成员字段;将singleton指向调配的内存空间(此时singleton就不是null了)因为存在着指令重排序的优化,第2、3步的程序是不能保障的,最初的执行程序可能是1-2-3,也可能是1-3-2,如果执行程序是1-3-2,咱们看看会呈现什么问题 尽管singleton不是null,然而指向的空间并没有初始化,还是会报错,这就是DCL生效的问题,这种问题难以跟踪难以重现可能会暗藏很久。 JDK1.5之前JMM(Java Memory Model,即Java内存模型)中的Cache、寄存器到主存的回写规定,下面第二第三的程序无奈保障。JDK1.5之后,SUN官网调整了JVM,具体化了volatile关键字,private static volatile Singleton singleton;只有加上volatile,就能够保障每次从主存中读取(这波及到CPU缓存一致性问题,不在本文探讨范畴内,有趣味自行搜寻),也能够避免指令重排序的产生,防止拿到未实现初始化的对象。 简略讲,volatile次要就是限度JIT编译器优化,编译器优化罕用的办法有: 将内存变量缓存到寄存器;调整指令程序充分利用CPU指令流水线,常见的是从新排序读写指令。如果没有volatile关键字,则编译器可能优化读取,应用寄存器中的缓存值,如果这个变量由别的线程更新了的话,将呈现理论值和读取的值不统一。应用了volatile后,编译器读取的时候跳过缓存,间接在内存中的理论地位读变量,写的时候告诉其余缓存更新,这就是所谓的保障内存可见性,并且应用volatile还能禁止指令重排序。 public volatile int a = 11;......int c = 6;c = a;// 执行这一句的时候,在高并发状况下,a如果被批改为22,那么c会被赋值为22而不是11//如果a不被volatile润饰,c有小概率被赋值为11,因为c取寄存器的缓存正本11还没来得及更新2. 动态外部类单例public class Singleton{ private Singleton(){} private static class SingletonInstance { private static Singleton singleton = new Singleton(); } public static Singleton getInstance(){ return SingletonInstance.singleton; }}与饿汉式的区别就在于,类加载的时候,这里并不会实例化对象,只有调用getInstance办法才会实例化对象。 ...

March 17, 2023 · 4 min · jiezi

关于java:深入了解Java-JIT编译器原理与性能优化

JIT 编译器的定义和作用Java JIT(Just-In-Time)编译器是Java虚拟机(JVM)中的一个组件,它负责将 Java 字节码转换为本地机器代码,以进步Java应用程序的性能。 在 Java 运行时,JIT编译器在程序运行时动静地将Java字节码编译成本地机器代码,这样能够防止每次执行时都解释字节码的开销。JIT编译器能够依据程序的执行状况和环境来做出优化决策,例如将频繁执行的代码编译成本地代码以进步执行速度,或者将不会被执行的代码从编译过程中删除以节俭资源。 JIT编译器的作用是优化 Java 程序的性能,缩小执行工夫和资源耗费。它能够提供以下优化: 提早编译:只有在代码被执行屡次后才会被编译,从而防止对不罕用的代码进行不必要的编译。编译器优化:JIT编译器能够对代码进行优化,例如打消无用的计算、缩小内存拜访、应用更疾速的算法等,从而进步程序的执行速度和效率。动静编译:JIT编译器能够依据程序的执行状况来动静生成代码,以适应不同的执行环境和需要。JIT编译器是Java虚拟机中十分重要的组件,它能够进步Java程序的性能和效率,从而使得Java成为了一种被宽泛应用的高性能编程语言。 JIT 编译器与解释器的区别和优缺点JIT编译器和解释器都是将程序代码翻译成机器指令的工具,但它们有着不同的工作形式和优缺点。 工作形式:解释器将程序代码逐行解释并执行,而JIT编译器会将程序代码动静地编译成本地机器代码后再执行。长处:解释器的长处在于实现简略,不须要额定的编译步骤,可能疾速地启动和执行程序。而JIT编译器的长处在于可能将代码编译成本地机器代码,从而进步程序的执行速度和效率。毛病:解释器的毛病在于每次执行程序时都须要逐行解释,效率较低。而JIT编译器的毛病在于启动速度较慢,因为须要预热编译器,同时编译过程也会耗费肯定的内存和CPU资源。实用场景:解释器实用于须要频繁更改程序代码的场景,例如开发阶段和调试阶段。而JIT编译器实用于须要长时间运行的场景,例如服务器端利用和桌面利用。组合应用:在理论利用中,解释器和JIT编译器可能会被组合应用,例如Java虚拟机就同时应用了解释器和JIT编译器。在程序启动时,应用解释器执行程序代码,同时预热JIT编译器,当程序代码被执行屡次后,JIT编译器会将代码编译成本地机器代码,进步程序的性能。JIT编译器和解释器都有其优缺点和实用场景,程序员须要依据理论状况抉择最适宜的工具来进步程序的性能和效率。 JIT 编译器的编译过程及原理JIT(Just-In-Time)编译器是一种动静编译器,它在程序运行时将字节码转换为本地机器码,以进步程序的执行速度。它的编译过程和原理能够简略地概括如下: 解析字节码:JIT编译器首先会解析Java字节码,将其转换成外部示意模式,例如形象语法树(AST)或两头示意(IR)。剖析代码:JIT编译器会对代码进行动态和动态分析,以确定代码的执行门路和性能瓶颈。动态剖析能够通过动态代码剖析工具进行,动态分析则能够在代码执行过程中收集性能数据。优化代码:JIT编译器会依据剖析后果对代码进行优化,例如打消无用的计算、缩小内存拜访、应用更疾速的算法等,从而进步程序的执行速度和效率。生成机器代码:JIT编译器会将优化后的代码生成本地机器代码,这些代码能够间接在处理器上执行,从而进步程序的性能。JIT编译器的原理是将Java字节码动静编译成本地机器代码,从而防止了每次执行时都解释字节码的开销。JIT编译器能够依据程序的执行状况和环境来做出优化决策,例如将频繁执行的代码编译成本地代码以进步执行速度,或者将不会被执行的代码从编译过程中删除以节俭资源。 JIT编译器通常应用编译器优化技术,例如常量折叠、死代码打消、循环展开、函数内联等,以进步代码的执行速度和效率。同时,JIT编译器还能够应用动静编译技术,例如即时编译(JIT)和依据执行状况进行编译等,以依据程序的执行状况和环境动静地生成代码,从而进步程序的性能和效率。 JIT 编译器如何进行优化JIT编译器进行优化的形式有很多种,以下是常见的几种优化技术: 提早编译:JIT编译器会将代码的编译提早到第一次执行时,从而防止对不罕用的代码进行不必要的编译。热点代码优化:JIT编译器会将频繁执行的代码编译成本地代码以进步执行速度。这些频繁执行的代码被称为“热点代码”。内联函数:JIT编译器会将函数调用间接替换为函数自身的代码,从而打消了函数调用的开销。循环展开:JIT编译器会将循环中的代码反复开展屡次,从而缩小循环的迭代次数,进步程序的执行速度。常量折叠:JIT编译器会将常量表达式计算出后果,从而缩小反复计算的开销。死代码打消:JIT编译器会检测和删除不会被执行的代码,从而缩小代码的大小和复杂度。对象去锁优化:JIT编译器会对代码进行剖析,将不须要锁的对象去掉锁,从而进步程序的执行速度。栈上调配:JIT编译器会将一些小的对象调配到栈上而不是堆上,从而缩小内存调配和回收的开销。缓存剖析:JIT编译器会分析程序拜访内存的模式,从而将数据预取到缓存中,进步程序的执行速度。JIT 编译器的应用场景和限度JIT 编译器通常实用于须要高性能的 Java 应用程序,尤其是那些须要大量计算和数据处理的应用程序,例如 Web 服务器、数据库、游戏引擎等。在这些应用程序中,JIT 编译器能够将热点代码编译成本地代码,从而防止了解释执行时的性能损失,大大提高了程序的运行速度,比方: 频繁调用的办法或代码块:JIT编译器能够将频繁调用的办法或代码块编译成本地代码,从而进步程序的执行速度。大规模数据处理:JIT编译器能够通过优化循环和数组拜访等操作,从而进步大规模数据处理的性能。高并发场景:JIT编译器能够应用对象去锁优化等技术,从而进步高并发场景下的程序性能。须要动静生成代码的场景:JIT编译器能够依据程序的执行状况和环境动静地生成本地代码,从而不便在运行时动静生成代码。然而它也存在一些限度: 启动时间延迟:JIT编译器须要在程序运行时解释和编译Java字节码,从而导致程序启动时间延迟。内存占用:JIT编译器会将编译后的本地代码存储在内存中,从而占据肯定的内存空间。编译开销:JIT编译器在编译Java字节码时须要进行肯定的优化解决,从而耗费肯定的CPU工夫和资源。可移植性:JIT编译器生成的本地代码依赖于特定的硬件平台和操作系统,从而限度了代码的可移植性。所以JIT编译器实用于须要进步程序性能和效率的场景,但也存在一些限度,须要依据具体的利用场景和需要进行衡量和抉择。 总结JIT 编译器对 Java 程序的性能有着重要的影响。因为 JIT 编译器可能动静地将字节码编译成本地代码,从而防止了解释执行时的开销,因而能够大大提高程序的执行效率。一般来说,JIT 编译器能够进步程序的运行速度 5 倍甚至更多,尤其是对于须要大量计算的程序,成果更加显著。 此外,JIT 编译器还能够通过各种优化伎俩,进一步提高程序的性能。例如,通过内联、逃逸剖析、打消冗余计算等形式,能够缩小程序的计算次数,从而进步程序的运行速度。 须要留神的是,JIT 编译器的性能也会受到一些因素的影响,例如代码的复杂度、编译器的实现形式、编译器的优化等等。因而,在应用 JIT 编译器时,须要依据理论状况进行测试和优化,以达到最优的性能体现。

March 16, 2023 · 1 min · jiezi

关于java:性能优化搞得好Tomcat少不了-博学谷狂野架构师

Tomcat根本应用 什么是Web服务器web服务器的定义其实并没有规范定义,个别认为Web服务器个别指网站服务器,是指驻留于因特网上某种类型计算机的程序,能够向浏览器等Web客户端提供文档,也能够搁置网站文件,让全世界浏览;能够搁置数据文件,让全世界下载。 Web服务器的特点服务器是一种被动程序:只有当Internet上运行其余计算机中的浏览器收回的申请时,服务器才会响应。服务器个别应用HTTP(超文本传输协定)与客户机浏览器进行信息交换,这就是人们常把它们称为HTTP服务器的起因。Web服务器不仅可能存储信息,还能在用户通过Web浏览器提供的信息的根底上运行脚本和程序什么是TomcatTomcat是由Apache软件基金会属下Jakarta我的项目开发的Servlet容器,是开发和调试JSP程序的首选,实现了对Servlet和JavaServer Page的反对,并提供Web服务器的一些特有性能。 Tomcat是一款开源轻量级Web应用服务器,是一款优良的Servlet容器实现。 Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具备独立于平台和协定的个性,次要性能在于交互式地浏览和生成数据,生成动静Web内容。 Servlet严格来讲是指Java语言实现的一个接口,个别状况下咱们说的Servlet是指任何实现了这个Servlet接口的类。 实例化并调用init()办法初始化该 Servlet,个别 Servlet 只初始化一次(只有一个对象)service()(依据申请办法不同调用doGet() 或者 doPost(),此外还有doHead()、doPut()、doTrace()、doDelete()、doOptions()、destroy())。当 Server 不再须要 Servlet 时(个别当 Server 敞开时),Server 调用 Servlet 的 destroy() 办法。 简略总结下,tomcat是一个中间件,在B/S架构中,浏览器收回的http申请通过tpmcat中间件,转发到最终的目标服务器上,响应音讯再通过tomcat返回给浏览器。 tomcat所做的事件次要有:开启监听端口监听用户的申请,解析用户发来的http申请而后拜访到你指定的利用零碎,而后你返回的页面通过tomcat返回给用户。 Apache,Nginx和Tomcat的区别Apache全称是 Apache Http Server Project, Tomcat全称是 Apache Tomcat。Apache和 Nginx用于解决动态资源, tomcat用来解决动静资源。Apache和Nginx相比,Nginx适宜做前端服务器,适宜做负载平衡。个别状况下,应用的时候,都是 Apache+Tomcat一起应用或者 Nginx+tomcat一起应用。 典型的Servlet的解决流程第一个达到服务器的HTTP申请被委派到Servlet容器。Servlet容器在调用service()办法之前加载Servlet。而后Servlet容器解决由多个线程产生的多个申请,每个线程执行一个繁多的Servlet实例的service()办法。Tomcat版本介绍Tomcat版本6788.59JDK≥5.0≥6.0≥7.0≥7.0≥8.0Servlet2.533.13.14JSP2.12.22.32.32.3EL2.12.2333WebScoketN/A1.11.11.11.1Servlet标准Servlet 2.X我的项目目录构造必须要有WEB-INF,web.xml等文件夹和文件,在web.xml中配置servlet,filter,listener,以web.xml为java web我的项目的对立入口。 Servlet 3.x我的项目中能够不须要WEB-INF,web.xml等文件夹和文件,在没有web.xml文件的状况下,通过注解实现servlet,filter,listener的申明,当应用注解时,容器主动进行扫描。 8.5版本特点Tomcat8.5进行了大量的代码重构,比照与7.0的版本,也合乎Tomcat将来的代码架构体系。然而Tomcat的外围和主体架构还是始终放弃这样的。反对Servlet3.1默认采纳NIO,移除BIO反对NIO2(AIO)反对HTTP/2协定默认采纳异步日志解决 为什么要应用8.5的版本,首先这个版本比拟新,因为太老的版本比方6.0的版本Servlet不反对3所以会导致部署SpringBoot等我的项目有问题,同时这个版本是在9.0呈现当前公布的一个两头版本,主体架构连续8.0,同时又实现了局部9.0的新个性。 Tomcat启动Tomcat 下载Tomcat下载地址:https://tomcat.apache.org/download-80.cgi 个别启动startup.bat 启动 Tomcat通常下载解压版即可,解压后能够间接应用,安装版应用不灵便。间接到 %Tomcat_HOME%/bin 目录上面运行 startup.bat ( linux 中是 startup.sh )文件即可开启 Tomcat,默认端口 8080,浏览器输出 localhost:8080 即可拜访。这样做的益处是能间接从窗口中实时的看到我的项目中所有输入的内容,以及抛出的异样与谬误等,适宜于调试阶段Windws 零碎中能够将 startup.bat 创立快捷方式,而后放到启动文件夹中,这样就会开机自起。 启动日志如下 ...

March 16, 2023 · 1 min · jiezi

关于java:100Wqps短链系统怎么设计

这段时间,在整顿常识星球中面试专栏时看到这么一个字节跳动的二面真题:100Wqps短链零碎,怎么设计? 这道题,看上去业务简略,其实,笼罩的知识点十分多: 高并发、高性能分布式 IDRedis Bloom Filter 高并发、低内存损耗的 过滤组件常识分库、分表海量数据存储多级缓存的常识HTTP传输常识二进制、十六进制、六十二进制常识总体来说,高并发、高性能零碎的外围畛域,都笼罩了。所以,陈某剖析下来,失去一个论断:是一个超级好的问题。 关注公z号:码猿技术专栏,回复关键词:1111 获取阿里外部性能调优手册1、短URL零碎的背景短网址代替长URL,在互联网网上流传和援用。 例如QQ微博的url.cn,新郎的sinaurl.cn等。 在QQ、微博上公布网址的时候,会主动判断网址,并将其转换,例如:http://url.cn/2hytQx 为什么要这样做的,无外乎几点: 缩短地址长度,留足更多空间的给 有意义的内容 URL是没有意义的,有的原始URL很长,占用无效的屏幕空间。 微博限度字数为140字一条,那么如果这个连贯十分的长,以至于将近要占用咱们内容的一半篇幅,这必定是不能被容许的,链接变短,对于有长度限度的平台发文,可编辑的文字就变多了, 所以短网址应运而生了。 能够很好的对原始URL内容管控。 有一部分网址能够会涵盖XX,暴力,广告等信息,这样咱们能够通过用户的举报,齐全治理这个连贯将不呈现在咱们的利用中,应为同样的URL通过加密算法之后,失去的地址是一样的。 能够很好的对原始URL进行行为剖析 咱们能够对一系列的网址进行流量,点击等统计,挖掘出大多数用户的关注点,这样有利于咱们对我的项目的后续工作更好的作出决策。 短网址和短ID相当于间接进步了带宽的利用率、节约老本链接太长在有些平台上无奈自动识别为超链接短链接更加简洁难看且平安,不裸露拜访参数。而且,能躲避关键词、域名屏蔽等伎俩2、短URL零碎的原理短URL零碎的外围:将长的 URL 转化成短的 URL。 客户端在拜访零碎时,短URL的工作流程如下: 先应用短地址A拜访 短链Java 服务短链Java 服务 进行 地址转换和映射,将 短URL零碎映射到对应的长地址URL短链Java 服务 返回302 重定向 给客户端而后客户端再重定向到原始服务如下图所示: 那么,原始URL如何变短呢?简略来说, 能够将原始的地址,应用编号进行代替 编号如何进一步变短呢? 能够应用更大的进制来示意 六十二进制表示法顾名思义短网址就是十分短的网址,比方http://xxx.cn/EYyCO9T,其中外围的局部 EYyCO9T 只有7位长度。 其实这里的7位长度是应用62进制来示意的,就是罕用的0-9、a-z、A-Z,也就是10个数字+26个小写+26个大写=62位。 那么7位长度62进制能够示意多大范畴呢? 62^7 = 3,521,614,606,208 (共计3.5万亿),阐明:10进制 最大只能生成 10 ^ 6 - 1 =999999个16进制 最大只能生成 16 ^ 6 - 1 =16777215个16进制外面曾经蕴含了 A B C D E F 这几个字母62进制 最大竟能生成 62 ^ 6 - 1 =56800235583个 基本上够了。A-Z a-z 0-9 刚好等于62位留神:int(4个字节) ,存储的范畴是-21亿到21亿long(8个字节),存储的范畴是-900万万亿 到 900万万亿至于短网址的长度,能够依据本人须要来调整,如果须要更多,能够减少位数, ...

March 16, 2023 · 3 min · jiezi

关于java:一个由public关键字引发的bug

先来看一段代码: @Service@Slf4jpublic class AopTestService { public String name = "真的吗"; @Retryable public void test(){ // 模仿业务操作 log.debug("name:{}", this.name); // 模仿内部操作,失败重试 }}很简略的代码,而后在另一个类中进行调用 public void test(){ testService.test(); log.info("name:{}", testService.name); }问题也很简略,以上代码打印输出什么? 如果没能看进去,无妨先来看(笑)看(笑)我是怎么触发一个简略的BUG。 bug之路以上代码必定是不标准的。失常应该是类里定义为一个private公有变量,而后提供getter/setter办法供内部拜访。 像这种将变量间接为定义public,在外部类间接拜访的状况,失常状况下我是写不进去。 然而,话说某天,活急了,一个类写了上千行代码,必定得想把公共代码提取进去,将代码依据业务拆分。原始类中有一个private的成员变量,在该类外部办法中拜访。因为部份代码拆分到其它类当中,该变量须要在内部被拜访,我一时偷懒,就将该变量的拜访级别由private改为public。省略业务代码,大略就变成了下面一结尾的示例代码。 司空见惯的,我认为这样就能拜访了。但我却被啪啪打脸了。 失常状况下,这样尽管代码不标准,但的确能拜访。 为什么这里确不能拜访了呢? 因为我在办法加了个@Retryable注解。 retryable是什么? 因为一些网络,内部接口等不可预知的问题,咱们的程序或者接口会失败,这时就须要重试机制,比方延时1S后重试、距离一直减少重试等,本人去实现这些性能的话,显得轻便而不优雅,所以spring官网实现了retryable模块。这里能够略过它的原理,只需晓得它是应用了动静代理+AOP。 这个注解需给AopTestService 生成代理类。而动静代理是不能代理属性的。所以在另一个类当中,应用AopTestService 的代理类不能间接拜访指标类的成员变量。 严格意义来说,这还不算BUG,因为在调试阶段就立马发现了,但我的确没能一眼看进去。 可能一眼看出问题所在的大佬,请喝茶。 当初咱们晓得,动静代理类只能代理办法而不能代理属性。然而话语是红润的,咱们还是要有间接的证据。 最表象的起因,间接Debug截图能够察看到,aopTestService由cglib生成了代理类。在这个代理类里value值为null。 再通过反编译动静代理生成的代码,能够看到只有办法的定义,没有父类变量的定义。 为什么spring中的动静代理不能代理属性?后面说到,spring动静代理只能代理办法,不能代理属性。 cglib都能够,为什么spring不能够呢? 再深刻一点。咱们能够在源码中断点,看看cglib到底如何没有代理属性。 在spring-aop模块中查找类ObjenesisCglibAopProxy,从名字当中就可以看进去,spring的动静代理全用了Objenesis+cglib。在这个类中的createProxyClassAndInstance办法断点,在srping boot启动的时候,能够察看到: 能够看到这里应用了Objenesis实例化了AopTestService代理对象。如果Objenesis实例失败,再通过默认构造方法进行实例。因为没有调用构造方法,所以spring生成动静代理类的时候没能保留父类的属性。 所以Objenesis是什么? 从以上的代码和正文当中也能够揣测得出,它是一个能够绕过构造方法实例对象的一个工具。为什么须要绕过构造方法实例对象? 这又分为spring和非spring。非srping下的确有这样的场景,比方 结构器须要参数 结构器有side effects 结构器会抛异样因而,在类库中常常会有类必须领有一个默认结构器的限度。Objenesis通过绕开对象实例结构器来克服这个限度。 至于为什么spring要应用Objenesis绕过构造方法,那就是另一个问题了。 java为什么要有private关键字?这仿佛是一个无厘头的问题,然而的确有很多初学者有这个疑难。 我想了想,至多在我刚接触java的时候没想过这个问题。创立一个java bean,private所有变量,而后主动生成getter/setter干就完了。 又比方这个知乎问题,看起来看是在钓鱼,也有人认为是好问题,不知道是不是反窜。 ...

March 16, 2023 · 1 min · jiezi

关于java:笑小枫的SpringBoot系列十三JAVA使用EasyExcel导出excel

性能背景简略的说下这个性能的背景需要吧,有相似需要的能够复用,果然导入还没写完,导出的性能接踵而来,一块写了吧 实现excel导出(仍旧废话...)多个sheet页一起导出第一个sheet页数据表头信息有两行款式略微好看,列宽能够自定义等数据量略微有些大(多个sheet页总量50w左右)我的项目引入依赖如果是从上一篇看过去的,就不必看我的项目引入了 gradle: compile "com.alibaba:easyexcel:3.1.0"maven: <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.1.0</version></dependency>留神: 3+版本的的easyexcel,应用poi 5+版本时,须要手动排除:poi-ooxml-schemas,例如: <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.1.0</version> <exclusions> <exclusion> <artifactId>poi-ooxml-schemas</artifactId> <groupId>org.apache.poi</groupId> </exclusion> </exclusions></dependency>我的项目编码如多个表格款式雷同,可编写一个父类,将款式定义在父类上,子类继承父类即可。 在config.bean.excel包下定义经销商信息对象ExportCompany.java,代码如下package com.maple.demo.config.bean.excel;import com.alibaba.excel.annotation.ExcelProperty;import com.alibaba.excel.annotation.write.style.ColumnWidth;import com.alibaba.excel.annotation.write.style.ContentFontStyle;import com.alibaba.excel.annotation.write.style.HeadFontStyle;import com.alibaba.excel.annotation.write.style.HeadStyle;import com.alibaba.excel.enums.poi.FillPatternTypeEnum;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.NoArgsConstructor;import java.util.Date;/** * @author 笑小枫 * @date 2022/7/22 */@Data@Builder@NoArgsConstructor@AllArgsConstructor@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)@HeadFontStyle(fontHeightInPoints = 12)@ContentFontStyle(fontHeightInPoints = 11)@ColumnWidth(20)public class ExportCompany { // -------------------- 根本信息 start ------------- @ExcelProperty({"根本信息", "公司名称"}) private String companyName; @ExcelProperty({"根本信息", "省份"}) private String province; @ExcelProperty({"根本信息", "成立工夫"}) private Date startDate; @ExcelProperty({"根本信息", "企业状态"}) private String entStatus; @ColumnWidth(30) @ExcelProperty({"根本信息", "博客地址"}) private String csdnAddress; // ---------------- 根本信息 end --------------------- // ---------------- 经营信息 start --------------------- @ExcelProperty({"经营信息", "员工数"}) private String employeeMaxCount; @ExcelProperty({"经营信息", "网站地址"}) private String netAddress; @ExcelProperty({"经营信息", "所属区域省"}) private String businessProvinceName; @ExcelProperty({"经营信息", "所属区域市"}) private String businessCityName; @ExcelProperty({"经营信息", "所属区域区县"}) private String businessAreaName; // ---------------- 经营信息 end ---------------------}在config.bean.excel包下定义联系人信息对象ExportContact.java,代码如下package com.maple.demo.config.bean.excel;import com.alibaba.excel.annotation.ExcelProperty;import com.alibaba.excel.annotation.write.style.ColumnWidth;import com.alibaba.excel.annotation.write.style.ContentFontStyle;import com.alibaba.excel.annotation.write.style.HeadFontStyle;import com.alibaba.excel.annotation.write.style.HeadStyle;import com.alibaba.excel.enums.poi.FillPatternTypeEnum;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.NoArgsConstructor;/** * @author 笑小枫 * @date 2022/7/22 */@Data@Builder@NoArgsConstructor@AllArgsConstructor@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)@HeadFontStyle(fontHeightInPoints = 12)@ContentFontStyle(fontHeightInPoints = 11)@ColumnWidth(20)public class ExportContact { @ExcelProperty("公司名称") private String companyName; @ExcelProperty("姓名") private String name; @ExcelProperty("身份证号码") private String idCard; @ExcelProperty("电话号码") private String mobile; @ExcelProperty("职位") private String contactPostName;}在controller包下编写TestExportExcelController.java进行测试,代码如下:package com.maple.demo.controller;import com.alibaba.excel.EasyExcelFactory;import com.alibaba.excel.ExcelWriter;import com.alibaba.excel.write.metadata.WriteSheet;import com.maple.demo.config.bean.excel.ExportCompany;import com.maple.demo.config.bean.excel.ExportContact;import io.swagger.annotations.Api;import lombok.extern.slf4j.Slf4j;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse;import java.io.OutputStream;import java.net.URLEncoder;import java.util.ArrayList;import java.util.Date;import java.util.List;/** * @author 笑小枫 * @date 2022/7/22 */@Slf4j@RestController@RequestMapping("/example")@Api(tags = "实例演示-导出Excel")public class TestExportExcelController { @GetMapping("/exportExcel") public void exportExcel(HttpServletResponse response) { try (OutputStream out = response.getOutputStream()) { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); String fileName = URLEncoder.encode("笑小枫测试导出", "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); handleExcel(out); out.flush(); } catch (Exception e) { log.error(e.getMessage()); } } private void handleExcel(OutputStream out) { try (ExcelWriter excelWriter = EasyExcelFactory.write(out).build()) { WriteSheet dealerSheet = EasyExcelFactory.writerSheet(0, "经销商信息").head(ExportCompany.class).build(); WriteSheet contactSheet = EasyExcelFactory.writerSheet(1, "联系人").head(ExportContact.class).build(); excelWriter.write(getCompany(), dealerSheet); excelWriter.write(getContact(), contactSheet); } } private List<ExportCompany> getCompany() { List<ExportCompany> companyList = new ArrayList<>(); for (int i = 0; i < 5; i++) { companyList.add(ExportCompany.builder() .companyName("笑小枫公司" + i) .province("上海市") .businessProvinceName("山东省") .businessCityName("临沂市") .businessAreaName("河东区") .entStatus("营业") .netAddress("www.xiaoxiaofeng.site") .csdnAddress("https://zhangfz.blog.csdn.net") .employeeMaxCount("100") .startDate(new Date()) .build()); } return companyList; } private List<ExportContact> getContact() { List<ExportContact> contactList = new ArrayList<>(); for (int i = 0; i < 5; i++) { contactList.add(ExportContact.builder() .companyName("笑小枫公司" + i) .name("笑小枫" + i) .mobile("183000000000") .idCard("371324199011111111") .contactPostName("后端") .build()); } return contactList; }}测试后果浏览器申请:http://localhost:8080/example/exportExcel ...

March 15, 2023 · 2 min · jiezi

关于java:自从用了-EasyExcel导入导出-Excel-更简单了

作者:风雨兼程 \起源:jianshu.com/p/8f3defdc76d4 EasyExcel在做excel导入导出的时候,发现我的项目中封装的工具类及其难用,于是去gitHub上找了一些相干的框架,最终选定了EasyExcel。之前早有听闻该框架,然而始终没有去理解,这次借此学习一波,进步当前的工作效率。 理论应用中,发现是真的很easy,大部分api通过名称就能晓得大抵意思,这点做的很nice。参考文档,大部分场景的需要根本都可能满足。 GitHub上的官网阐明 疾速开始maven仓库地址<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.1.2</version></dependency>举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practice导入如下图excel表格: 建设导入对应实体类@Datapublic class ReqCustomerDailyImport { /** * 客户名称 */ @ExcelProperty(index = 0) private String customerName; /** * MIS编码 */ @ExcelProperty(index = 1) private String misCode; /** * 月度滚动额 */ @ExcelProperty(index = 3) private BigDecimal monthlyQuota; /** * 最新应收账款余额 */ @ExcelProperty(index = 4) private BigDecimal accountReceivableQuota; /** * 本月利率(年化) */ @ExcelProperty(index = 5) private BigDecimal dailyInterestRate;}Controller代码@PostMapping("/import")public void importCustomerDaily(@RequestParam MultipartFile file) throws IOException { InputStream inputStream = file.getInputStream(); List<ReqCustomerDailyImport> reqCustomerDailyImports = EasyExcel.read(inputStream) .head(ReqCustomerDailyImport.class) // 设置sheet,默认读取第一个 .sheet() // 设置题目所在行数 .headRowNumber(2) .doReadSync();}运行后果 ...

March 15, 2023 · 3 min · jiezi

关于java:透过现象看Java-AIO的本质-|-得物技术

1.前言对于Java BIO、NIO、AIO的区别和原理,这样的文章十分的多的,但次要还是在BIO和NIO这两者之间探讨,而对于AIO这样的文章就少之又少了,很多只是介绍了一下概念和代码示例。 在理解AIO时,有留神到以下几个景象: 1、 2011年Java 7公布,外面减少了AIO称之为异步IO的编程模型,但曾经过来了近12年,平时应用的开发框架中间件,还是以NIO为主,例如网络框架Netty、Mina,Web容器Tomcat、Undertow。 2、 Java AIO又称为NIO 2.0,难道它也是基于NIO来实现的? 3、 Netty舍去了AIO的反对。https://github.com/netty/netty/issues/2515 4、 AIO看起来只是解决了有无,公布了个寂寞。这几个景象未免会令很多人心存疑惑,所以决定写这篇文章时,不想简略的把AIO的概念再复述一遍,而是要透过景象, 如何剖析、思考和了解Java AIO的实质。 2.什么是异步2.1 咱们所理解的异步AIO的A是Asynchronous异步的意思,在理解AIO的原理之前,咱们先理清一下“异步”到底是怎么的一个概念。说起异步编程,在平时的开发还是比拟常见,例如以下的代码示例: @Asyncpublic void create() { //TODO}public void build() { executor.execute(() -> build());}不论是用@Async注解,还是往线程池里提交工作,他们最终都是同一个后果,就是把要执行的工作,交给另外一个线程来执行。这个时候,能够大抵的认为,所谓的“异步”,就是多线程,执行工作。 2.2 Java BIO和NIO到底是同步还是异步?Java BIO和NIO到底是同步还是异步,咱们先依照异步这个思路,做异步编程。 2.2.1 BIO示例byte [] data = new byte[1024];InputStream in = socket.getInputStream();in.read(data);// 接管到数据,异步解决executor.execute(() -> handle(data));public void handle(byte [] data) { // TODO}BIO在read()时,尽管线程阻塞了,但在收到数据时,能够异步启动一个线程去解决。 2.2.2 NIO示例selector.select();Set<SelectionKey> keys = selector.selectedKeys();Iterator<SelectionKey> iterator = keys.iterator();while (iterator.hasNext()) { SelectionKey key = iterator.next(); if (key.isReadable()) { SocketChannel channel = (SocketChannel) key.channel(); ByteBuffer byteBuffer = (ByteBuffer) key.attachment(); executor.execute(() -> { try { channel.read(byteBuffer); handle(byteBuffer); } catch (Exception e) { } }); }}public static void handle(ByteBuffer buffer) { // TODO}同理,NIO尽管read()是非阻塞的,通过select()能够阻塞期待数据,在有数据可读的时候,异步启动一个线程,去读取数据和解决数据。 ...

March 15, 2023 · 2 min · jiezi

关于java:这是一篇纯讲SQL语句优化的文章-博学谷狂野架构师

insert如果咱们须要一次性往数据库表中插入多条记录,能够从以下三个方面进行优化。 insert into tb_test values(1,'tom');insert into tb_test values(2,'cat');insert into tb_test values(3,'jerry');.....优化计划一:批量插入数据 Insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');优化计划二手动管制事务 start transaction;insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');insert into tb_test values(4,'Tom'),(5,'Cat'),(6,'Jerry');insert into tb_test values(7,'Tom'),(8,'Cat'),(9,'Jerry');commit;优化计划三主键程序插入,性能要高于乱序插入。 主键乱序插入 : 8 1 9 21 88 2 4 15 89 5 7 3主键程序插入 : 1 2 3 4 5 7 8 9 15 21 88 89大批量插入数据如果一次性须要插入大批量数据(比方: 几百万的记录),应用insert语句插入性能较低,此时能够应用MySQL数据库提供的load指令进行插入。操作如下: 能够执行如下指令,将数据脚本文件中的数据加载到表构造中: -- 客户端连贯服务端时,加上参数 -–local-infilemysql –-local-infile -u root -p-- 设置全局参数local_infile为1,开启从本地加载文件导入数据的开关set global local_infile = 1;-- 执行load指令将筹备好的数据,加载到表构造中load data local infile '/root/sql1.log' into table tb_user fields terminated by ',' lines terminated by '\n' ;主键程序插入性能高于乱序插入实例演示: ...

March 15, 2023 · 9 min · jiezi

关于java:面试官怎么删除-HashMap-中的重复元素第-3-种实现思路99-的人不会

背景大家好,我是栈长。 前些天,栈长给大家分享了 3 篇实用的文章: 带了一个 3 年的开发,不会循环删除 List 中的元素,我几乎解体!!面试官:怎么去除 List 中的反复元素?我一行代码搞定,连忙拿去用!面试官:怎么删除 HashMap 中的元素?我一行代码搞定,连忙拿去用!List 和 Map 元素的删除、去重,这些都是工作中常常遇到的问题,一些根底程序员可能会走一些弯路,所以栈长输入了三篇,心愿对大家有用,其中一些编程技巧很多老程序员也没用过,所以,技术真的是学无止境。 明天栈长带来汇合的删除及去重系列的最初一篇,如何删除 HashMap 中的反复元素,即怎么依据 Value 去重,去除 HashMap 中 Value 反复的元素,这也是面试官可能会问到的。为什么不是依据 Key 去重?大家都晓得,HashMap 的 key 是不会反复的,如果有反复就会用新值笼罩旧值。 当咱们向一个 HashMap 中插入元素时,HashMap 会依据这个 key 的 equals 和 hashCode 办法进行判断,如果两个 key 的值用 equals 办法比拟雷同,且 key 的 hashCode 值也雷同,那么 HashMap 将认为这是同一个 key,后续插入雷同 key 的键值对会将旧值替换为新值。 须要留神的是: Java 中的根本数据类型和 String 等内置类,它们曾经正确实现了 equals 和 hashCode 办法,能够间接用作 HashMap 的 key,而不会导致反复的 key 呈现。 如果咱们应用自定义类的对象作为 HashMap 的 key,须要保障这个类正确实现了 equals 和 hashCode 办法,否则可能会呈现插入 "反复 key" 的状况,失常状况下,这是不符合规范和逻辑的。 ...

March 15, 2023 · 2 min · jiezi

关于java:卷起来看了这篇文章我才知道MySQL事务MVCC到底是啥

事务根底事务事务 是一组操作的汇合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向零碎提交或撤销操作申请,即这些操作要么同时胜利,要么同时失败。 个性原子性(Atomicity):事务是不可分割的最小操作单元,要么全副胜利,要么全副失败。一致性(Consistency):事务实现时,必须使所有的数据都保持一致状态。隔离性(Isolation):数据库系统提供的隔离机制,保障事务在不受内部并发操作影响的独立环境下运行。持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的扭转就是永恒的。那实际上,咱们钻研事务的原理,就是钻研MySQL的InnoDB引擎是如何保障事务的这四大个性的。 而对于这四大个性,实际上分为两个局部。 其中的原子性、一致性、长久化,实际上是由InnoDB中的两份日志来保障的,一份是redo log日志,一份是undo log日志。 而持久性是通过数据库的锁,加上MVCC来保障的。 接下来次要就是来钻研一下redolog,undolog以及MVCC。 redo log重做日志,记录的是事务提交时数据页的物理批改,是用来实现事务的持久性。 该日志文件由两局部组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log file),前者是在内存中,后者在磁盘中。当事务提交之后会把所有批改信息都存到该日志文件中, 用于在刷新脏页到磁盘,产生谬误时, 进行数据恢复应用。 如果没有redolog,可能会存在什么问题的? 咱们一起来剖析一下。 咱们晓得,在InnoDB引擎中的内存构造中,次要的内存区域就是缓冲池,在缓冲池中缓存了很多的数据页。 当咱们在一个事务中,执行多个增删改的操作时,InnoDB引擎会先操作缓冲池中的数据,如果缓冲区没有对应的数据,会通过后盾线程将磁盘中的数据加载进去,寄存在缓冲区中,而后将缓冲池中的数据批改,批改后的数据页咱们称为脏页。 而脏页则会在肯定的机会,通过后盾线程刷新到磁盘中,从而保障缓冲区与磁盘的数据统一。 而缓冲区的脏页数据并不是实时刷新的,而是一段时间之后将缓冲区的数据刷新到磁盘中,如果刷新到磁盘的过程出错了,而提醒给用户事务提交胜利,而数据却没有长久化下来,这就呈现问题了,没有保障事务的持久性。 那么,如何解决上述的问题呢? 在InnoDB中提供了一份日志 redo log,接下来咱们再来剖析一下,通过redolog如何解决这个问题。 有了redolog之后,当对缓冲区的数据进行增删改之后,会首先将操作的数据页的变动,记录在redo log buffer中。在事务提交时,会将redo log buffer中的数据刷新到redo log磁盘文件中。过一段时间之后,如果刷新缓冲区的脏页到磁盘时,产生谬误,此时就能够借助于redo log进行数据恢复,这样就保障了事务的持久性。 而如果脏页胜利刷新到磁盘 或 或者波及到的数据曾经落盘,此时redolog就没有作用了,就能够删除了,所以存在的两个redolog文件是循环写的。 那为什么每一次提交事务,要刷新redo log 到磁盘中呢,而不是间接将buffer pool中的脏页刷新到磁盘呢 ? 因为在业务操作中,咱们操作数据个别都是随机读写磁盘的,而不是程序读写磁盘。 而redo log在往磁盘文件中写入数据,因为是日志文件,所以都是程序写的。程序写的效率,要远大于随机写。 这种先写日志的形式,称之为 WAL(Write-Ahead Logging)。 undo log回滚日志,用于记录数据被批改前的信息 , 作用蕴含两个 : 提供回滚(保障事务的原子性) 和MVCC(多版本并发管制) 。 undo log和redo log记录物理日志不一样,它是逻辑日志。能够认为当delete一条记录时,undolog中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相同的update记录。当执行rollback时,就能够从undo log中的逻辑记录读取到相应的内容并进行回滚。 Undo log销毁:undo log在事务执行时产生,事务提交时,并不会立刻删除undo log,因为这些日志可能还用于MVCC。 Undo log存储:undo log采纳段的形式进行治理和记录,寄存在后面介绍的 rollback segment回滚段中,外部蕴含1024个undo log segment。 ...

March 14, 2023 · 3 min · jiezi

关于java:Android设备接入阿里云IoT物联网平台设备接入类

1. 筹备工作1.1 注册阿里云账号应用集体淘宝账号或手机号,开明阿里云账号,并通过__实名认证(能够用支付宝认证)__ 1.2 收费开明IoT物联网套件产品官网 https://www.aliyun.com/product/iot 1.3 软件环境JDK装置编辑器 IDEA 2. 开发步骤2.1 云端开发1) 创立高级版产品 2) 性能定义,产品物模型增加属性增加产品属性定义 物模型对应属性上报topic /sys/替换为productKey/替换为deviceName/thing/event/property/post物模型对应的属性上报payload { id: 123452452, params: { temperature: 26.2, humidity: 60.4 }, method: "thing.event.property.post"}3) 设施治理>注册设施,取得身份三元组 2.2 设施端开发咱们以java程序来模仿设施,建设连贯,上报数据。 1) build.gradle增加sdk依赖dependencies { implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.0'}2) AliyunIoTSignUtil工具类import javax.crypto.Mac;import javax.crypto.SecretKey;import javax.crypto.spec.SecretKeySpec;import java.util.Arrays;import java.util.Map;/** * AliyunIoTSignUtil */public class AliyunIoTSignUtil { public static String sign(Map<String, String> params, String deviceSecret, String signMethod) { //将参数Key按字典程序排序 String[] sortedKeys = params.keySet().toArray(new String[] {}); Arrays.sort(sortedKeys); //生成规范化申请字符串 StringBuilder canonicalizedQueryString = new StringBuilder(); for (String key : sortedKeys) { if ("sign".equalsIgnoreCase(key)) { continue; } canonicalizedQueryString.append(key).append(params.get(key)); } try { String key = deviceSecret; return encryptHMAC(signMethod,canonicalizedQueryString.toString(), key); } catch (Exception e) { throw new RuntimeException(e); } } /** * HMACSHA1加密 * */ public static String encryptHMAC(String signMethod,String content, String key) throws Exception { SecretKey secretKey = new SecretKeySpec(key.getBytes("utf-8"), signMethod); Mac mac = Mac.getInstance(secretKey.getAlgorithm()); mac.init(secretKey); byte[] data = mac.doFinal(content.getBytes("utf-8")); return bytesToHexString(data); } public static final String bytesToHexString(byte[] bArray) { StringBuffer sb = new StringBuffer(bArray.length); String sTemp; for (int i = 0; i < bArray.length; i++) { sTemp = Integer.toHexString(0xFF & bArray[i]); if (sTemp.length() < 2) { sb.append(0); } sb.append(sTemp.toUpperCase()); } return sb.toString(); }}3) 模仿设施MainActivity.java代码public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private TextView msgTextView; private String productKey = "";// 高级版产品key private String deviceName = "";//曾经注册的设施id private String deviceSecret = "";//设施秘钥 //property post topic private final String payloadJson = "{\"id\":%s,\"params\":{\"temperature\": %s,\"humidity\": %s},\"method\":\"thing.event.property.post\"}"; private MqttClient mqttClient = null; final int POST_DEVICE_PROPERTIES_SUCCESS = 1002; final int POST_DEVICE_PROPERTIES_ERROR = 1003; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case POST_DEVICE_PROPERTIES_SUCCESS: showToast("发送数据胜利"); break; case POST_DEVICE_PROPERTIES_ERROR: showToast("post数据失败"); break; } } }; private String responseBody = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); msgTextView = findViewById(R.id.msgTextView); findViewById(R.id.activate_button).setOnClickListener((l) -> { new Thread(() -> initAliyunIoTClient()).start(); }); findViewById(R.id.post_button).setOnClickListener((l) -> { mHandler.postDelayed(() -> postDeviceProperties(), 1000); }); findViewById(R.id.quit_button).setOnClickListener((l) -> { try { mqttClient.disconnect(); } catch (MqttException e) { e.printStackTrace(); } }); } /** * 应用 productKey,deviceName,deviceSecret 三元组建设IoT MQTT连贯 */ private void initAliyunIoTClient() { try { String clientId = "androidthings" + System.currentTimeMillis(); Map<String, String> params = new HashMap<String, String>(16); params.put("productKey", productKey); params.put("deviceName", deviceName); params.put("clientId", clientId); String timestamp = String.valueOf(System.currentTimeMillis()); params.put("timestamp", timestamp); // cn-shanghai String targetServer = "tcp://" + productKey + ".iot-as-mqtt.cn-shanghai.aliyuncs.com:1883"; String mqttclientId = clientId + "|securemode=3,signmethod=hmacsha1,timestamp=" + timestamp + "|"; String mqttUsername = deviceName + "&" + productKey; String mqttPassword = AliyunIoTSignUtil.sign(params, deviceSecret, "hmacsha1"); connectMqtt(targetServer, mqttclientId, mqttUsername, mqttPassword); } catch (Exception e) { e.printStackTrace(); responseBody = e.getMessage(); mHandler.sendEmptyMessage(POST_DEVICE_PROPERTIES_ERROR); } } public void connectMqtt(String url, String clientId, String mqttUsername, String mqttPassword) throws Exception { MemoryPersistence persistence = new MemoryPersistence(); mqttClient = new MqttClient(url, clientId, persistence); MqttConnectOptions connOpts = new MqttConnectOptions(); // MQTT 3.1.1 connOpts.setMqttVersion(4); connOpts.setAutomaticReconnect(true); connOpts.setCleanSession(true); connOpts.setUserName(mqttUsername); connOpts.setPassword(mqttPassword.toCharArray()); connOpts.setKeepAliveInterval(60); mqttClient.connect(connOpts); Log.d(TAG, "connected " + url); } /** * post 数据 */ private void postDeviceProperties() { try { Random random = new Random(); //上报数据 String payload = String.format(payloadJson, String.valueOf(System.currentTimeMillis()), 10 + random.nextInt(20), 50 + random.nextInt(50)); responseBody = payload; MqttMessage message = new MqttMessage(payload.getBytes("utf-8")); message.setQos(1); String pubTopic = "/sys/" + productKey + "/" + deviceName + "/thing/event/property/post"; mqttClient.publish(pubTopic, message); Log.d(TAG, "publish topic=" + pubTopic + ",payload=" + payload); mHandler.sendEmptyMessage(POST_DEVICE_PROPERTIES_SUCCESS); mHandler.postDelayed(() -> postDeviceProperties(), 5 * 1000); } catch (Exception e) { e.printStackTrace(); responseBody = e.getMessage(); mHandler.sendEmptyMessage(POST_DEVICE_PROPERTIES_ERROR); Log.e(TAG, "postDeviceProperties error " + e.getMessage(), e); } } private void showToast(String msg) { msgTextView.setText(msg + "\n" + responseBody); }}3. 启动运行3.1 设施启动 ...

March 14, 2023 · 3 min · jiezi

关于java:确定了今天带一个看板娘回家

内容为王,但谁还不是一个颜控? 有一说一,向来我本人的站点格调都尽力放弃简洁慷慨,没有多余的功能模块,也没有花里胡哨的css和js,就是简简单单的,心愿给人一种大家闺秀的感觉。但这样,难免会短少邻家小妹的秀气,宛如房间里短少绿植,少了些许灵动。于是,我决定走进来参观哈大佬们的博客,只有这样才能够让愚蠢的我找到些许灵感,进而让我的寒舍蓬荜生辉。 对不起,我看上你家的老板娘了怀着初心,到处寻找,在TX交友网站「Github」停留好久,尤其是基于Hexo的主题更是让人目迷五色。 乱花渐欲迷人眼,浅草能力没马蹄。 —— 钱塘湖春行(白居易)为了维持现有的博客格调,天然是不能大修大改。正在迟疑时,一篇博文引起了我的留神,当然当初我曾经想不起来具体文章内容,只记得左下角有一个可可恶爱的女孩像花一样冲着我笑,还很淘气。我坦率,过后我就……霎时有了灵感。<div><video src= "https://file.mynamecoder.com/live2d_api/live2d-demo.mp4" width="200" height="250" muted autoplay loop></video></div> 是不是很二次元!点击残缺体验 过后我猜测,这个姑娘应该是该网站的老板娘,如果把她带走搁置到我的网站,岂不是会减少些许灵气? 一见倾心,我带走了他人的看板娘说干就干,查了相干材料,原来这个叫做Live2D 是一种利用于电子游戏的绘图渲染技术,技术由日本Cybernoids公司开发。通过一系列的间断图像和人物建模来生成一种相似三维模型的二维图像,对于以动画格调为主的冒险游戏来说十分有用。集成到网页中后,学术名叫看板娘,hexo官网曾经存在插件hexo-helper-live2d,然而5年前就曾经进行更新,没有新的模型,不举荐大家应用。 看着看着我就关上了控制台……<img src="https://img.mynamecoder.com/20230310114431.jpg"/>剖析了一下网络申请,原来看板娘分两块内容: 框架模型所以,首先咱们得先把框架集成到我的项目中,而后再将模型文件引入进来。 看板娘框架我又在TX交友网站「Github」依据关键词检索了一番,发现一个不错的框架stevenjoezhang/live2d-widget,反对的模型也很可恶,目前这个框架曾经开源,我曾经fork。感激该作者,阐明文档也写的很全面,此处不再赘述如何应用,次要有两种集成形式: | 形式 | 长处 | 毛病 || :-: | :-: | :-: | | 间接援用JS| 一键引入、方便快捷、节俭生命 | 不反对自定义 || 魔改框架✅ | 将源码下载后,魔改该框架,这样更符合你的网站 | 花点工夫了解框架 | 我当然抉择了魔改框架,因为我要为我的网站高级定制看板娘。 看板娘模型当你看懂这个框架之后,会发现,尽管这个框架不提供模型,然而,很显著cdnPath就是拜访模型的门路。模型的动态资源曾经放入到cdn下面了,速度却还是很慢。所以,接下来,我有一个想法:把动态资源爬下来,放到国内的cdn上。<img src="https://img.mynamecoder.com/20230310215816.jpg"/>通过剖析网络申请,发现前三个申请都是json格局的配置文件: model_list.json是展现该模型库所有的模型列表waifu-tips.json 是管制看板娘框架不同交互的提醒语,在框架中管制,不属于模型库index.json指的是以后展现的模型须要哪些配置剩下的网络申请门路全副依靠于index.json外面的配置内容所以,咱们能够得出结论,如果想要爬取这个模型库,那咱们按以下步骤:<img src="https://img.mynamecoder.com/20230310224059.png"/>人生苦短,我用python写了一个脚本爬取,次要用到的库是requests、os,在写的过程中发现一个趣事: # mkdirs居然能够反对创立带有下级门路的文件夹path = '/pic/../video'os.path.mkdirs(path) # 会创立video的文件夹# abspath能够计算绝对路径,比方输出`/pic/../video/xx.mp4`path = '/pic/../video/xx.mp4'print(os.path.abspath(path)) # 输入`/video/xx.mp4`代码我曾经上传到github下面,大家能够参考。这个仓库会更新一些平时写的脚本,老哥们感兴趣的话,能够star⭐️。通过爬取,我整顿了一下模型库,总共有27个模型,并将各个模型的名字也标注进去:<img src="https://img.mynamecoder.com/20230312225005.png"/>模型库我曾经上传到Githublive2d_models,举荐大家能够将这些模型都上传本人的cdn服务(大小70M+,不适宜放入我的项目中),而后在model_list.json配置本人喜爱的模型,cdn服务我始终用的是七牛云,一个月不到1块钱(可能是没什么访问量)<img src="https://img.mynamecoder.com/20230312230900.jpg"/>速度很快,服务稳固,价格便宜,方便管理(比方防盗链等设置),当初能够点击我的推广链接进行试用。比方,以后网站就配置了6个模型<img src="https://img.mynamecoder.com/20230313000544.jpeg" width=400 height=400/> 好啦,大家如果感兴趣能够带一个看板娘回家,如果在配置过程中遇到什么问题,能够关注微信公众号,进群交换。 本文可转载,但需申明原文出处。 程序员小明,一个很少加班的程序员。欢送关注微信公众号“程序员小明”,获取更多优质文章。

March 14, 2023 · 1 min · jiezi

关于java:Java线程池动态配置以及注意点

原始博文链接 序Java线程池这个货色也算是八股文常客了,然而自己在理论利用监控下发现了之前忽略的问题遂决定再论一番,简略谈谈Java线程池的动静配置以及对于线程池应用和了解上容易忽略的问题,置信理清之后会对线程池的优化可能有更精确的考量。首先抛出一个问题,即副标题所言:线程池线程数量超过外围线程数当前过一段时间后会缩小么?如果这个线程池放弃肯定的调用量。 注:本文所述Java版本为1.8 。 动静配置咱们晓得线程池的外围属性和成员(就构造函数的入参)次要有:corePoolSize(外围线程数)、maximumPoolSize(最大线程数)、keepAliveTime(线程闲暇回收工夫)、workQueue(寄存工作的阻塞队列)、threadFactory(线程工厂)、rejectHandler(回绝策略)。查看源码中的set办法,可知其中可能动静调整的有:corePoolSize、keepAliveTime、maximumPoolSize、rejectHandler、threadFactory以及allowCoreThreadTimeOut。而其中对线程运行状态有影响、有调整价值的次要为corePoolSize和maximumPoolSize以及keepAliveTime。这些办法的操作比我本来设想的要简略一些,间接把代码贴出来: /** * Sets the thread factory used to create new threads. * * @param threadFactory the new thread factory * @throws NullPointerException if threadFactory is null * @see #getThreadFactory */public void setThreadFactory(ThreadFactory threadFactory) { if (threadFactory == null) throw new NullPointerException(); this.threadFactory = threadFactory;}/** * Sets a new handler for unexecutable tasks. * * @param handler the new handler * @throws NullPointerException if handler is null * @see #getRejectedExecutionHandler */public void setRejectedExecutionHandler(RejectedExecutionHandler handler) { if (handler == null) throw new NullPointerException(); this.handler = handler;}/** * Sets the core number of threads. This overrides any value set * in the constructor. If the new value is smaller than the * current value, excess existing threads will be terminated when * they next become idle. If larger, new threads will, if needed, * be started to execute any queued tasks. * * @param corePoolSize the new core size * @throws IllegalArgumentException if {@code corePoolSize < 0} * @see #getCorePoolSize */public void setCorePoolSize(int corePoolSize) { if (corePoolSize < 0) throw new IllegalArgumentException(); int delta = corePoolSize - this.corePoolSize; this.corePoolSize = corePoolSize; if (workerCountOf(ctl.get()) > corePoolSize) interruptIdleWorkers(); else if (delta > 0) { // We don't really know how many new threads are "needed". // As a heuristic, prestart enough new workers (up to new // core size) to handle the current number of tasks in // queue, but stop if queue becomes empty while doing so. int k = Math.min(delta, workQueue.size()); while (k-- > 0 && addWorker(null, true)) { if (workQueue.isEmpty()) break; } }}/** * Sets the policy governing whether core threads may time out and * terminate if no tasks arrive within the keep-alive time, being * replaced if needed when new tasks arrive. When false, core * threads are never terminated due to lack of incoming * tasks. When true, the same keep-alive policy applying to * non-core threads applies also to core threads. To avoid * continual thread replacement, the keep-alive time must be * greater than zero when setting {@code true}. This method * should in general be called before the pool is actively used. * * @param value {@code true} if should time out, else {@code false} * @throws IllegalArgumentException if value is {@code true} * and the current keep-alive time is not greater than zero * * @since 1.6 */public void allowCoreThreadTimeOut(boolean value) { if (value && keepAliveTime <= 0) throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); if (value != allowCoreThreadTimeOut) { allowCoreThreadTimeOut = value; if (value) interruptIdleWorkers(); }}/** * Sets the maximum allowed number of threads. This overrides any * value set in the constructor. If the new value is smaller than * the current value, excess existing threads will be * terminated when they next become idle. * * @param maximumPoolSize the new maximum * @throws IllegalArgumentException if the new maximum is * less than or equal to zero, or * less than the {@linkplain #getCorePoolSize core pool size} * @see #getMaximumPoolSize */public void setMaximumPoolSize(int maximumPoolSize) { if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize) throw new IllegalArgumentException(); this.maximumPoolSize = maximumPoolSize; if (workerCountOf(ctl.get()) > maximumPoolSize) interruptIdleWorkers();}/** * Sets the time limit for which threads may remain idle before * being terminated. If there are more than the core number of * threads currently in the pool, after waiting this amount of * time without processing a task, excess threads will be * terminated. This overrides any value set in the constructor. * * @param time the time to wait. A time value of zero will cause * excess threads to terminate immediately after executing tasks. * @param unit the time unit of the {@code time} argument * @throws IllegalArgumentException if {@code time} less than zero or * if {@code time} is zero and {@code allowsCoreThreadTimeOut} * @see #getKeepAliveTime(TimeUnit) */public void setKeepAliveTime(long time, TimeUnit unit) { if (time < 0) throw new IllegalArgumentException(); if (time == 0 && allowsCoreThreadTimeOut()) throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); long keepAliveTime = unit.toNanos(time); long delta = keepAliveTime - this.keepAliveTime; this.keepAliveTime = keepAliveTime; if (delta < 0) interruptIdleWorkers();}能够发现这几个动静配置除了外围线程调大时会判断立即减少一些worker之外,次要操作就是赋值而后判断是否须要打断闲暇线程(调用interruptIdleworkers办法),所以线程池动静调整的外围就是给闲暇线程发送interrupt信号,咱们看一下这个打断办法,也很简略: ...

March 13, 2023 · 6 min · jiezi

关于java:Java高并发之CyclicBarrier简介

 Java 中的 CyclicBarrier 是一种同步工具,它能够让多个线程在一个屏障处期待,直到所有线程都达到该屏障处后,能力继续执行。CyclicBarrier 能够用于协调多个线程的执行,以便它们能够在某个点上同步执行。 CyclicBarrier 是 Java 中的一种同步工具,它能够让多个线程在一个屏障点处期待,直到所有线程都达到该点后,能力继续执行。CyclicBarrier 能够用于协调多个线程的执行,以便它们能够在某个点上同步执行。 应用形式CyclicBarrier 的根本用法如下: import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;public class CyclicBarrierExample { public static void main(String[] args) { int n = 3; CyclicBarrier barrier = new CyclicBarrier(n, new Runnable() { public void run() { System.out.println("All threads have reached the barrier"); } }); Thread t1 = new Thread(new MyRunnable(barrier), "Thread 1"); Thread t2 = new Thread(new MyRunnable(barrier), "Thread 2"); Thread t3 = new Thread(new MyRunnable(barrier), "Thread 3"); t1.start(); t2.start(); t3.start(); } static class MyRunnable implements Runnable { private final CyclicBarrier barrier; public MyRunnable(CyclicBarrier barrier) { this.barrier = barrier; } public void run() { try { System.out.println(Thread.currentThread().getName() + " is waiting at the barrier..."); barrier.await(); System.out.println(Thread.currentThread().getName() + " has crossed the barrier"); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }} 在这个例子中,咱们创立了一个 CyclicBarrier 对象,它须要期待 3 个线程达到屏障点。当所有线程都达到屏障点后,将会触发一个回调函数,打印一条音讯。 ...

March 13, 2023 · 2 min · jiezi

关于java:面试官如何在千万级数据中查询-10W-的数据都有什么方案

作者:变速风声 \链接:https://juejin.cn/post/7104090532015505416 前言在开发中遇到一个业务诉求,须要在千万量级的底池数据中筛选出不超过 10W 的数据,并依据配置的权重规定进行排序、打散(如同一个类目下的商品数据不能间断呈现 3 次)。 上面对该业务诉求的实现,设计思路和计划优化进行介绍,对「千万量级数据中查问 10W 量级的数据」设计了如下计划 多线程 + CK 翻页计划ES scroll scan 深翻页计划ES + Hbase 组合计划RediSearch + RedisJSON 组合计划初版设计方案整体方案设计为: 先依据配置的「筛选规定」,从底池表中筛选出「指标数据」在依据配置的「排序规定」,对「指标数据」进行排序,失去「后果数据」技术计划如下: 每天运行导数工作,把现有的千万量级的底池数据(Hive 表)导入到 Clickhouse 中,后续应用 CK 表进行数据筛选。将业务配置的筛选规定和排序规定,构建为一个「筛选 + 排序」对象 SelectionQueryCondition。从 CK 底池表取「指标数据」时,开启多线程,进行分页筛选,将获取到的「指标数据」寄存到 result 列表中。//分页大小 默认 5000int pageSize = this.getPageSize();//页码数int pageCnt = totalNum / this.getPageSize() + 1;List<Map<String, Object>> result = Lists.newArrayList();List<Future<List<Map<String, Object>>>> futureList = new ArrayList<>(pageCnt);//开启多线程调用for (int i = 1; i <= pageCnt; i++) { //将业务配置的筛选规定和排序规定 构建为 SelectionQueryCondition 对象 SelectionQueryCondition selectionQueryCondition = buildSelectionQueryCondition(selectionQueryRuleData); selectionQueryCondition.setPageSize(pageSize); selectionQueryCondition.setPage(i); futureList.add(selectionQueryEventPool.submit(new QuerySelectionDataThread(selectionQueryCondition)));}for (Future<List<Map<String, Object>>> future : futureList) { //RPC 调用 List<Map<String, Object>> queryRes = future.get(20, TimeUnit.SECONDS); if (CollectionUtils.isNotEmpty(queryRes)) { // 将指标数据寄存在 result 中 result.addAll(queryRes); }}对指标数据 result 进行排序,失去最终的「后果数据」。 ...

March 13, 2023 · 3 min · jiezi

关于java:classgetResourceAsStream用法和Properties工具类

定义文件内容为:ip = 14554.5454.656port=8754name=rerepassword=545kgf 程序读取配置文件属性:String propertiesName = "/commonTool.properties";getResourceAsStream办法的参数,如果最后面是正斜杆/,那么则从我的项目根目录开始查找,留神是我的项目根目录不是磁盘根目录。 用法为:App.class.getResourceAsStream(propertiesName),App这个类能够任意替换成其余类,对后果没有影响,因为都是从根目录开始查找。 如果不加正斜杆/,那么则从该办法的调用者class所在的目录查找。 用法为:App.class.getResourceAsStream(propertiesName)//App.java和app.txt在同一个目录,App这个类不能随便替换成其余类,只能替换成同一个包下的类,不然找不到文件。 InputStream defaultIns = CommonToolProUtil.class.getResourceAsStream(propertiesName); props = new Properties(); try { props.load(defaultIns); } catch (IOException e) { logger.error("can't read common tool properties about : {}", propertiesName); }获取某个属性:props.getProperty(proName);

March 13, 2023 · 1 min · jiezi

关于java:Spring-Boot-分片上传断点续传大文件上传秒传应有尽有建议收藏

文件上传是一个陈词滥调的话题了,在文件绝对比拟小的状况下,能够间接把文件转化为字节流上传到服务器,但在文件比拟大的状况下,用一般的形式进行上传,这可不是一个好的方法,毕竟很少有人会忍耐,当文件上传到一半中断后,持续上传却只能重头开始上传,这种让人不爽的体验。那有没有比拟好的上传体验呢,答案有的,就是下边要介绍的几种上传形式。 1、分片上传1.1 什么是分片上传分片上传,就是将所要上传的文件,依照肯定的大小,将整个文件分隔成多个数据块(咱们称之为Part)来进行别离上传,上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件。 1.2 分片上传的场景大文件上传网络环境环境不好,存在须要重传危险的场景2断点续传2.1 什么是断点续传断点续传是在下载或上传时,将下载或上传工作(一个文件或一个压缩包)人为的划分为几个局部,每一个局部采纳一个线程进行上传或下载,如果碰到网络故障,能够从曾经上传或下载的局部开始持续上传或者下载未实现的局部,而没有必要从头开始上传或者下载。 本文的断点续传次要是针对断点上传场景。 2.2 利用场景断点续传能够看成是分片上传的一个衍生,因而能够应用分片上传的场景,都能够应用断点续传。 2.3 实现断点续传的外围逻辑在分片上传的过程中,如果因为零碎解体或者网络中断等异样因素导致上传中断,这时候客户端须要记录上传的进度。在之后反对再次上传时,能够持续从上次上传中断的中央进行持续上传。 为了防止客户端在上传之后的进度数据被删除而导致从新开始从头上传的问题,服务端也能够提供相应的接口便于客户端对曾经上传的分片数据进行查问,从而使客户端晓得曾经上传的分片数据,从而从下一个分片数据开始持续上传。 整体的过程如下: 前端将文件装置百分比进行计算,每次上传文件的百分之一(文件分片),给文件分片做上序号后端将前端每次上传的文件,放入到缓存目录期待前端将全副的文件内容都上传完毕后,发送一个合并申请后端应用RandomAccessFile进多线程读取所有的分片文件,一个线程一个分片后端每个线程依照序号将分片的文件写入到指标文件中在上传文件的过程中产生断网了或者手动暂停了,下次上传的时候发送续传申请,让后端删除最初一个分片前端从新发送上次的文件分片2.4 实现流程步骤计划一,惯例步骤 将须要上传的文件依照肯定的宰割规定,宰割成雷同大小的数据块;初始化一个分片上传工作,返回本次分片上传惟一标识;依照肯定的策略(串行或并行)发送各个分片数据块;发送实现后,服务端依据判断数据上传是否残缺,如果残缺,则进行数据块合成失去原始文件。计划二、本文实现的步骤 前端(客户端)须要依据固定大小对文件进行分片,申请后端(服务端)时要带上分片序号和大小。服务端创立conf文件用来记录分块地位,conf文件长度为总分片数,每上传一个分块即向conf文件中写入一个127,那么没上传的地位就是默认的0,已上传的就是Byte.MAX_VALUE 127(这步是实现断点续传和秒传的外围步骤)服务器依照申请数据中给的分片序号和每片分块大小(分片大小是固定且一样的)算出开始地位,与读取到的文件片段数据,写入文件。整体的实现流程如下: 3、分片上传/断点上传代码实现3.1 前端实现前端的File对象是非凡类型的Blob,且能够用在任意的Blob类型的上下文中。 就是说可能解决Blob对象的办法也能解决File对象。在Blob的办法里有有一个Slice办法能够帮实现切片。 举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practice外围代码: fileMD5 (files) { // 计算文件md5 return new Promise((resolve,reject) => { const fileReader = new FileReader(); const piece = Math.ceil(files.size / this.pieceSize); const nextPiece = () => { let start = currentPieces * this.pieceSize; let end = start * this.pieceSize >= files.size ? files.size : start + this.pieceSize; fileReader.readAsArrayBuffer(files.slice(start,end)); }; let currentPieces = 0; fileReader.onload = (event) => { let e = window.event || event; this.spark.append(e.target.result); currentPieces++ if (currentPieces < piece) { nextPiece() } else { resolve({fileName: files.name, fileMd5: this.spark.end()}) } } // fileReader.onerror = (err => { reject(err) }) nextPiece() })}当然如果咱们是vue我的项目的话还有更好的抉择,咱们能够应用一些开源的框架,本文举荐应用vue-simple-uploader 实现文件分片上传、断点续传及秒传。 ...

March 13, 2023 · 6 min · jiezi

关于java:推荐一套轻量级的开源图床系统Light-Fast-Picture

如果您跟我一样平时有些博客的习惯,那么图片存储是否有困扰过你呢?明天就给大家举荐一款不错的开源图床零碎:Light Fast Picture 它是一个基于koa + vue3.x + typescript实现的图床工具。它能够帮忙用户疾速上传图片到云端,并返回图片链接,不便用户在网页、社交媒体等平台上分享图片。 它的性能曾经十分丰盛,满足咱们对图片治理的日常需要 图片上传:反对图片多图上传、拖拽上传、粘贴上传、一键复制多种格局的图片外链。图片治理:多上传的图片进行治理,反对文件重命名、移入指定相册、删除图片、预览图片等。存储桶治理:反对多桶贮存,可同时增加多个对象存储桶治理,上不封顶,例如:七牛云对象存储、阿里云对象存储、腾讯云对象存储等等,零碎会统计出每个存储桶下的图片数量以及已应用存储量。同时也反对管制存储桶是否显示在上传区。相册治理:反对相册治理,能够对图片进行分组分类管理,便于用户将不同的图片进行分类挂办理,同时也反对间接将图片上传到相册中。操作日志治理:残缺的可视化日志性能,记录用户所有操作,不便事件溯源。普通用户只能查看本人的操作记录,管理员则能查看所有人员的操作记录,于此同时数据统计中的奉献图的数据起源也是从操作记录中提取。个人信息保护:用户能够对本人的信息管理,如头像(零碎内置4组不同维度的头像供选择)、昵称、职业、性别、个人简介以及集体登录明码进行保护治理。数据统计:零碎提供了数据统计性能,统计用户的图片数量、存储桶数量、总占用存储量、相册数量以及零碎贡献度数据进行统计。应用习惯配置:思考到每个用户的应用习惯不同,零碎提供了应用习惯配置核心,能够对默认复制的图片链接格局、自定义链接格局、罕用快捷键配置以及是否开启上传胜利提醒、复制链接胜利提醒等配置。用户治理:多用户治理,依据不同的角色能够治理不同的数据,同时用户能够通过自主注册或者管理员在治理页面间接创立。存储桶插件治理:存储桶治理,是由管理员进行在线开发的插件,用于管理员对存储桶插件的相干配置,须要做什么前置解决或者后置解决等进行治理,例如七牛云对象存储,须要用户在界面上感知出须要填写哪些数据、哪些数据时必填项、有哪些数据的智能提醒,须要前置操作则是获取上传认证,其实就是对存储桶领有哪些元数据进行配置,于此同时还提供了是否启用或者禁用的性能,比方某一个对象存储曾经从市面上out,则管理员能够进行禁用操作,这样用户就不能创立该类型的存储桶。字典治理:对系统中常常应用的一些较为固定的数据进行保护,例如集体核心的职业、用户性别、存储桶页面不同的存储桶类别展现不同的图标等数据保护。零碎设置:对系统中一些罕用的数据进行保护,包含零碎名称、零碎logo、备案信息、更新日志、零碎上所应用的的图标的起源进行配置。权限管制:残缺的权限管制性能,不同的角色可调配不同的操作权限,管制对应的删除及查看。一款开源软件做到这个水平,曾经十分优良了,如果合乎你的需要的话,连忙试试看吧。欢送扫描下方二维码,关注公众号:TJ君,订阅每日举荐,获取更多好用效率工具 在线体验地址:http://picture.itchenliang.club/#/账号:guest@163.com明码:000000 最初,奉上我的项目地址:https://github.com/ischenliang/quickly-picture-bed 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

March 13, 2023 · 1 min · jiezi

关于java:Orika-JavaBean映射工具使用

作者:京东批发 张宾 1.Orika是什么?Orika是一个简略、疾速的JavaBean拷贝框架,它可能递归地将数据从一个JavaBean复制到另一个JavaBean,这在多层利用开发中是十分有用的。 2.为什么要引入Orika?工作中,咱们常常须要将对象转换成不同的模式以适应不同的api,或者在不同业务层中传输对象而不同分层的对象存在不同的格局,因而咱们须要编写映射代码将对象中的属性值从一种类型转换成另一种类型。 Orika用于简化多层之间的对象映射,防止苦苦挣扎于手工编码和基于反射的映射。Orika关注尽可能地自动化,同时依据须要提供配置和扩大实现定制。 3.我的项目罕用javabean映射技术Java反射:性能问题、无奈解决嵌套javabean映射复制 手工映射:硬编码、代码量大 序列化形式:通过json、xml的序列化和反序列化形式,字段参数不雷同时,须要硬编码赋值 4.罕用bean映射工具BeanUtils:apache的BeanUtils和spring的BeanUtils中拷贝办法的原理都是先用jdk中 java.beans.Introspector类的getBeanInfo()办法获取对象的属性信息及属性get/set办法,接着应用反射(Method的invoke(Object obj, Object... args))办法进行赋值。apache反对名称雷同但类型不同的属性的转换,spring反对疏忽某些属性不进行映射,他们都设置了缓存保留已解析过的BeanInfo信息。 BeanCopier:cglib的BeanCopier采纳了不同的办法:它不是利用反射对属性进行赋值,而是间接应用ASM的MethodVisitor间接编写各属性的get/set办法(具体过程可见BeanCopier类的generateClass(ClassVisitor v)办法)生成class文件,而后进行执行。因为是间接生成字节码执行,所以BeanCopier的性能较采纳反射的BeanUtils有较大进步。 Orika:底层采纳了javassist类库生成Bean映射的字节码,之后间接加载执行生成的字节码文件,因而在速度上比应用反射进行赋值会快很多。Orika反对递归映射,将映射嵌套类直到用“简略”类型实现映射。它还蕴含故障保险,以正确处理正在尝试映射的对象中的递归援用。 5.如何应用Orika?5.1 maven依赖<dependency> <groupId>ma.glasnost.orika</groupId> <artifactId>orika-core</artifactId> <version>1.5.2</version> </dependency> 5.2 两个javabean字段名称雷同映射MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); //字段名雷同映射 mapperFactory.classMap(Person.class, PersonInfo.class).byDefault().register(); MapperFacade mapperFacade = mapperFactory.getMapperFacade(); Person person = new Person(); person.setFirstName("张"); person.setLastName("三"); PersonInfo personInfo = mapperFacade.map(person, PersonInfo.class); 输入后果: 5.3 两个javabean字段名称不雷同映射MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); mapperFactory.classMap(Person.class, PersonDesc.class) .field("firstName", "givenName").field("lastName", "sirName") .byDefault() .register(); MapperFacade mapperFacadeDesc = mapperFactory.getMapperFacade(); Person personNew = new Person(); ...

March 13, 2023 · 2 min · jiezi

关于java:AI来实现代码转换Python转JavaJava转Go不在话下

明天看到个乏味的网站,给大家分享一下。 该网站的性能很神奇,能够实现编程语言的转化。感觉在一些场景之下还是有点作用的,比方你原来跟我一样是做Java的,因为工作须要忽然转Go。这个时候用你Java的教训 + 这个工具,或者能够起到肯定的帮忙作用。 工具的应用也很简略,只须要在左侧黏贴你想转换的原始代码,而后点击CONVERT CODE,右侧输入框就会转换成指标代码: 像上面这样更加简单的代码转换也是不在话下: const fs = require('fs'); const AWS = require('aws-sdk'); const s3 = new AWS.S3({ accessKeyId: process.env.AWS_ACCESS_KEY, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY }); const fileName = 'contacts.csv'; const uploadFile = () => { fs.readFile(fileName, (err, data) => { if (err) throw err; const params = { Bucket: 'testBucket', // pass your bucket name Key: 'contacts.csv', // file will be saved as testBucket/contacts.csv Body: JSON.stringify(data, null, 2) }; s3.upload(params, function(s3Err, data) { if (s3Err) throw s3Err }); }); }; uploadFile();能够看到其中还蕴含了aws的内容,竟然也能顺利的转成Java ...

March 12, 2023 · 2 min · jiezi

关于java:在Java中使用HttpUtils实现发送HTTP请求

微信公众号:冯文议(ID:fwy-world)HTTP申请,在日常开发中,还是比拟常见的,明天给大家分享HttpUtils如何应用。 浏览本文,你将播种: 简略总结HTTP申请罕用配置;JavaLib中HttpUtils如何应用;如何封装HTTP申请工具类。第一局部:简略总结HTTP申请罕用配置大家好,在 Java 开发中,常常遇到须要调用第三方提供的接口服务,常见的模式是 HTTP + JSON,上面,就对 http 申请常见的设置,做一个阐明 http提供多种申请形式,以满足咱们日常须要,先按申请形式来做阐明: GETPOSTPUTPATCHDELETE在 RESTful API 开发中,咱们能够依据这些申请形式设计咱们的API接口。举例: GET:获取资源POST:提交资源PUT:更新残缺资源PATCH:更新局部资源DELETE:删除资源参数格局 form表单json其余 超时工夫设置第二局部:应用JavaLib的HttpUtils简略的get申请 System.out.println(HttpUtils.get("https://www.baidu.com"));响应后果: 通过简略尝试,证实两点: 一是,这个还是能够应用的;二是,原来应用如此简略。如果要你手写一个http申请,或者你脑海里一篇空白,会去搜寻各种材料。 咱们再试一个简单的 接口: 接口地址:https://erwin-api.fengwenyi.com/erwin/blog/page申请办法:GET参数:currentPage,pageSize参数格局:form响应:application/json String url = "https://erwin-api.fengwenyi.com/erwin/bookmark/page?currentPage=1&pageSize=10";Request request = new Request();request.setUrl(url);request.setMethod(Request.Method.GET);Map<String, String> headerMap = new HashMap<>();headerMap.put("Accept", "application/json");Request.Option option = new Request.Option();option.setHeaders(headerMap);try { System.out.println(HttpUtils.execute(request, option));} catch (IOException e) { throw new RuntimeException(e);}响应后果: { "code":"SUCCESS", "message":"Success", "success":true, "header":null, "body":{ "currentPage":1, "pageSize":10, "totalRows":661, "totalPages":67, "content":[ { "id":"1634772578877935617", "timestamp":1678595130000, "enabledState":null, "name":"VScode 中文显示呈现黄色方框的解决办法_vscode汉字被框住_YJer的博客-CSDN博客", "url":"https://blog.csdn.net/qq_33249042/article/details/123252625", "icon":null, "classifyName":"软件", "classifyId":"1522587269600481281" }, { "id":"1632640455110922241", "timestamp":1678086792000, "enabledState":null, "name":"Spring中init-method和destroy-method的四种形式_星夜孤帆的博客-CSDN博客", "url":"https://blog.csdn.net/qq_38826019/article/details/117387398", "icon":null, "classifyName":"Spring", "classifyId":"1522586360887742466" }, { "id":"1631597310596190209", "timestamp":1677838087000, "enabledState":null, "name":"vue3 + elemenplus实现导航栏 - 掘金", "url":"https://juejin.cn/post/7084871748608327687", "icon":null, "classifyName":"前端", "classifyId":"1525554881275990018" }, { "id":"1631593154401636354", "timestamp":1677837096000, "enabledState":null, "name":"Spring bean 创立过程源码解析 - 腾讯云开发者社区-腾讯云", "url":"https://cloud.tencent.com/developer/article/1631160", "icon":null, "classifyName":"Spring", "classifyId":"1522586360887742466" }, { "id":"1631592987673858050", "timestamp":1677837056000, "enabledState":null, "name":"SpringBoot之容器启动源码剖析与Bean加载_springboot加载bean 源码_minemine0418的博客-CSDN博客", "url":"https://blog.csdn.net/minemine0418/article/details/102308912", "icon":null, "classifyName":"Spring Boot", "classifyId":"1522586446766116865" }, { "id":"1631586585454678018", "timestamp":1677835530000, "enabledState":null, "name":"Spring-Bean生命周期 - 知乎", "url":"https://zhuanlan.zhihu.com/p/158468104", "icon":null, "classifyName":"Spring", "classifyId":"1522586360887742466" }, { "id":"1631579732104548354", "timestamp":1677833896000, "enabledState":null, "name":"一文读懂 Spring Bean 的生命周期_spring bean的生命周期_老周聊架构的博客-CSDN博客", "url":"https://blog.csdn.net/riemann_/article/details/118500805", "icon":null, "classifyName":"Spring", "classifyId":"1522586360887742466" }, { "id":"1630768897186697218", "timestamp":1677640578000, "enabledState":null, "name":"MySQL同时统计多个条件的记录条数_ztnhnr的博客-CSDN博客", "url":"https://blog.csdn.net/ztnhnr/article/details/107165942", "icon":null, "classifyName":"MySQL", "classifyId":"1522586805693681666" }, { "id":"1630768792098410497", "timestamp":1677640553000, "enabledState":null, "name":"sql查问近七天,近两周,近一个月的数据_sql最近一周数据_心诚则灵'的博客-CSDN博客", "url":"https://blog.csdn.net/wenchangwenliu/article/details/119891790", "icon":null, "classifyName":"MySQL", "classifyId":"1522586805693681666" }, { "id":"1630480535938764801", "timestamp":1677571827000, "enabledState":null, "name":"开源流程引擎哪个好,如何选型? - 知乎", "url":"https://zhuanlan.zhihu.com/p/369761832", "icon":null, "classifyName":"Java", "classifyId":"1522586296119300097" } ] }}响应后果,还是合乎预期的。 ...

March 12, 2023 · 2 min · jiezi

关于java:比cat更好用的命令

大家好,我是良许。 作为程序员,大家肯定对 cat 这个命令不生疏。它次要的性能就是用来显示文本文件的具体内容。 但 cat 命令两个很重大的缺点:1. 不能语法高亮输入;2. 文本太长的话无奈翻页输入。正是这两个有余,使得 cat 只能用来查看行数不多的小文件。 为了解决 cat 命令这两个毛病,国外有大牛将 cat 命令进行了加强,弱小到连 cat 亲妈都不意识! 它就是本文的配角:bat 命令。 bat 命令能够用来做啥呢?简略来说有上面这些: 语法高亮。它能够依据编程语言以及 markdown 语法将文本关键词高亮,可浏览性大大加强;主动翻页。如果文本内容太长,超过一页的话,它会主动将内容通过管道传到 less 命令,实现翻页的成果;集成Git。bat 命令跟 git 完满联合,将文本的批改局部在左侧展现,一眼就能够看出文件批改了啥。显示不可打印字符。有些字符无奈通过 cat 在屏幕上显示,但 bat 让它们无处遁形!bat 的这些个性,真的是分分钟让 cat 打下神坛!(怪不得人家是以 b 结尾的,牛 B 的 B !) 1. bat命令的装置当初很多 Linux 发行版的官网源曾经内置了这个命令,所以只需应用它们对应的装置工具就能够装置。 以 Ubuntu 为例,只须要运行以下命令就能够装置 bat : $ sudo apt-get install bat这里要留神一下,因为名称的抵触,在 Ubuntu 下无奈间接通过敲 bat 这三个字母运行 bat 命令,而是须要敲 batcat 。为了不便,咱们能够设置别名: $ alias "bat=batcat"2. bat命令的应用2.1 根本应用bat 命令的用法跟 cat 大差不差的,咱们间接上图来看下比照。 ...

March 12, 2023 · 1 min · jiezi

关于java:Java并发编程-锁

本文次要答复以下问题:1.锁是什么,有哪些类型的锁,什么时候须要锁,以及锁的实现原理;2.如何正确地应用锁;有哪些潜在的问题;3.如何晋升并发的性能(例如缩小锁竞争,JVM的锁优化,原子类,非阻塞算法,无锁算法);1. 锁的类型从不同的角度或性能来对锁进行分类,使锁的类型有很多。上面表格列出了一些常见的锁类型。 类型定义例子长处毛病显示锁须要通过代码显示地加锁和开释锁,JDK1.5引入Lock,ReentrantLock加锁灵便,期待锁可设置超时工夫并且可被中断须要写加锁和开释锁的代码内置锁又叫隐式锁,应用关键字后由JVM主动地加锁和开释锁。每个对象都能够用作锁对象synchronized关键字代码简洁,不必关怀锁的获取与开释;可重入1.期待锁时无奈被中断;2.申请锁时会有限期待上来乐观锁乐观锁和乐观锁是一种锁的设计思维。乐观锁总认为数据不会被其余线程批改,所以写操作前不会对资源加锁,当最坏状况产生时再采取其余措施CAS操作,版本号机制锁竞争少,性能高。实用于读多写少的场景只能保障单个变量的原子性。ABA问题。乐观锁乐观锁总认为最坏的状况会呈现,数据很可能被其余线程批改,所以它总会把资源锁住synchronized锁,ReentrantLock等加锁灵便。实用于写多读少的场景锁竞争强烈,性能较低偏心锁按线程申请锁的程序取得锁FairSync,继承自AQS不会呈现线程饿死性能较低非偏心锁不是按申请锁的程序,而是容许”插队“取得锁。synchronized 和 ReentrantLock 默认都是非偏心锁NonfairSync,继承自AQS性能高,防止了线程频繁的休眠和复原可能呈现线程饿死独占锁独占锁(排它锁)和共享锁是从多个线程是否能够同时获取同一个锁的角度来分的。独占锁在同一时刻只能被一个线程所持有写锁,synchronized锁既能够读取数据,也能够批改数据锁抵触增多,并发度升高共享锁共享锁可能被多个线程所领有,某个线程对资源加上共享锁后,其余线程只能对其再加共享锁,不能加独占锁。取得共享锁的线程只能读数据,不能批改数据读锁进步并发度不能批改数据互斥锁同一时刻只能有一个线程领有共享资源,加锁后其余线程无奈获取该共享资源,保障资源批改的原子性,和独占锁相似synchronized锁能够读取和批改资源并发度不高可重入锁又叫递归锁,可反复可递归调用的锁,在外层获取锁后在内层能够持续获取此锁,通过锁记录器累计锁的次数ReentrantLock,synchronized锁有助于防止死锁可能导致不变量的不统一,不能确定获取锁和开释锁时不变量放弃不变读锁是一种共享锁,加锁后只可读数据,读锁之间不互斥。ReentrantReadWriteLock提供了读锁和写锁ReentrantReadWriteLock.ReadLock并发读取十分高效不能写数据否则会有线程平安问题写锁是一种独占锁,加锁后可写数据和读数据,读写、写读和写写都是互斥的ReentrantReadWriteLock.WriteLock可读可写相比读锁比拟低效自旋锁没有获取到锁的线程始终循环判断资源是否开释锁,而不会被挂起(阻塞)的循环加锁-期待机制TicketLock,CLHLock防止了线程切换的开销,锁工夫较短时十分高效占用CPU工夫分布式锁对运行在集群上的分布式应用的共享资源进行加锁,是一种跨机器的互斥机制。要求高可用。Redis,Redlock,Zookeeper,数据库解决分布式场景的互斥问题和一致性问题与单机锁相比不够简洁可靠性较低。高并发下存在锁性能问题可中断锁在申请锁时能够被中断,即收到中断信号会进行锁的申请,并抛出中断异样ReentrantLock.lockInterruptibly()有助于防止死锁 不可中断锁在申请锁时不可被中断,始终期待锁synchronized锁 异常情况时不能进行申请锁,易造成死锁偏差锁当一段同步代码始终被同一个线程所拜访时(即不存在多个线程的竞争时),那么该线程在后续拜访时便会主动取得锁(无需任何同步操作),从而升高取得锁带来的开销JDK1.6开始synchronized的优化,默认开启偏差锁。JDK15改为默认敞开没有锁竞争时性能高有锁竞争时很快生效,JDK保护老本高轻量级锁应用CAS申请锁,没有拿到锁的线程会自旋期待(自旋锁),默认最大自旋10次。不挂起线程,从而进步性能synchronized偏差锁降级到轻量级锁锁竞争较低时性能高锁竞争较高时很快生效重量级锁当有一个线程获取锁之后,其余所有期待获取该锁的线程都会处于阻塞状态。线程调度交给操作系统synchronized轻量级锁降级到重量级锁,可重入锁无锁撤销的问题性能较低思考题:1.乐观锁会加锁吗?2.为什么wait和notify办法放在Object类里? 2. 加锁机制锁的实质是什么? 锁是一种同步机制,管制并发程序对共享资源的拜访,线程持有锁时才能够对共享资源进行拜访。在锁的实现上,锁是一个数据标记。 2.1 内置锁(synchronized)的原理每个Java对象都能够作为一个锁,这个锁被称为内置锁或监视器锁(Monitor Lock)。内置锁的长处是:进入synchronized润饰的同步代码块前会主动去取得锁,在退出(包含抛出异样退出)同步代码块时主动开释锁。 内置锁通过更改对象头里的锁状态位来加锁和开释锁(对象头的构造上面会展现)。同步的实现依赖于monitor对象(HotSpot虚拟机里的monitor实现是ObjectMonitor对象),每个Java对象都能够有一个对应的monitor对象与之关联。ObjectMonitor对象中有两个队列_WaitSet 和 _EntryList,用来保留ObjectWaiter对象(封装了期待的线程)列表,monitor对象的同步形式如下: 如上图所示,新的线程会进入EntryList,当一个持有锁的线程开释monitor时,在入口区(EntryList)和期待区(WaitSet)的线程都会去竞争监视器(图中Owner所在区域)。Monitor对象只能有一个owner,一个线程成为监视器的owner后如果须要期待某个条件而执行了wait()办法,那么这个线程会开释锁并进入WaitSet(第3步所示)。 32位JVM的对象构造:1.对象头:由 MarkWord(32bit) + ClassMeta地址(32bit) 组成。在无锁状态时MarkWord的存储构造为:对象hashcode-25bit,对象分代年龄-4bit,是否偏差锁-1bit,锁标记位-2bit。32位JVM的MarkWord和ClassMeta地址别离占用32bit,64位JVM的MarkWord和ClassMeta地址别离占用64bit。2.实例数据;3.对齐填充的数据;JVM要求对象的起始地址必须是8字节的整数倍。对象头的MarkWord存储构造:(锁状态这列为每行的含意) 在JDK1.6时,虚拟机团队对synchronized进行了一系列的优化。在此之前,synchronized是一个重量级锁,效率比拟低。优化后,synchronized一开始是无锁或偏差锁(MarkWord后三位是001或101),随着锁竞争水平的加剧,才开始锁降级:无锁 -> 偏差锁 -> 轻量级锁 -> 重量级锁。留神,锁降级是一个不可逆的过程。 synchronized的执行过程:1.查看MarkWord里是不是以后线程的ID,如果是,示意以后线程处于偏差锁;2.如果不是,则用CAS操作将以后线程ID替换进MardWord;如果胜利则示意以后线程取得偏差锁,置偏差标记位1;3.如果失败,则阐明产生锁竞争,撤销偏差锁,并降级为轻量级锁;4.以后线程应用CAS将对象头的MarkWord替换为栈中锁记录指针;如果胜利,以后线程取得锁;5.如果失败,示意其余线程竞争锁,以后线程便尝试应用自旋来获取锁;6.如果自旋胜利则仍然处于轻量级锁状态;7.如果自旋失败,则降级为重量级锁。 如果线程争用强烈,那么应该禁用偏差锁(-XX:-UseBiasedLocking),JDK1.6之后偏差锁是默认开启的,JDK15偏差锁改为默认敞开(开启配置-XX:+UseBiasedLocking)。 2.2 可重入锁(ReentrantLock)的原理2.2.1惯例用法Lock lock = new ReentrantLock(false); // 参数为空时,默认创立非偏心锁lock.lock(); try { operation-xx(); // 业务解决逻辑} finally { lock.unlock(); // 放在finally中确保锁开释}2.2.2 ReentrantLock的实现ReentrantLock的实现基于AbstractQueuedSynchronizer(简写为AQS),可重入性能基于AQS的同步状态字段(也是锁标记字段):state。state用来示意所有者线程曾经反复取得该锁的次数。 可重入锁的原理:当某一线程获取锁后,将state值加1,并记录下以后持有锁的线程标识,以便查看是否是反复获取锁,以及检测线程开释锁时是否非法;再有线程来获取锁时,判断这个线程与持有锁的线程是否是同一个线程,如果是,将state值再加1;如果不是,则阻塞新来的线程。在线程开释锁时,将state值减1;当state值减为0时,示意以后线程彻底开释了锁。 ReentrantLock没有间接继承AQS类,而是在外部定义了一个公有外部类Sync来继承AQS类,而后把本人的同步办法的实现都委托给这个公有外部类。这种同步器实现形式也是AQS作者Doug Lea倡议的形式。ReentrantLock的类间关系如下图所示: 2.2.3 AQS类介绍j.u.c包中大部分的同步器(例如锁,屏障等)都是基于AQS类构建的。AQS为同步状态的原子性治理、线程的阻塞和解除阻塞以及排队提供了一种通用的机制。同步器个别蕴含两种根本办法,一种是acquire,另一种是release。acquire操作用于阻塞调用的线程,直到或除非同步状态容许其继续执行。而release操作则是通过某种形式扭转同步状态,使得一或多个被acquire阻塞的线程继续执行。 acquire操作包含:Lock.lock,Semaphore.acquire,CountDownLatch.await 等。release操作包含:Lock.unlock,Semaphore.release,CountDownLatch.countDown 等。AQS封装了实现同步器时波及的大量细节问题,极大地缩小了同步器的实现工作,只用依据须要重写几个AQS的protected办法(tryAcquire/TryAcquireShard,tryRelease/tryReleaseShared,getState,setState等)即可。整个AQS框架的要害是如何治理被阻塞线程的链表队列,该队列是严格的FIFO队列(但不肯定是偏心的)。AQS抉择了CLH锁作为实现此队列的根底,因为CLH锁能够更容易地去实现“勾销(cancellation)”和“超时”性能。 AQS框架提供了一个ConditionObject类,给保护独占同步的类以及实现Lock接口的类应用。此条件对象提供了await、signal和signalAll操作,AQS在一个独自的条件队列中保护这些条件对象节点,其中signal操作是通过将节点从条件队列转移到锁队列(即上述的CHL链表队列)中来实现的。 应用AQS框架构建同步器时,将AQS的子类作为同步器抽象类并不适宜,因为AQS子类必须提供办法在外部管制acquire和release的规定,但这些办法都应该对用户暗藏。倡议的做法是在定义的同步器类外部申明一个AQS子类作为公有外部类,把所有同步办法都委托给这个公有外部类,j.u.c包里的同步器类都是这种用法(应用公有外部类Sync)。AQS框架的应用例子: ReentrantLock类代码截图 3. 死锁3.1 什么是死锁经典的“哲学家进餐”问题很好的形容了死锁的情况,当上面这种状况呈现时将产生死锁:每个哲学家都领有其他人须要的资源(一根筷子),同时又期待其他人曾经领有的资源(一根筷子),并且每个人在取得所需资源(两根筷子)前都不会放弃曾经领有的资源。此时每个哲学家都在期待另一根筷子,在没有外力干预的状况下,他们会始终期待上来,这就是死锁,所有哲学家都将“饿死”。 当死锁呈现时,往往是在最蹩脚的时候 - 零碎高负载时,因为这时并发最高竞争也最强烈。推波助澜莫过如此。 上面介绍死锁的几种类型,包含:锁程序死锁,动静的锁程序死锁,合作对象之间的死锁,资源死锁。 ...

March 12, 2023 · 2 min · jiezi

关于java:线程池-ThreadPoolExecutor源码分析

之所以存在线程池是基于以下两个起因: 线程的创立和销毁是须要有资源耗费的,多线程环境下频繁创立、销毁线程会影响零碎性能对于一个须要频繁创立工作、线程的利用来说,创立的工作数、线程数须要受到管制或治理有了线程池,尤其是相似ThreadPoolExecutor这种能够通过参数调整其行为的线程池,能够近乎完满的解决上述两个问题。 线程池工作原理简略来说线程池的工作原理就是:提前或者在执行工作的时候创立线程,执行完工作之后不销毁线程而是将线程偿还到线程池中,后续有工作提交上来之后就能够不再创立线程、而是由线程池中闲暇的线程执行工作。 这样一来就能够防止频繁创立和销毁线程,并且也能够控制线程池中线程的数量,同时如果提交工作的速度太快、线程池中的线程来不及执行工作的话,能够将工作放在队列中期待,等后面的工作执行实现、线程偿还到线程池中之后,再从队列中获取工作继续执行。 其实以上就是ThreadPoolExecutor性能的简略形容。 当然ThreadPoolExecutor的性能要比这个形容弱小的多也简单的多。咱们就从以下几个方面来详细分析一下ThreadPoolExecutor的性能和底层原理: 根本属性工作队列创立线程池提交工作执行工作回绝工作钩子函数根本属性corePoolSize&maximumPoolSize:ThreadPoolExecutor有外围线程数(corePoolSize)和最大线程数(maximumPoolSize)的概念,新工作提交后,如果以后线程数小于corePoolSize,即便线程池中有闲暇线程,ThreadPoolExecutor也会立刻创立一个线程去执行工作。如果以后线程数大于corePoolSize且小于maximumPoolSize,则只有队列满的状况下才会创立线程、否则工作入队列排队。 ctl:绑定了状态runState和线程数workerCount两个属性的AtomicInteger变量: private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));了解ctl的工作原理是读懂ThreadPoolExecutor源码的必要前提。 先看两个辅助变量: private static final int COUNT_BITS = Integer.SIZE - 3; private static final int CAPACITY = (1 << COUNT_BITS) - 1;COUNT_BITS是Integer.size-3=31-3=29,CAPACITY是1向左位移29位后减1,用二进制示意就是: 0001 1111 1111 1111 1111 1111 1111 1111 ~CAPACITY用二进制示意就是: 1110 0000 0000 0000 0000 0000 0000 0000 // runState is stored in the high-order bits private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS; // Packing and unpacking ctl private static int runStateOf(int c) { return c & ~CAPACITY; } private static int workerCountOf(int c) { return c & CAPACITY; } private static int ctlOf(int rs, int wc) { return rs | wc; }runState有RUNNING、SHUTDOWN、STOP、TIDYING和TERMINATED等5个状态,压入ctl示意的时候全副要左移29位。意思是:ctl是依照2进制位来表白含意的,高位的3位用来示意状态runstate,低位的29位用来示意线程数workerCount。 ...

March 11, 2023 · 4 min · jiezi

关于java:微软的148座坟墓

深夜档分享,给大家介绍一个黑白的、“惊悚”的网站! 从名字来看(killed by microsoft),是不是猜到点端倪了? 这个神奇的网站竟然收录了微软死于非命的那些软件。这是一个收费的开放源码列表,其中列出了已停产的微软服务、产品、设施和应用程序。网站的指标是成为无关微软已死我的项目历史的实在信息起源。 认真看看,都是满满的回顾! 比方:你是否还记得这个Lumia?当初与Nokia单干,在手机零碎上奋斗了6年,最初不敌安卓和iOS 各种跟MSN相干的利用,过后是办公人群装逼神器,当初曾经没人用了 一个古老的数据处理软件,记得以前考级还要学的 不晓得这里是否还有哪些是你用过的软件呢? 一起来这里回一下青春:https://killedbymicrosoft.info/ 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

March 11, 2023 · 1 min · jiezi

关于java:录音文件音频实现mp3等文件语音转换文字txt文档提取文字精准高效识别

音频录音文件实现语音转换辨认文字最初文档输入后果实现对mp3等录音文件进行语音辨认成文字,最终获取文档格局或者其它定义格式文件,也能够进行提取数据处理逻辑,轻松实现大文件的语音文字转换性能,精准高效便捷... 性能技术:java+阿里云语音辨认+OSS文件存储 *留神:文件须要有读写和可下载拜访权限 代码实现配置地区ID、常量、固定值: // 地区ID,常量,固定值。(依据本人开明地址配置) public static final String REGIONID = "cn-shenzhen"; public static final String ENDPOINTNAME = "cn-shenzhen"; public static final String PRODUCT = "nls-filetrans"; public static final String DOMAIN = "filetrans.cn-shenzhen.aliyuncs.com"; public static final String API_VERSION = "2018-08-17"; // 中国站版本 // public static final String API_VERSION = "2019-08-23"; // 国内站版本 public static final String POST_REQUEST_ACTION = "SubmitTask"; public static final String GET_REQUEST_ACTION = "GetTaskResult"; // 申请参数 public static final String KEY_APP_KEY = "appkey"; public static final String KEY_FILE_LINK = "file_link"; public static final String KEY_VERSION = "version"; public static final String KEY_ENABLE_WORDS = "enable_words"; // 响应参数 public static final String KEY_TASK = "Task"; public static final String KEY_TASK_ID = "TaskId"; public static final String KEY_STATUS_TEXT = "StatusText"; public static final String KEY_RESULT = "Result"; // 状态值 public static final String STATUS_SUCCESS = "SUCCESS"; private static final String STATUS_RUNNING = "RUNNING"; private static final String STATUS_QUEUEING = "QUEUEING";残缺代码: ...

March 11, 2023 · 4 min · jiezi

关于java:笑小枫的SpringBoot系列八SpringBoot集成Redis

SpringBoot集成RedisRedis原生命令大全,作者整顿的很具体,大部分命令转化为java命令根本也是关键词 Redis 命令参考 接下来开始咱们的正题,一起学习下,SpringBoot整合Redis 引入依赖pom文件不贴全副代码了,依赖有些多了,占据的篇幅过大,只贴新增的吧 pom.xml <!-- 引入redis依赖 --><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- 引入redis连接池的依赖 --><dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId></dependency>Redis配置随着配置越来越多,这里就不贴全副了,留神和datasource同级,在spring的上级,要去掉spring哈 增加application.yml 配置spring: redis: database: 0 host: 127.0.0.1 port: 6379 timeout: 5000 lettuce: pool: max-active: 32 max-wait: -1 max-idle: 16 min-idle: 8在config包下增加RedisConfig.java 配置类 package com.maple.demo.config;import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.boot.autoconfigure.data.redis.RedisProperties;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.RedisOperations;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.serializer.StringRedisSerializer;/** * @author 笑小枫 * @date 2022/07/19 **/@Configuration@ConditionalOnClass(RedisOperations.class)@EnableConfigurationProperties(RedisProperties.class)public class RedisConfig { @Bean @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); //应用fastjson序列化 FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); // value值的序列化采纳fastJsonRedisSerializer template.setValueSerializer(fastJsonRedisSerializer); template.setHashValueSerializer(fastJsonRedisSerializer); // key的序列化采纳StringRedisSerializer template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean(StringRedisTemplate.class) public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; }}工具类配置完配置,其实咱们的Redis就曾经集成了,SpringBoot的starter是真的香,前面咱们会解说一下如何制作咱们本人的starter。 ...

March 10, 2023 · 5 min · jiezi

关于java:时效准确率提升之承运商路由网络挖掘-|-得物技术

1引子履约时长是电商的生命线,间接关系到用户的生产体验。新华网[5]2022年双十一的报告显示,37.4%的受访者心愿次日达,29.91%心愿当日达。相较于其余物品,受访者对手机、电脑、数码产品的物流时效要求更高,更心愿当日或1-2天内能收到货。得物履约场景中,次要的阶段包含仓库内生产和第三方承运商配送。在用户领取时,得物会依据仓库的生产状况和运配资源,给用户一个承诺时效。 1.1 为什么要预测承运商的线路时效在履约过程中,得物须要监控订单的流转,及时的发现可能超时的订单(与和用户承诺时效相比),这里蕴含仓库生产的监控和三方配送的监控。在理论过程中咱们发现:配送节点产生变更时,承运商给的预测偏激进的。上面例子中,到了营业部承运商才给到比拟精准的预计送达工夫,故在分拣核心应用承运商的预计送达工夫容易呈现误报。 下图是承运商接口返回的预计送达时效的宽松指数,能够看到在靠近目的地时,承诺时效才比拟精确。 2承运商网络是如何运作的在构建承运商网络之前,须要先理解承运商网络是如何工作的。上面是从A网点到E网点的配送示意图,分为以下内容: (1)节点,蕴含的揽收和派送网点以及分拣核心。 (2)线路,包含支线和干线。例如从网点到分拣核心属于干线,从分拣核心到分拣核心属于支线。 (3)班次:承运商为了均衡老本和时效,会设置生产班次。到分拣核心之后,须要依据目的地进行分拣,当达到一定量的货物之后,会从分拣核心登程,返回下一个节点。承运商在设置班次的时候,会思考单量,兼顾运输的老本以及时效。 上图中:以紫色为例,在A网点,早上8点截单,即8点之前交接给承运商的货物,会在8点20左右实现封车,而后从网点登程,返回B分拣核心,达到B分拣核心的工夫是11点40,这个时候赶上了B分拣核心截单工夫为12点的班次,B分拣核心会在12:30实现分拣并返回下一个分拣核心,以此类推实现整个配送过程。 在构建承运商的网络时,须要进行建模。除了节点、线路和班次之外,外围还包含以下两个模型: (5)成品线,即从A网点到E网点通过所有节点。上图中:A网点-B分拣核心-C分拣核心-D分拣核心-E网点形成了一条成品线。 (6)成品线波次:因为节点存在波次,所以成品线也存在波次,实际上成品线波次和第一个节点的波次数一样。 3如何构建承运商网络在理解承运商网络如何工作后,须要着手构建承运商的网络。承运商回将轨迹信息推送到得物,内容相似以下的文本。 [ {"code":"180","desc":"快件达到【xxx营业部】","location":{"city":"xxx市","district":"xxx县","point":{"latitude":xxx,"longitude":xxx },"province":"xxx" },"node":"已揽收","opeTitle":"站点装箱","time":"2022-09-04 17:29:27" }, {"code":"xxx","desc":"收取快件","location":{"city":"xxx","district":"xxx","point":{"latitude":28.65,"longitude":120.07 },"province":"xx" },"node":"已揽收","opeTitle":"配送员实现揽收","time":"2022-09-04 17:29:27" }]3.1 结构化荡涤轨迹的文本,须要通过结构化的荡涤之后,能力获取轨迹的含意。对于每一个运单,它的轨迹会通过很多个节点,而每个节点的数据类型如下: 1. waybill_no 示意运单号,同一个运单号会有多条节点记录2. station_index 示意以后这个节点的下标3. station_enum 示意这个节点的类型,是分拣核心还是揽派网点4. station_name 示意节点的名称,例如下面例子里的xxx营业部5. station_status 示意这个节点的状态,例如是进入还是来到6. operate_time 示意以后节点的操作工夫3.2 轨迹外面是否真的有班次信息承运商网络工作原理提到了承运商会按班次进行生产,从轨迹的后果外面是否能找到班次生产的证据呢。通过剖析,咱们猜测:雷同流向(例如从A分拣核心开往B分拣核心)来到某个分拣核心(例如来到A分拣核心)的工夫应该是绝对集中的。实时上通过一些简略的聚类办法,证实了咱们的猜测。上面图中,横轴示意的是出分拣核心的小时,每一个点示意历史上的某一个运单,纵轴没有业务含意,只是为了不便显示。 绘制上述图时应用的是kmeans聚类算法,kmeans聚类算法须要指定聚类的个数。故须要应用Knee/Elbow 这类的算法进行聚类数检测,同时它对异样值敏感,故在实现时最终应用的DBSCAN。 3.3 聚类参数该如何选取DBSCAN尽管不须要指定聚类的个数,然而须要指定点之间的间隔以及点的密度,通过重复调整,最终确定这两个外围的参数如下: clustering = DBSCAN(eps=0.25, min_samples=max(5, int(x.size * 0.02)), metric=metric).fit(x_after_reshape)其中eps为0.25,即15分钟。点密度为5和总数的2%的最大值。 3.4 如何解决跨天的问题从下面聚类图看,同一个波次的点可能呈现跨天的状况,即有些点出分拨核心的工夫可能是23:50,有些分拨核心的点可能是00:10。这两个点的欧式间隔比拟大,故须要重写间隔的metrics函数。 ret = abs(x[0] - y[0])if ret > 12:ret = abs(24 - ret)return ret3.5 线路是如何串联的剖析节点的生产班次和线路的班次是不够的,还须要将它们进行串联,失去成品线班次,这样能力在售前或者售中进行利用。这里在解决的时候进行了一些简化,一方面是分拣核心的分拣波次是没有方法辨认到的,另外一方面其实能够不必关注分拣核心的分拣波次。实际上,串联成品线班次的过程是这样的: ...

March 10, 2023 · 1 min · jiezi

关于java:存货库存模型升级始末-|-得物技术

1背景公司存在多种物料品种、不同类型的库存和价值治理不一,存货零碎目前次要接入包装耗材、商品数据。目标是为了: 治理出入库价格、数量、库龄等业务数据,便于管理部门追溯及财务管控,帮助仓库晋升存货和物料的治理能力。治理仓库物料及商品的费用价值,晋升核算及业务的效率,实现业务信息一体化及凭证自动化。辅助打算或洽购部门查看库存,为采购计划提供数据撑持。存货零碎先接入了包耗材数据,这类数据的个性是行数据不多,但每行数量很大。后接入了商品的库存,因为行数据量增长N倍以上 ,并且随着业务一直增长数据量越来越大,思考到原有底层设计不能很好的撑持这么大的数据量,故有了这次零碎的模型降级。 2面对的问题2.1 数据承接点问题原业务流程在数据承接上逾越了外围P0链路后才把数据落地到库存利用(造成了肯定的技术危险,历史上也的确产生过一次技术故障 ,生产上游音讯代码有bug,导致P0清结算链路数据下发呈现阻塞,影响了局部结算单据的解决时效): (1)数据落库在单据零碎(2)关联订单数据(3)查问出未税单价(4)组装后下发库存 重构前的设计,老本表存储逻辑:不论每天成本价有没有变动,都会保护一条记录;台账表存储逻辑:每天如果有出入库数据依照业务类型汇总+2条期初期末数据,如果没有出入库数据,只保留2条期初期末数据。从存储逻辑不难看出存储了很多冗余数据,且台账表期初期末数据以行的模式存储也是不合理的。 如下是例子数据 2.2.1 明细表(record)每天出入库、调价单的数据 2.2.2 老本表(cost_price)所有物料每天都须要计算一个成本价2.2.3 台账表(ledger)日台账:汇总当天明细数据、以及期初、期末价格和数量 月台账:汇总当月明细数据、以及期初、期末价格和数量 2.3 页面数据查问性能瓶颈2.3.1 大盘&台账表剖析:通过大盘和台账表剖析,在接入仓库商品数据后,页面查问接口耗时很高,接口性能存在问题 2.3.2 日/月进销存也面临同样的问题 3解决方案3.1 数据承接优化3.1.1 库存利用间接承接单据池落地信息表 3.1.2 具体实现过程 3.2 数据存储设计问题优化3.2.1 简略示例比方一个物料,3月1日的成本价为100元,后在3月30日又进一件成本价200元的雷同物料,则咱们库里的记录信息如下, 2条数据即可 , 【毋庸每日更新数据,只有以后物料当日有出入库、调价数据时,才须要插入当日最新数据】, 理论场景,当业务代码查问3月10日的成本价时,往前查问到03.01的数据即可 3.2.2 冀望的数据存储款式 而不是30条数据 ( 03.02 至 03.29,这28条数据都是冗余的数据) 3.2.3 页面数据查问性能瓶颈解决方案因为数据存储逻辑变更,只会存储有变动的数据,而进销存报表是每天都须要产出的不论数据有没有变动。联合以后业务逻辑以及数据量最初决定把数据同步到数仓,在数仓进行数据补全后,通过报表平台拉取报表信息。 弃用以后后管平台查问报表 转为应用报表平台拉取库存报表信息 数据同步流程如下: 报表平台具备生成相似于Excel的数据展现,以及任意维度查问信息的能力,同时也具备Excel导出的性能 4重构后的价值4.1 量化业务价值:每月节俭核算以及审核工夫约30小时,占核算组总月结工夫比例为30%。 4.2 不可量化业务价值将仓库业务纳入存货零碎,宏大数据量通过零碎主动核算,输入表格,节约手工核算的工夫,以及晋升核算数据的准确性,解决无奈通过表格实现的窘境;晋升核算品质的同时,能够实现更多库存、销售数据分析,如周转率剖析,出入库渠道剖析,减值计提等等。剖析后果晋升公司退货商品的治理以及库存治理。性能重构从根底数据、入库模型、调价单、成本计算、出库模型、重算、报表都做了降级,在数据接管、成本计算等过程中减少了校验逻辑和修复数据的性能。 4.3 技术价值(1)技术价值:首次尝试了在线TIDB切换流程(包含数据复制、数据同步、数据比对、数据切流),积攒了TIDB切换教训,给后续的TIDB迁徙专项提供了教训积淀。 (2)技术价值:把P0级的清结算利用里的局部性能迁徙到库存利用中,解决了大流量的仓库数据下传至清结算利用的危险,实现了交易和非交易在利用级别的解耦和隔离。 (3) 团队价值:以赛代练,通过该我的项目造就了组内成员对于数仓平台和报表平台的实际和应用,拓宽了团队整体的技术栈,并积攒了数据开发的对应教训,也落地了数仓平台和报表平台的操作应用文档(节俭了后续团队成员的数据开发相熟接入的老本)。

March 10, 2023 · 1 min · jiezi

关于java:如何通过Java程序加密或者解密PDF文档

PDF文档加密是一种用于爱护文件内容的性能。加密后的文档须要提供明码能力关上和查看。这一性能无效避免未经受权的拜访、复制和批改 PDF 文件。Free Spire.PDF for Java反对以编程的形式加密和解密PDF文档,且过程中不须要装置第三方软件。具体操作步骤和相干代码能够参考以下内容。程序环境在进行操作之前,请先将jar导入到Java程序中,请参考以下两种导入办法:办法一:如果您应用的是 maven,能够通过增加以下代码到我的项目的 pom.xml 文件中,将 jar文件导入到应用程序中。 <repositories> <repository> <id>com.e-iceblue</id> <name>e-iceblue</name> <url>https://repo.e-iceblue.com/nexus/content/groups/public/</url> </repository></repositories><dependencies> <dependency> <groupId>e-iceblue</groupId> <artifactId>spire.pdf.free</artifactId> <version>5.1.0</version> </dependency></dependencies>办法二:如果您没有应用 maven,则能够从此链接下载Free Spire.PDF for Java,找到lib文件夹下的Spire.PDF.jar并进行解压;而后在IDEA中创立一个新我的项目,顺次点击“文件”(File),“我的项目构造”(Project Structure),“组件”(Modules),“依赖项”(Dependencies),再点击右方绿色“+”下的第一个选项“jar文件或门路”(JARs or Directories),找到解压后的Spire.PDF.jar 文件,点击确认,将其导入到我的项目中。 加密PDF文档• 创立一个 PdfDocument 实例。• 应用 PdfDocument.loadFromFile()办法加载PDF示例文档。• 设置关上明码、权限明码、加密密钥大小和权限。• 应用 PdfDocument.getSecurity().encrypt(java.lang.String openPassword, java.lang.String permissionPassword, java.util.EnumSet<PdfPermissionsFlags> permissions, PdfEncryptionKeySize keySize)办法来加密 PDF 文件。• 应用 PdfDocument.saveToFile() 办法保留后果文档。 import java.util.EnumSet;import com.spire.pdf.PdfDocument;import com.spire.pdf.security.PdfEncryptionKeySize;import com.spire.pdf.security.PdfPermissionsFlags;public class EncryptPDF { public static void main(String[] args) { //创立PdfDocument实例 PdfDocument pdf = new PdfDocument(); //加载PDF示例文档 pdf.loadFromFile("sample.pdf"); //加密文档 PdfEncryptionKeySize keySize = PdfEncryptionKeySize.Key_128_Bit; String openPassword = "123456"; String permissionPassword = "abcdef"; EnumSet flags = EnumSet.of(PdfPermissionsFlags.Print, PdfPermissionsFlags.Fill_Fields); pdf.getSecurity().encrypt(openPassword, permissionPassword, flags, keySize); //保存文档 pdf.saveToFile("Encrypt.pdf"); pdf.close(); }} ...

March 10, 2023 · 1 min · jiezi

关于java:公司新来一个同事为什么-HashMap-不能一边遍历一边删除一下子把我问懵了

作者:你呀不牛 \链接:https://juejin.cn/post/7114669787870920734 前段时间,共事在代码中KW扫描的时候呈现这样一条: 下面呈现这样的起因是在应用foreach对HashMap进行遍历时,同时进行put赋值操作会有问题,异样ConcurrentModificationException。 于是帮同简略的看了一下,印象中汇合类在进行遍历时同时进行删除或者增加操作时须要审慎,个别应用迭代器进行操作。 于是通知共事,应该应用迭代器Iterator来对汇合元素进行操作。共事问我为什么?这一下子把我问蒙了?对啊,只是记得这样用不能够,然而如同本人素来没有细究过为什么? 于是明天决定把这个HashMap遍历操作好好地钻研一番,避免采坑! foreach循环?java foreach 语法是在jdk1.5时退出的新个性,次要是当作for语法的一个加强,那么它的底层到底是怎么实现的呢?上面咱们来好好钻研一下: foreach 语法外部,对collection是用iterator迭代器来实现的,对数组是用下标遍从来实现。Java 5 及以上的编译器暗藏了基于iteration和数组下标遍历的外部实现。 (留神,这里说的是“Java编译器”或Java语言对其实现做了暗藏,而不是某段Java代码对其实现做了暗藏,也就是说,咱们在任何一段JDK的Java代码中都找不到这里被暗藏的实现。这里的实现,暗藏在了Java 编译器中,查看一段foreach的Java代码编译成的字节码,从中推测它到底是怎么实现的了) 咱们写一个例子来钻研一下: public class HashMapIteratorDemo { String[] arr = {"aa", "bb", "cc"}; public void test1() { for(String str : arr) { } }}将下面的例子转为字节码反编译一下(主函数局部): 兴许咱们不能很分明这些指令到底有什么作用,然而咱们能够比照一下上面段代码产生的字节码指令: public class HashMapIteratorDemo2 { String[] arr = {"aa", "bb", "cc"}; public void test1() { for(int i = 0; i < arr.length; i++) { String str = arr[i]; } }} ...

March 10, 2023 · 3 min · jiezi

关于java:快-40-岁刚被裁

作者:张飞洪 \起源:www.cnblogs.com/jackyfei/p/13862607.html 到职的心态人们在解雇或者被解雇都会对原公司抱有意见,因为疫情,公司业务告急,工资发不进去,我也失去了工作。尽管情绪上难免会有稳定,然而转念一想,我应该用开心的心态来对待这次辞职,并心愿能疾速翻过这一页,从新来过,趁现在状态还不错。 为什么不去数落老东家,最次要起因是这会减少自我的负能量,损人不利己,从而不能把更好的精力花在下一步的布局上。不论公司给你多少抵偿,是否扣除你的年终奖,这些都不重要了。如果公司对你有过帮忙,哪怕前面公司占你一点便宜,比方克扣年初什么的,我也看开了。公司能够占我的便宜,我不能负了仁义,毕竟在公司待了5年,公司也待我不薄。我想说的是好聚好散,低头看看后方,不要因为错过星星而错过月亮。 我想每个程序员到职都有各自的起因,比方公司发不出工资,和领导抵触了,比方有了更好的平台等等。每个人都无奈终其一生呆在一家公司,特地是程序员这种岗位更加突出。所以,不论是什么起因,都要坚守一条准则,公司是否提供了本人成长的机会?如果没有,问公司能不能给本人更多的工作和挑战。 想想本人有什么?我尽管奔四了,然而因为保持早睡早起(每天9点半睡,早上5点起来),同时也学了点养生常识,所以当初整体状态还是十分好,我想给那些出入江湖的同学举荐早睡早起,因为这能够减少你的编程寿命,真的不夸大,如果你的真的技术不错,不要旷废,哪怕你有机会做治理,也不要轻易废除,毕竟管理层也可能被解雇,如果你的技术底子还在,违心享乐,应该能够找到一份活口的工作。也祝愿我本人也能找到职场的下一站。 很多程序员怕年纪大,我也怕过,然而想一想这是每个人必经的过程,咱们应该不必去排挤它,违心服老。要害是咱们“老了”之后,咱们还有什么? 和刚毕业相比,咱们年纪尽管大了些,然而能力和教训更加丰盛了,把过往的教训复盘复盘,总能提炼出一些心得模型,这些模型产生的效率肯定是能够完胜过往。欧美很多程序员是能够作为一生职业,置信国内的环境也会越来越好,毕竟数字化的浪潮还没实现,咱们国家须要大量的有教训的技术人才。所谓天生我材必有用吧,就怕本人“老了”啥也没有积淀下来。 我能从这次到职当中学到什么?和年老的时候比拟,我学会了从容,铁打的营盘流水的兵,天下没有不散的筵席;和年老的时候比拟,我学会了不怨天不尤人,不论是公司负我还是本人做得不够,从今天开始,心态归零,带着乐观去开始新的人生,有时候来到一家呆了5年的公司,未尝不是一种解脱。 我学会了要积极主动,当咱们在一家公司一天,咱们就要尽可能把工作做好,对得起公司给薪资。如果公司没有工作了,你不要有混日子的想法,没有业务的公司对咱们是危险的。尽力帮忙公司把业务做好,只有公司好了,集体能力成长得好。 兴许你对公司有各自埋怨,如果真的如你所想的那样,那就无妨跳槽,然而你肯定要三思,没有美中不足的公司;另外,又给本人的人生积攒了一点挫折的经验,人生的止境是零。生老病死哪个不比辞职苦楚,如果不能用平常心对待,那么将来可能会更加苦楚。 有时候小公司为了活下来,你可能须要做很多的杂活,从产品的设计,到开发,从前端到后端到测试都要本人来,那就来吧,不要埋怨。如果你切实调整不过去心态,那就无妨这么想,这个尽管不能增长你的技能,然而能够锤炼你的心态,心诚则灵。没有小事做的时候,做做小事很能锤炼急躁的。所有的小事不都是由小事形成的吗? 很多时候我感觉不是员工对杂活有意见,而是对领导的为人有意见。就会产生一种想法,看你那副德行,老子就不给你干,你能怎么?所以,找工作宁愿找个价值观雷同的老板,也不要冤屈本人,去一个价值观心心相印的部门干活,我置信你保持不了多久的。 工作中难免会因为做得不好被领导数落,要先想想本人是否尽责了,只有一心想的是公司的事,为公司好,咱们肯定要名正言顺,不要因为对方是你的下属而畏缩不前,那对本人和公司都是一种挫伤。 和共事相处,尽量与人为善,能帮忙他人的尽量要帮忙他人,这个情理很奢侈,然而真的很实用。咱们环顾四周,其实咱们这种乐于助人的共事真的百里挑一,没有人违心去做这种事,在这个人情味越来越淡薄的社会。当咱们有余力去帮忙他人的时候,是十分难能可贵的,毕竟公司有情,人有情。 将来的布局1.把过来积淀过的框架打磨一下,积淀下来,变成一个数字基座,心愿能帮忙更多的中小公司和研发团队。 2.边学习边持续找工作,毕竟本人得吃饭,如果你有好的机会,有幸能失去你的举荐,感激不尽。 3.持续分享博客和录制视频。因为我也做不了别的事件。 4.陪陪家人,看下本人还能够在哪方面有倒退的机会 结尾感谢您聆听我的啰嗦,其实到职和入职都很重要,有时候更加重要,因为那可能是人生的另外一个终点,另外一条路线。在登程之前,咱们都心愿尽可能少走弯路,尽管没有完满的人生,然而尽可能防止犯错真的十分重要,那意味着工夫和金钱。 在这家公司呆的前后5年,从刚进来的被面试,到起初的面试他人,细想都是贵重的财产,我得以窥视以后厦门程序员的广泛心态,有对工作抉择的审慎,有对面试后果的渴望,有进来后又回笼的小伙伴,最初又抉择来到。也有共事雷打不动的虔诚……生存永远充斥了期待,冲动,悲观,丧气,再期待,再冲动,跌宕起伏。 愿天下的程序员都得其所愿,各安其所! 近期热文举荐: 1.1,000+ 道 Java面试题及答案整顿(2022最新版) 2.劲爆!Java 协程要来了。。。 3.Spring Boot 2.x 教程,太全了! 4.别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!! 5.《Java开发手册(嵩山版)》最新公布,速速下载! 感觉不错,别忘了顺手点赞+转发哦!

March 10, 2023 · 1 min · jiezi

关于java:关于加解密加签验签的那些事-|-得物技术

1前言面对MD5、SHA、DES、AES、RSA等等这些名词你是否有很多问号?这些名词都是什么?还有什么公钥加密、私钥解密、私钥加签、公钥验签。这些都什么鬼?或者在你日常工作没有据说过这些名词,然而一旦你要设计一个对外拜访的接口,或者安全性要求高的零碎,那么必然会接触到这些名词。所以加解密、加签验签对于一个合格的程序员来说是必须要把握的一个概念。接下来咱们就一文彻底搞懂这些概念。 2没有硝烟的战场——浅谈明码技术没有根基兴许能够建一座小屋,但相对不能造一座坚硬的大厦。明码这个词有很多种的解释,在古代社会如果不接触编程的话,那么广泛的认为是咱们设置的登录明码、或者是去银行取钱时输出的数字。都是咱们在注册时实现给提供服务的一方存储一组数字,当前咱们登录的时候就用这组数字相当于就证实了咱们的身份。这个数字通常来说就是叫做明码。 而咱们须要理解的不是下面说的明码,而是一种“密码术”,就是对于要传递的信息依照某种规定进行转换,从而暗藏信息的内容。这种办法能够使机密信息得以在公开的渠道传递而不泄密。应用这种办法,要通过加密过程。在加密过程中咱们须要晓得上面的这些概念: 原文:或者叫明文,就是被暗藏的文字加密法:指暗藏原文的法令密文:或者叫伪文,指对原文依照加密法解决过后生成的可公开传递的文字密钥:在加密法中起决定性的因素,可能是数字、词汇,也可能是一些字母,或者这些货色的组合 加密的后果生成了密文,要想让接受者可能读懂这些密文,那么就要把加密法以及密钥通知接受者,否者接受者无奈对密文解密,也就无奈读懂原文。 从历史的角度来看,密码学大略能够分为古典密码学和近现代密码学两个阶段。两者以古代信息技术的诞生为分界点,当初所探讨的密码学多指的是后者,建设在信息论和数学成绩根底之上的。 2.1 古典密码学古典密码学源自于数千年前,最早在公元前1900年左右的古埃及,就呈现了通过应用特殊字符和简略替换式明码来爱护信息。美索不达米亚平原上已经出土一个公元前1500年左右的泥板,其上记录了加密形容的陶瓷器上釉的工艺配方。古希腊期间(公元前800 ﹣前146 年)还创造了通过物理伎俩来暗藏信息的“隐写术”,例如应用牛奶书写、用蜡笼罩文字等。起初在古罗马期间还呈现了基于替换加密的凯撒明码,据称凯撒曾用此办法与其部下通信而得以命名。这些伎俩少数是采纳简略的机械工具来爱护机密,在明天看来毫无疑问是非常简陋,很容易猜出来的。严格来看,可能都很难称为明码迷信。 凯撒明码是当偏移量是3的时候,所有的字母都A都将被替换成D,B变成E,以此类推。 2.2 近代密码学近代密码学的钻研来自于第一、二次世界大战中对于军事通信进行爱护和猜出来的需要。1901年12月,意大利的工程师Guglielmo Marconi(奎里亚摩•马可尼)胜利实现了逾越大西洋的无线电通信的试验,在寰球范畴内引发轰动,推动了无线电通信时代的到来。无线电大大提高了近程通信的能力,然而它有一个人造的缺点——很难限度接管方,这就意味着你所传的信息有可能被拦挡,因而就催生了加密技术的倒退。 对于无线电信息进行加密和解密也间接促成了近现代密码学和计算机技术的呈现。反过来这些科技进步也影响了时代的倒退。一战期间德国外交部长Arthur Zimmermann(阿瑟•齐默尔曼)笼络墨西哥形成抗美军事同盟的电报(1917 年1月16日)被英国情报机构—40号办公室破译,间接导致了美国的参战;二战时期德国应用的恩尼格玛(Enigma)密码机(过后最先进的加密设施)被盟军胜利破译(1939年到1941年),导致大西洋战斗德国失败。据称,二战时期光英国从事密码学钻研的人员就达到7000人,而他们的成绩使二战完结的工夫至多提前了一到两年工夫。 接下来就是能够称之为是密码学发展史上里程碑的事件了。1945年9月1日,Claude Elwood Shannon(克劳德•艾尔伍德•香农)实现了划时代的外部报告《A Mathematical Theory of Cryptography(密码术的一个数学实践)》,1949 年 10 月,该报告以《Communication Theory of Secrecy Systems(窃密零碎的通信实践)》为题在 Bell System Technical Journal(贝尔零碎技术期刊)上正式发表。这篇论文首次将密码学和信息论分割到一起,为对称明码技术 提供了数学根底。这也标记着近现代密码学的正式建设。这也是密码学发展史上的第一座里程碑性事件。 密码学发展史上的第二个里程碑性事件是DES的呈现。DES全称为Data Encryption Standard,即数据加密规范,是一种应用密钥加密的分组明码算法,1977年被美国联邦政府的国家标准局确定为联邦材料解决规范(FIPS),并受权在非密级政府通信中应用,随后该算法在国内上宽泛流传开来。 密码学发展史上的第三个里程碑性事件就是咱们区块链中广泛应用的公钥明码,也就是非对称明码算法 的呈现。1976年11月,Whitfield Diffie 和 Martin E.Hellman 在 IEEE Transactions on Information Theory 上发表了论文《New Directions in Cryptography(密码学的新方向)》,探讨了无需传输密钥的窃密通信和签名认证体系问题,正式创始了古代公钥密码学体系的钻研。在公钥明码发现以前,如果须要窃密通信,通信单方当时要对加解密的算法以及要应用的密钥进行当时协商,包含送鸡毛信,实际上是在传送密钥。但自从有了公钥明码,须要进行机密通信的单方不再须要进行事先的密钥协商了。公钥明码在实践上是不窃密的,在实际上是窃密的。也就是说,公钥明码是能够猜出来的,但须要极长的工夫,等到猜出来了,这个机密也没有窃密的必要了。 下面咱们说到了对于近现代的密码学相干的货色,基本上总结下来咱们当初罕用的就两个,一个是对称加密算法,一个是非对称加密算法。那么接下来咱们就以介绍这两个概念为主线引出开题中咱们提到的概念。 3程序实现3.1 对称加密算法对称加密指的就是加密和解密应用同一个秘钥,所以叫做对称加密。对称加密只有一个秘钥,作为私钥。具体的算法有:DES、3DES、TDEA、Blowfish,RC5,IDEA。然而咱们常见的有:DES、AES等等。 那么对称加密的长处是什么呢?算法公开、计算量小、加密速度快、加密效率高。毛病就是秘钥的治理和散发是十分艰难的,不够平安。在数据传送前,发送方和接管方必须约定好秘钥,而后单方都必须要保留好秘钥,如果一方的秘钥被泄露了,那么加密的信息也就不平安了。另外,每对用户每次应用对称加密算法时,都须要应用其他人不晓得的惟一秘钥,这会使得收、发单方所领有的的钥匙数量微小,秘钥治理也会成为单方的累赘。 加密的过程咱们能够了解为如下: 加密:原文+秘钥 = 密文解密:密文-秘钥 = 原文能够看到两次过程应用的都是一个秘钥。用图简略示意如下: 3.2实战演练既然咱们晓得对于对称加密算法的相干常识,那么咱们日常用Java如何实现对称加密的加密和解密动作呢?常见的对称加密算法有:DES、AES等。 3.2.1 DESDES加密算法是一种分组明码,以64位为分组对数据加密,它的密钥长度是56位,加密解密用同一算法。DES加密算法是对密钥进行窃密,而公开算法,包含加密和解密算法。这样,只有把握了和发送方雷同密钥的人才能解读由DES加密算法加密的密文数据。因而,破译DES加密算法实际上就是搜寻密钥的编码。对于56位长度的密钥来说,如果用穷举法来进行搜寻的话,其运算次数为2的56次方。 接下来用Java实现DES加密 ...

March 10, 2023 · 4 min · jiezi

关于java:异步Servlet学习笔记一

两周没更新了,感觉不写点什么,有点不难受的感觉。前言回顾一下学Java的历程,过后是看JavaSE(根本语法、线程、泛型),而后是JavaEE,JavaEE也根本就是围绕着Servlet的应用、JSP、JDBC来学习,过后看的是B站up主颜群的教学视频: JavaWeb视频教程(JSP/Servlet/上传/下载/分页/MVC/三层架构/Ajax)https://www.bilibili.com/video/BV18s411u7EH?p=6&vd_source=aae...当初一看这个播放量破百万了,当初我看的时候应该播放量很少,当初这么多倒是有点昨舌。学完了这个之后,开始学习框架:Spring、SpringMVC、MyBatis、SpringBoot。尽管Spring MVC实质上也是基于Servlet做封装,但前面根本就转型成Spring 工程师了,最近碰到一些问题,又看了一篇文章,感觉一些问题之前本人还是没思考到,颇有种离了Spring家族,不会写后端一样。原本明天的行文最后是什么是异步Servlet,异步Servlet该如何应用。然而想想没有切入实质,所以将其换成了对话体。 注释咱们接着有请之前的实习生小陈,每当咱们须要用到对话体、故事体这样的行文。实习生小陈就会出场。明天的小陈呢感觉行情有些不好,然而还是感觉想进来看看,毕竟金三银四,于是下午就向领导销假去面试了。进到面试的中央,一番自我介绍,面试官首先问了这样一个问题: 一个申请是怎么被Tomcat所解决的呢?小陈答复到: 我目前用的都是Spring Boot工程,我看都是启动都是在main函数外面启动整个我的项目的,而main函数又被main线程执行,所以我想应该是申请过去之后,被main线程所解决,给出响应的。面试官: ╮(╯▽╰)╭,main函数确实是被main线程执行,但都是被main线程解决的? 这不合理吧,假如某个申请占用了main线程三秒,那这三秒内,零碎都无奈再回应申请了。你要不再想想?小陈挠了挠头,接着答到: 的确是,浏览器和Tomcat通信用的是HTTP协定,我也学过网络编程,所以我感觉应该是一个线程一个申请吧。像上面这样:public class ServerSocketDemo { private static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(4); public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(8080); while (true){ // 一个socket对象代表一个连贯 // 期待TCP连贯申请的建设,在TCP连贯申请建设实现之前,会陷入阻塞 Socket socket = serverSocket.accept(); System.out.println("以后连贯建设:"+ socket.getInetAddress().getHostName()+socket); EXECUTOR_SERVICE.submit(()->{ try { // 从输出流中读取客户端发送的内容 InputStream inputStream = socket.getInputStream(); // 从输入流里向客户端写入数据 OutputStream outPutStream = socket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } }); } }}serverSocket的accept在连贯建设起来会陷入阻塞。面试官点了拍板, 接着问到: ...

March 10, 2023 · 3 min · jiezi

关于java:GitHub上线重量级分布式事务笔记再也不怕面试官问分布式了

分布式事务就是指事务的参与者、反对事务的服务器、资源服务器以及事务管理器别离位于不同的分布式系统的不同节点之上。简略的说,就是一次大的操作由不同的小操作组成,这些小的操作散布在不同的服务器上,且属于不同的利用,分布式事务须要保障这些小操作要么全副胜利,要么全副失败。实质上来说,分布式事务就是为了保障不同数据库的数据一致性。 举个栗子,你去小卖铺买货色,付了钱,然而店主因为解决了一些其余事,竟然遗记你付了钱,又叫你从新付。又或者在网上购物明明曾经扣款,然而却通知我没有产生交易。这一系列状况都是因为没有事务导致的。这阐明了事务在生活中的一些重要性。有了事务,你去小卖铺买货色,那就是一手交钱一手交货。有了事务,你去网上购物,扣款即产生订单交易。 看看上面这些分布式事务知识点你把握了多少 本地事务和分布式事务的概念和区别分布式事务的实践根底各分布式事务计划的优缺点及实用场景如何依据本人的业务场景抉择适合的分布式事务计划fescar+dubbo实现分布式事务RocketMQ事务音讯TX-LCN分布式事务框架市面上的分布式教程大多仅限于理论知识解说,很少有具体的实现计划案例.在这里小编给大家分享一份分布式事务笔记带你3天吃透分布式事务利用及解决方案,通过分布式事务的学习,能够让你不仅理解分布式事务的理论知识,并且能够真正把握企业中实在的分布式事务利用实际以及分布式事务常见面试题的解决方案。有须要这份分布式事务笔记的敌人看文末有收费的获取形式! 不多BB,看目录和次要内容因为文档内容过多,因而为了防止影响到大家的浏览体验,在此只以截图展现局部内容,具体完整版【点击此处】即可获取!1,本地事务和分布式事务的概念和区别什么是事务事务的四个个性ACID事务的隔离级别本地事务什么是分布式事务分布式事务利用架构CAP实践BASE实践柔性事务解决方案 2, 分布式事务解决方案分布式事务中的模型与标准弥补事务(TCC)本地音讯表(异步确保)MQ 事务音讯(rocketMQ) 3,分布式事务实战外围步骤:代码实现:Atomikos分布式事务 4, fescar分布式事务实现fescar介绍分布式事务案例阐明建库操作公共工程搭建业务层搭建 5,RocketMQ事务音讯RocketMQ事务音讯流程事务音讯生产者事务音讯生产分布式事务实现流程 6,Lcn分布式事务框架介绍什么是LCN框架框架特点LCN框架原理外围步骤SpringCloud整合LCN框架实战筹备的软件环境测试用例剖析构建测试用例 7,lcn框架集成实战

March 10, 2023 · 1 min · jiezi

关于java:30天帮你一步步学会Python的开源项目

最近发现一个不错的收费开源学习我的项目:30天学会Python 如果您最近有学习Python的打算,无妨看看这个是否适宜你? 我的项目地址:https://github.com/Asabeneh/30-Days-Of-Python博客地址:https://blog.didispace.com/tj-30-days-of-python/ 该我的项目内容的设计很棒,不是单纯的重叠内容,而是制订了一个30天的学习打算,这样能够循序渐进的帮忙读者来学习Python编程语言。 Python类教程那么多了,为什么举荐它呢,我感觉该我的项目有以下几点劣势: 适宜初学者:该我的项目提供了一个逐渐学习Python的打算,适宜那些没有编程教训或想要进一步理解Python的人。全面而深刻:该我的项目涵盖了Python编程的许多方面,包含根本语法、数据类型、函数、模块、面向对象编程等,能够帮忙您全面理解Python。实践性强:该我的项目不仅提供理论知识,还包含许多理论的编程练习,能够帮忙您坚固所学的常识并进步编程技能。社区反对:该我的项目有一个沉闷的社区,您能够在其中与其余学习者交换和分享教训。收费开源:该我的项目是收费开源的,您能够自在地下载、应用和批改它。总之,如果您想要学习Python编程,并且想要一个系统化、全面、实践性强的学习打算,那么这个我的项目是一个十分好的抉择。 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

March 10, 2023 · 1 min · jiezi

关于java:推荐一款漂亮的-Java-图形验证码

Java图形验证码,反对自定义图片、中文、算术等类型,可用于Java Web、JavaSE等我的项目。真香成果展现 我的项目集成package com.kyger;import jakarta.servlet.ServletException;import jakarta.servlet.http.HttpServlet;import jakarta.servlet.http.HttpServletRequest;import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Map;public class demo extends HttpServlet { private static final long serialVersionUID = 1L; public demo() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 编码 request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8");; response.setContentType("text/html; charset=utf-8"); // 后盾解决 if (request.getMethod().equals("POST")){ String html, appId, appSecret; // 设置 AppId 及 AppSecret,在利用治理中获取 appId = "L001"; appSecret = "W68oJi0iqT2C3BFRGirO1IaYCDvsYEED"; KgCaptchaSDK KgRequest = new KgCaptchaSDK(appId, appSecret); // 前端验证胜利后颁发的 token,有效期为两分钟 KgRequest.token = request.getParameter("kgCaptchaToken"); // System.out.print(KgRequest.token); // 填写应用服务域名,在利用治理中获取 KgRequest.appCdn = "https://cdn9.kgcaptcha.com"; // 申请超时工夫,秒 KgRequest.connectTimeout = 5; // 用户登录或尝试帐号,当安全策略中的防控等级为3时必须填写,个别状况下能够疏忽 // 能够填写用户输出的登录帐号(如:request.getParameter("username"),可拦挡同一帐号屡次尝试等行为 KgRequest.userId = "kgCaptchaDemo"; // request 对象,当安全策略中的防控等级为3时必须填写,个别状况下能够疏忽 KgRequest.request = request; // java 环境中无奈提供 request 对象,请别离定义:clientIp|clientBrowser|domain 参数,即: // KgRequest.clientIp = "127.0.0.1"; // 填写客户端IP // KgRequest.clientBrowser = ""; // 客户端浏览器信息 // KgRequest.domain = "http://localhost"; // 你的受权域名或服务IP // 发送验证申请 Map<String, String> requestResult = KgRequest.sendRequest(); if("0".toString().equals(requestResult.get("code"))) { // 验签胜利逻辑解决 *** // 这里做验证通过后的数据处理 // 如登录/注册场景,这里通常查询数据库、校验明码、进行登录或注册等动作解决 // 如短信场景,这里能够开始向用户发送短信等动作解决 // ... html = "<script>alert('验证通过');history.back();</script>"; } else { // 验签失败逻辑解决 html = "<script>alert(\"" + requestResult.get("msg") + " - " + requestResult.get("code") + "\");history.back();</script>"; } response.getWriter().append(html); } else { response.sendRedirect("index.html"); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }} ...

March 10, 2023 · 1 min · jiezi

关于java:三天吃透RabbitMQ面试八股文

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址:https://github.com/Tyson0314/Java-learning 什么是RabbitMQ?RabbitMQ是一个由erlang开发的音讯队列。音讯队列用于利用间的异步合作。 RabbitMQ的组件Message:由音讯头和音讯体组成。音讯体是不通明的,而音讯头则由一系列的可选属性组成,这些属性包含routing-key、priority、delivery-mode(是否持久性存储)等。 Publisher:音讯的生产者。 Exchange:接管音讯并将音讯路由到一个或多个Queue。default exchange 是默认的直连交换机,名字为空字符串,每个新建队列都会主动绑定到默认交换机上,绑定的路由键名称与队列名称雷同。 Binding:通过Binding将Exchange和Queue关联,这样Exchange就晓得将音讯路由到哪个Queue中。 Queue:存储音讯,队列的个性是先进先出。一个音讯可散发到一个或多个队列。 Virtual host:每个 vhost 实质上就是一个 mini 版的 RabbitMQ 服务器,领有本人的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的根底,必须在连贯时指定,RabbitMQ 默认的 vhost 是 / 。当多个不同的用户应用同一个RabbitMQ server提供的服务时,能够划分出多个vhost,每个用户在本人的vhost创立exchange和queue。 Broker:音讯队列服务器实体。 什么时候应用MQ对于一些不须要立刻失效的操作,能够拆分进去,异步执行,应用音讯队列实现。 以常见的订单零碎为例,用户点击下单按钮之后的业务逻辑可能包含:扣减库存、生成相应单据、发短信告诉。这种场景下就能够用 MQ 。将短信告诉放到 MQ 异步执行,在下单的主流程(比方扣减库存、生成相应单据)实现之后发送一条音讯到 MQ, 让主流程疾速完结,而由另外的线程生产MQ的音讯。 RabbitMQ的优缺点毛病:应用erlang实现,不利于二次开发和保护;性能较kafka差,长久化音讯和ACK确认的状况下生产和生产音讯单机吞吐量大概在1-2万左右,kafka单机吞吐量在十万级别。 长处:有治理界面,方便使用;可靠性高;功能丰富,反对音讯长久化、音讯确认机制、多种音讯散发机制。 RabbitMQ 有哪些重要的角色?RabbitMQ 中重要的角色有:生产者、消费者和代理。 生产者:音讯的创建者,负责创立和推送数据到音讯服务器;消费者:音讯的接管方,用于解决数据和确认音讯;代理:就是 RabbitMQ 自身,用于表演“快递”的角色,自身不生产音讯,只是表演“快递”的角色。Exchange 类型Exchange散发音讯时依据类型的不同散发策略不同,目前共四种类型:direct、fanout、topic、headers 。headers 模式依据音讯的headers进行路由,此外 headers 交换器和 direct 交换器完全一致,但性能差很多。 Exchange规定。 类型名称类型形容fanout把所有发送到该Exchange的音讯路由到所有与它绑定的Queue中directRouting Key==Binding Keytopic含糊匹配headersExchange不依赖于routing key与binding key的匹配规定来路由音讯,而是依据发送的音讯内容中的header属性进行匹配。direct direct替换机会将音讯路由到binding key 和 routing key齐全匹配的队列中。它是齐全匹配、单播的模式。 fanout 所有发到 fanout 类型交换机的音讯都会路由到所有与该交换机绑定的队列下来。fanout 类型转发音讯是最快的。 ...

March 10, 2023 · 3 min · jiezi

关于java:一文快速回顾-ServletFilterListener

什么是Servlet?前置常识: Web 服务器:能够指硬件上的,也能够指软件上的。从硬件的角度来说, Web 服务器指的就是一台存储了网络服务软件的计算机;从软件的角度来说, Web 服务器指的是一种软件,比方 Tomcat。 Servlet 容器:目前支流的 Servlet 容器软件包含 Tomcat、Jetty、Jboss 等。 Web 服务器 ≠ Servlet 容器,Tomcat 是一种 Web 服务器,同时它还是一个 Servlet 容器。 打开 Servlet 源码,有这样的一句话: A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients, usually across HTTP, the HyperText Transfer Protocol. 一个 Servlet 就是一个小型的运行在 Web 服务器外面的 Java 程序。每个 Servlet 都会接管并且响应来自 Web 客户端的每一个申请,申请指的是 HTTP 申请(超文本传输协定)。 ...

March 9, 2023 · 10 min · jiezi

关于java:BlockingQueue-ArrayBlockingQueue

ArrayBlockingQueue相对来说就比较简单了。 ArrayBlockingQueue是基于数组的阻塞队列,创立的时候须要指定容量,也就是说ArrayBlockingQueue是有界队列。 ArrayBlockingQueue#次要属性items:也就是ArrayBlockingQueue的底层数据结构 final Object[] items;takeIndex:下次出队列的地位,包含take, poll, peek or remove等操作。 putIndex:下次入队列的地位,包含put, offer, or add等操作。 count:队列理论长度。 lock:ReentrantLock,出、入队列的时候都须要上锁。 notEmpty:lock的Condition,帮助获取数据的线程排队。 notFull:lock的Condition,帮助退出队列的线程排队。 构造方法采纳非偏心锁创立容量为capacity的队列: public ArrayBlockingQueue(int capacity) { this(capacity, false); }创立容量为capacity的队列,fair参数指定应用偏心锁或非偏心锁: public ArrayBlockingQueue(int capacity, boolean fair) { if (capacity <= 0) throw new IllegalArgumentException(); this.items = new Object[capacity]; lock = new ReentrantLock(fair); notEmpty = lock.newCondition(); notFull = lock.newCondition(); }创立一个非空的队列,如果初始化汇合容量超过了指定的队列容量则抛出异样,初始化数据的过程中统计队列理论容量count、以及putIndex: public ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> c) { this(capacity, fair); final ReentrantLock lock = this.lock; lock.lock(); // Lock only for visibility, not mutual exclusion try { int i = 0; try { for (E e : c) { checkNotNull(e); items[i++] = e; } } catch (ArrayIndexOutOfBoundsException ex) { throw new IllegalArgumentException(); } count = i; putIndex = (i == capacity) ? 0 : i; } finally { lock.unlock(); } }入队和出队与LinkedBlockingQueue相似,ArrayBlockingQueue也提供了两类出队、入队办法。 ...

March 9, 2023 · 1 min · jiezi

关于java:JMH指北

原始博文链接 今回介绍入门一款实用性不错的测试工具——JMH,其实理解这个货色也是一段时间之前的事件了,拖拖拉拉到当初,感觉曾经遗记了大部分,所以就当重温吧。理解JMH的同时会自然而然接触到一些JVM相干的常识,值得学习一番。 简介JMH全称Java Microbenchmark Harness,翻译过去就是Java微基准测试工具套件。很显著它是一款Java的测试工具,而其中的微基准则表明了它的实用层级。对代码性能的追赶是码农经常须要做的事件,那么代码的性能到底怎么样,不能靠嘴巴说而须要量化的指标,很多开源工具会给出JMH的比照测试后果来显示本人性能是如何的优越。现在计算机的算力对于执行一段代码块来说,很有可能就是几纳秒的事件,因而为了得出“肉眼可见”的论断,往往须要循环重试。没有接触JMH之前我置信大多数人都做过把一个办法用for循环执行n次并且记录起始完结工夫来验证这个办法耗时如何的事件,这对于纯编译执行的语言或者没什么问题,然而对于Java或者基于JVM的语言来说并不能失去最精确的后果,JVM做了很多咱们看不到的事件,所以同一个测试运行屡次可能会看到差异较大的后果。而JMH就是为了解决这个问题而来, 它由JVM开发人员编写,编写JMH不是一件容易的事件,因为这须要十分相熟JVM的运行机制。 用法说明JDK9以上的版本自带了JMH,其余版本则须要引入相干的依赖。JMH的主页很简略,基本上就只是有一个指向Github我的项目地址的连贯,而Github我的项目中的主页也只是给出了一些简略的用法说明,其余的只是通知你去看样例来了解。其实这样我感觉挺不错,所以本篇的内容次要就是照着样例一个一个解释。 官网我的项目阐明文档中写明了举荐应用命令行来执行测试,首先采纳maven来创立我的项目的根本骨架,而后编写测试代码并打包,最初应用命令行调用执行jar包。在编写时举荐将JMH构建成为一个独立的我的项目,在关系上依赖具体的利用我的项目,这样可能确保基准测试程序正确地初始化并产生牢靠的后果。当然也能够抉择在IDE中间接运行,当初风行的IDE如IDEA中也提供了相干插件,在进行理解学习时是个不错的应用形式。 样例阐明01 HelloWorldpublic class JMHSample_01_HelloWorld { @Benchmark public void wellHelloThere() { // this method was intentionally left blank. } public static void (String[] args) throws RunnerException { Options opt = new OptionsBuilder() .include(JMHSample_01_HelloWorld.class.getSimpleName()) .forks(1) .build(); new Runner(opt).run(); } }JMH的工作形式如下: 用户应用@benchmark 正文办法,而后 JMH执行生成的代码,以此尽可能牢靠地执行该测试方法。请浏览@Benchmark的javadoc正文来理解残缺的语义和限度。办法名称并不重要,只有办法用@benchmark 它就会被认为是一个基准测试方法,在同一个类中能够有多个基准办法。留神如果基准测试方法永远不完结,那么JMH运行也永远不会完结。如果您从办法体中抛出异样,JMH 运行会立即完结这个基准测试,而后执行列表中的下一个基准测试。只管这个基准测试什么也没有执行,但它很好地展现了根底构造对于测量的负载,没有任何基础设施不会导致任何开销,重要的是要晓得你正在解决的根底管理费用是多少。在未来的示例中,你可能会发现这种思维是通过比拟“基线”测量后果而开展的。 02 BenchmarkModespublic class JMHSample_02_BenchmarkModes { @Benchmark @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.SECONDS) public void measureThroughput() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(100); } @Benchmark @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) public void measureAvgTime() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(100); } @Benchmark @BenchmarkMode(Mode.SampleTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) public void measureSamples() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(100); } @Benchmark @BenchmarkMode(Mode.SingleShotTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) public void measureSingleShot() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(100); } @Benchmark @BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SampleTime, Mode.SingleShotTime}) @OutputTimeUnit(TimeUnit.MICROSECONDS) public void measureMultiple() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(100); } @Benchmark @BenchmarkMode(Mode.All) @OutputTimeUnit(TimeUnit.MICROSECONDS) public void measureAll() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(100); }}这个例子介绍了注解@BenchmarkMode以及配合应用的@OutputTimeUnit,这个注解接管的枚举值代表了测试类型,留神注解接管的是数组类型,这代表你能够同时执行多种测试。 ...

March 9, 2023 · 36 min · jiezi

关于java:SpringBoot整合ElasticSearch

ElasticSearch是个开源分布式搜索引擎,提供收集、剖析、存储数据三大性能。它的特点有:分布式,零配置,主动发现,索引主动分片,索引正本机制,restful格调接口,多数据源,主动搜寻负载等。次要负责将日志索引并存储起来,不便业务方检索查问。 1 装置ES下载地址:https://www.elastic.co/cn/downloads/elasticsearch 抉择Windows版本,我下载的是7.17.0。解压后即可实现装置。 进入bin文件, 双击执行 elasticsearch.bat,而后关上浏览器,进入页面: http://localhost:9200,看到以下输入,示意启动胜利。 2 Spring我的项目我的项目GitHub地址:https://github.com/Snowstorm0/learn-es 我的项目Gitee地址:https://gitee.com/Snowstorm0/learn-es 2.1 配置ES客户端public class RestClientConfig extends AbstractElasticsearchConfiguration { @Override @Bean public RestHighLevelClient elasticsearchClient() { final ClientConfiguration clientConfiguration = ClientConfiguration.builder() .connectedTo("localhost:9200") .build(); return RestClients.create(clientConfiguration).rest(); }}2.2 创立User类public class UserEntity { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; private String job; private Double deposit; private Date processTime = new Date();}配置实现后,ElasticSearch即可像惯例的数据库那样进行增删改查的操作。 2.3 配置数据库spring.datasource.username=rootspring.datasource.password=rootspring.datasource.url=jdbc:mysql://localhost:3306/sys?characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC3 运行我的项目3.1 增加调用增加接口:http://localhost:8080/user/add 增加User类的申请体: { "id":"1", "name":"代码的路", "job":"码农", "deposit":100.0}能够看到增加胜利: ...

March 9, 2023 · 1 min · jiezi

关于java:Java中restTemplate携带Header请求

创立申请创立申请头: Map<String, String> requestBody = new HashMap<>();requestBody.put("userId", userId);requestBody.put("userName", userName);创立申请体: HttpHeaders requestHeader = new HttpHeaders();requestHeader.add("cookie", "cookie");requestHeader.add("userInfo", "{userId:101,userName:userName}");创立申请形式: HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(requestHeader);RestTemplate restTemplate = new RestTemplate();POST申请restTemplate发送POST申请时能够通过如下办法获取ResponseEntity: ResponseEntity responseEntity = restTemplate.postForEntity(url, httpEntity, JSONObject.class);或用以下办法获取jsonObject: JSONObject jsonObject = restTemplate.postForObject(url, httpEntity, JSONObject.class);GET申请GET申请没有相应的办法,只能用exchange办法获取ResponseEntity: ResponseEntity<JSONObject> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, JSONObject.class, requestBody);若呈现如下报错: Not enough variables available to expand则是因为RestTemplate认为大括号{}为占位符,须要将申请头中的{userId:101,userName:userName}改为{\"userId\":\"101\",\"userName\":\"userName\"}    学习更多编程常识,请关注我的公众号: 代码的路

March 9, 2023 · 1 min · jiezi

关于java:还不知道如何在java中终止一个线程快来一文给你揭秘

简介工作中咱们常常会用到线程,个别状况下咱们让线程执行就完事了,那么你们有没有想过如何去终止一个正在运行的线程呢? 明天带大家一起来看看。 Thread.stop被禁用之谜问道怎么终止一个线程,可能大多数人都晓得能够调用Thread.stop办法。 然而这个办法从jdk1.2之后就不举荐应用了,为什么不举荐应用呢? 咱们先来看下这个办法的定义: @Deprecated(since="1.2") public final void stop() { @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { checkAccess(); if (this != Thread.currentThread()) { security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION); } } // A zero status value corresponds to "NEW", it can't change to // not-NEW because we hold the lock. if (threadStatus != 0) { resume(); // Wake up thread if it was suspended; no-op otherwise } // The VM can handle all thread states stop0(new ThreadDeath()); }从代码咱们能够看出,stop这个办法首先检测有没有线程拜访的权限。如果有权限的话,来判断以后的线程是否是刚刚创立的线程,如果不是刚刚创立的,那么就调用resume办法来解除线程的暂停状态。 ...

March 9, 2023 · 2 min · jiezi

关于java:盘点10个最受欢迎IntelliJ-IDEA主题必有一款适合你

抉择一款适宜本人的主题,这样每天工作才不会累!上面给大家精选了一批优良的主题,并配上案例截图。如果有你喜爱的,那就连忙去下载吧! Darcula这是IntelliJ IDEA默认的暗色主题,适宜长时间应用,缩小眼睛疲劳。 Material Theme UI一款基于谷歌Material Design的主题,领有娇艳的色彩和现代化的UI设计。 One Dark一款受欢迎的VS Code主题,也能够在IntelliJ IDEA上应用。领有深色背景和亮堂的代码高亮。 Solarized一款经典的主题,具备柔和的色彩和对比度,使得代码更容易浏览。 Nord一款冷色调主题,具备清晰的代码高亮和现代化的UI设计。 Dracula另一个受欢迎的暗色主题,领有紫色和粉色的配色计划。欢送关注公众号:TJ君,订阅每日举荐,获取更多好用效率工具! Monokai一款受欢迎的代码高亮主题,领有娇艳的色彩和对比度。 Gruvbox一款和煦的主题,具备棕色和黄色的配色计划,适宜长时间应用。 Atom One Dark一款Atom编辑器的主题,也能够在IntelliJ IDEA上应用。具备深色背景和亮堂的代码高亮。 Obsidian一款彩色主题,具备简洁的UI设计和清晰的代码高亮。 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

March 9, 2023 · 1 min · jiezi

关于java:面试官Configuration-和-Component-注解的区别大部分人都会答错

一句话概括就是 @Configuration 中所有带 @Bean 注解的办法都会被动静代理,因而调用该办法返回的都是同一个实例。 了解:调用@Configuration类中的@Bean注解的办法,返回的是同一个示例;而调用@Component类中的@Bean注解的办法,返回的是一个新的实例。 留神:下面说的调用,而不是从spring容器中获取! 见最上面的示例 1 及 示例 2上面看看实现的细节。 @Configuration 注解:@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Configuration { String value() default "";}从定义来看, @Configuration注解实质上还是@Component,因而 <context:component-scan/> 或者 @ComponentScan 都能解决@Configuration注解的类。 @Configuration标记的类必须合乎上面的要求: 配置类必须以类的模式提供(不能是工厂办法返回的实例),容许通过生成子类在运行时加强(cglib 动静代理)。配置类不能是final 类(没法动静代理)。配置注解通常为了通过 @Bean注解生成 Spring 容器治理的类,配置类必须是非本地的(即不能在办法中申明,不能是 private)。任何嵌套配置类都必须申明为static。@Bean办法可能不会反过来创立进一步的配置类(也就是返回的 bean 如果带有 @Configuration,也不会被非凡解决,只会作为一般的 bean)。@Bean 注解办法执行策略举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practice先给一个简略的示例代码: @Configurationpublic class MyBeanConfig { @Bean public Country country(){ return new Country(); } @Bean public UserInfo userInfo(){ return new UserInfo(country()); }}置信大多数人第一次看到下面 userInfo() 中调用 country()时,会认为这里的 Country和下面 @Bean办法返回的 Country 可能不是同一个对象,因而可能会通过上面的形式来代替这种形式: ...

March 9, 2023 · 2 min · jiezi

关于java:BlockingQueue-LinkedBlockingQueue

LinkedBlockingQueue是一个能够有界、也能够无界的阻塞队列,以FIFO(先进先出)的形式拜访队列。 head是队首节点,是进入队列工夫最长的节点,tail是队尾节点,是进入队列工夫最短的节点。 节点从队尾退出队列,从head出队。 LinkedBlockingQueue#次要属性节点:通过外部类Node定义节点: static class Node<E> { E item; Node<E> next; Node(E x) { item = x; } }很简略,次要属性就两个:next:下一节点。item:节点蕴含的数据。 capacity:队列容量,无界队列值为Integer.MAX_VALUE。 count:队列以后节点数,AtomicInteger类型。 head:头节点。 last:尾结点。 takeLock:ReentrantLock,出队锁,也就是从队列获取数据的锁。 notEmpty:takeLock的Condition,帮助获取数据的线程排队。 putLock:ReentrantLock,入队锁,数据退出队列的锁。 notFull:putLock的Condition,帮助退出队列的线程排队。 构造方法无参构造方法创立一个无边界空队列。 public LinkedBlockingQueue() { this(Integer.MAX_VALUE); }带容量参数capacity的构造方法创立一个有界空队列 public LinkedBlockingQueue(int capacity) { if (capacity <= 0) throw new IllegalArgumentException(); this.capacity = capacity; last = head = new Node<E>(null); }汇合参数结构器创立一个无界队列,将参数的汇合初始化到队列中: public LinkedBlockingQueue(Collection<? extends E> c) { this(Integer.MAX_VALUE); final ReentrantLock putLock = this.putLock; putLock.lock(); // Never contended, but necessary for visibility try { int n = 0; for (E e : c) { if (e == null) throw new NullPointerException(); if (n == capacity) throw new IllegalStateException("Queue full"); enqueue(new Node<E>(e)); ++n; } count.set(n); } finally { putLock.unlock(); } }须要留神创立的队列中必然会蕴含一个dummy性质的head节点,所以出队列的时候这个head节点必定也须要跳过。 ...

March 8, 2023 · 2 min · jiezi

关于java:Java多种方法实现等待所有子线程完成再继续执行

简介在事实世界中,咱们经常须要期待其它工作实现,能力继续执行下一步。Java实现期待子线程实现再继续执行的形式很多。咱们来一一查看一下。 Thread的join办法该办法是Thread提供的办法,调用join()时,会阻塞主线程,等该Thread实现才会继续执行,代码如下: private static void threadJoin() { List<Thread> threads = new ArrayList<>(); for (int i = 0; i < NUM; i++) { Thread t = new Thread(new PkslowTask("Task " + i)); t.start(); threads.add(t); } threads.forEach(t -> { try { t.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } }); System.out.println("threadJoin Finished All Tasks...");}后果: Task 6 is runningTask 9 is runningTask 3 is runningTask 4 is runningTask 7 is runningTask 0 is runningTask 2 is runningTask 1 is runningTask 5 is runningTask 8 is runningTask 1 is completedTask 8 is completedTask 6 is completedTask 4 is completedTask 3 is completedTask 0 is completedTask 7 is completedTask 9 is completedTask 2 is completedTask 5 is completedthreadJoin Finished All Tasks...CountDownLatchCountDownLatch是一个很好用的并发工具,初始化时要指定线程数,如10。在子线程调用countDown()时计数减1。直到为0时,await()办法才不会阻塞。代码如下: ...

March 8, 2023 · 4 min · jiezi

关于java:一个NASAGoogle都在用的开源CMSwagtail

说起开源CMS,你会想到哪些呢?WordPress?DoraCMS?joomla? 明天再给大家举荐一个十分好用的开源CMS:Wagtail 如果您正在选型的话,能够理解一下Wagtail的特点: 基于Django构建,具备杰出的文档治理性能和敌对的用户界面。提供了一个灵便且易于应用的页面编辑器,反对多种类型的内容块,包含文本、图像、视频和HTML代码。具备杰出的SEO性能,包含敌对的URL和元标记治理。反对多语言网站,并提供了一个易于应用的翻译界面。齐全开源的CMS,领有弱小的社区反对和沉闷的开发人员社区。内容审核和版本控制:wagtail反对审核和审批工作流程,以确保您的内容在公布之前通过审核和批准。网站搜寻:wagtail提供了一个易于应用的搜寻框架,反对全文搜寻和过滤器。云存储反对:wagtail反对多种云存储服务,包含Amazon S3和Google Cloud Storage,以帮忙您治理和存储大量的媒体文件。定制化:wagtail提供了一个灵便的插件零碎,使您能够轻松地增加自定义性能和扩大。Wagtail的忠诚用户中还有NASA、OXFAM、NHS、Google等出名公司 目前wagtail在GitHub上领有14.3k的Star,可见其用户与生态是十分宏大的。 总之,wagtail的性能十分弱小且灵便,实用于各种不同类型的网站,包含博客、新闻网站、企业门户等。如果您是一位开发人员或具备肯定的技术常识,那么wagtail相对是一个值得思考的抉择。 官方网站:https://wagtail.org/开源地址:https://github.com/wagtail/wagtail欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

March 8, 2023 · 1 min · jiezi

关于java:面试官什么是双亲委派模型

本文曾经收录进 JavaGuide(「Java学习+面试指南」一份涵盖大部分 Java 程序员所须要把握的外围常识。)加入过校招面试的同学,应该对这个问题不生疏。个别发问 JVM 知识点的时候,就会顺带问你双亲委派模型(顺当的翻译。。。)。 就算是不筹备面试,学习双亲委派模型对于咱们也十分有帮忙。咱们比拟相熟的 Tomcat 服务器为了实现 Web 利用的隔离,就自定义了类加载并突破了双亲委派模型。 这篇文章我会先介绍类加载器,再介绍双亲委派模型,这样有助于咱们更好地了解。 目录概览: 回顾一下类加载过程开始介绍类加载器和双亲委派模型之前,简略回顾一下类加载过程。 类加载过程:加载->连贯->初始化。连贯过程又可分为三步:验证->筹备->解析。 加载是类加载过程的第一步,次要实现上面 3 件事件: 通过全类名获取定义此类的二进制字节流将字节流所代表的动态存储构造转换为办法区的运行时数据结构在内存中生成一个代表该类的 Class 对象,作为办法区这些数据的拜访入口类加载器类加载器介绍类加载器从 JDK 1.0 就呈现了,最后只是为了满足 Java Applet(曾经被淘汰) 的须要。起初,缓缓成为 Java 程序中的一个重要组成部分,赋予了 Java 类能够被动静加载到 JVM 中并执行的能力。 依据官网 API 文档的介绍: A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a "class file" of that name from a file system. ...

March 8, 2023 · 4 min · jiezi

关于java:如何搞定MySQL锁全局锁表级锁行级锁这篇文章告诉你答案太TMD详细了

概述锁是计算机协调多个过程或线程并发拜访某一资源的机制。在数据库中,除传统的计算资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发拜访的一致性、有效性是所有数据库必须解决的一个问题,锁抵触也是影响数据库并发拜访性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加简单。 MySQL中的锁,依照锁的粒度分,分为以下三类: 全局锁:锁定数据库中的所有表。表级锁:每次操作锁住整张表。行级锁:每次操作锁住对应的行数据。全局锁介绍全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,曾经更新操作的事务提交语句都将被阻塞。 其典型的应用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。 为什么全库逻辑备份,就须要加全就锁呢? A. 咱们一起先来剖析一下不加全局锁,可能存在的问题。 假如在数据库中存在这样三张表: tb_stock 库存表,tb_order 订单表,tb_orderlog 订单日志表。 在进行数据备份时,先备份了tb_stock库存表。而后接下来,在业务零碎中,执行了下单操作,扣减库存,生成订单(更新tb_stock表,插入tb_order表)。而后再执行备份 tb_order表的逻辑。业务中执行插入订单日志操作。最初,又备份了tb_orderlog表。此时备份进去的数据,是存在问题的。因为备份进去的数据,tb_stock表与tb_order表的数据不统一(有最新操作的订单信息,然而库存数没减)。 那如何来躲避这种问题呢? 此时就能够借助于MySQL的全局锁来解决。 B. 再来剖析一下加了全局锁后的状况 对数据库进行进行逻辑备份之前,先对整个数据库加上全局锁,一旦加了全局锁之后,其余的DDL、DML全副都处于阻塞状态,然而能够执行DQL语句,也就是处于只读状态,而数据备份就是查问操作。那么数据在进行逻辑备份的过程中,数据库中的数据就是不会发生变化的,这样就保障了数据的一致性和完整性。 语法加全局锁flush tables with read lock;数据备份mysqldump -uroot –p1234 itcast > itcast.sql开释锁unlock tables;特点数据库中加全局锁,是一个比拟重的操作,存在以下问题: 如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆。如果在从库上备份,那么在备份期间从库不能执行主库同步过去的二进制日志(binlog),会导致主从提早。在InnoDB引擎中,咱们能够在备份时加上参数 --single-transaction 参数来实现不加锁的一致性数据备份。 mysqldump --single-transaction -uroot –p123456 itcast > itcast.sql表级锁介绍表级锁,每次操作锁住整张表。锁定粒度大,产生锁抵触的概率最高,并发度最低。利用在MyISAM、InnoDB、BDB等存储引擎中。 对于表级锁,次要分为以下三类: 表锁元数据锁(meta data lock,MDL)意向锁表锁对于表锁,分为两类: 表共享读锁(read lock)表独占写锁(write lock)语法: 加锁:lock tables 表名... read/write。开释锁:unlock tables / 客户端断开连接 。特点: A. 读锁 左侧为客户端一,对指定表加了读锁,不会影响右侧客户端二的读,然而会阻塞右侧客户端的写。 测试: B.写锁 左侧为客户端一,对指定表加了写锁,会阻塞右侧客户端的读和写。 测试: 论断 ...

March 8, 2023 · 3 min · jiezi

关于java:BlockQueue-基于TransferQueue的SynchronousQueue

原来认为TransferQueue和TransferStack的实现应该是一样的,一个是Queue,一个是Stack,take的时候都是从head获取,只是put的时候不一样,Queue是放在队尾,Stack是压栈放在栈首。所以想两者的区别只是put不一样就能够了。 然而理论他们的算法差距不止是在put,差距还是比拟大的,了解了TransferStack的源码,并不是天经地义间接就能轻松了解TransferQueue的。 TransferQueue#QNode与TransferStack相似,通过QNode(TransferStack的叫SNode)存储“数据”或者获取数据的“申请”。 QNode次要属性: static final class QNode { volatile QNode next; // next node in queue volatile Object item; // CAS'ed to or from null volatile Thread waiter; // to control park/unpark final boolean isData;next:下一节点。waiter:该节点绑定的线程,与SNode的waiter含意一样。item:与SNode的item含意统一。isData:相似于SNode的mode,true示意是数据,false示意该节点是request。head:头节点,或者叫首节点。tail:尾结点。 比拟厌恶的是,他没有match!他也没有FULFILLING的mode,所以也就暗示了他的算法逻辑和TransferStack的差距可能会比拟大。 QNode提供了几个原子性的操作: casNext:cas形式替换以后节点的下一节点casItem:cas形式替换以后节点的itemtryCancel;cas形式设置以后节点的item为本人,用这种形式示意该节点被calceladvanceHead:cas的形式批改头节点,其实就是队列从head出队列advanceTail:从队尾入队TransferQueue#初始化 TransferQueue() { QNode h = new QNode(null, false); // initialize to dummy node. head = h; tail = h; }构造函数创立了一个“dummy node”并设置为head、tail,须要留神,这个“dummy node”在take操作的时候必须要跳过。 TransferQueue#transferTransferQueue的重头戏,入队列和出队列都是这一个办法。 代码的解析放在正文中了: E transfer(E e, boolean timed, long nanos) { QNode s = null; // constructed/reused as needed boolean isData = (e != null); for (;;) { QNode t = tail; QNode h = head; //如果以后队列尚未实现初始化,则期待初始化实现 if (t == null || h == null) // saw uninitialized value continue; // spin //队列空,或者以后操作与tail的mode雷同 //这种状况下,队列内的节点与以后申请节点无奈匹配,所以,以后申请节点入队 if (h == t || t.isData == isData) { // empty or same-mode QNode tn = t.next; //并发操作过程中,t曾经不是尾结点了(其余线程有节点入队了),重来主循环 if (t != tail) // inconsistent read continue; //有新节点退出队尾了,从新设置尾结点,重来主循环 if (tn != null) { // lagging tail advanceTail(t, tn); continue; } //等超时的,返回null if (timed && nanos <= 0) // can't wait return null; //创立新节点 if (s == null) s = new QNode(e, isData); //新节点退出队尾,退出失败的话,重来 if (!t.casNext(null, s)) // failed to link in continue; //新节点设置为尾结点 --- 实现入队 advanceTail(t, s); // swing tail and wait //通过自旋或者阻塞以后过程,期待匹配 Object x = awaitFulfill(s, e, timed, nanos); //期待匹配过程中,节点勾销,则clean之后,返回null if (x == s) { // wait was cancelled clean(t, s); return null; } //实现匹配了,要么就是自旋过程中间接实现了匹配,要么就是阻塞后被匹配胜利的节点唤醒了 //如果s还在队列中 if (!s.isOffList()) { // not already unlinked //则s的上一节点如果是首节点的话,换成s为首节点,原来的首节点t移除队列 //接下来的操作逻辑基于:s曾经匹配胜利,原来的头节点出队列,s如果是数据节点的话解除s对数据的援用,s节点变为一个dummy类的节点变更为head advanceHead(t, s); // unlink if head //匹配胜利后,如果x!=null,阐明以后节点s是"request",匹配到了“data” if (x != null) // and forget fields //s的item指向本人,因为x就要返回来,开释掉s对x的援用 s.item = s; //s的期待线程置空 s.waiter = null; } //匹配胜利,返回 return (x != null) ? (E)x : e; //否则,队列不空并且mode不同,能够匹配 } else { // complementary-mode //筹备进行匹配,留神获取的是首节点的下一个节点,跳过了首节点 QNode m = h.next; // node to fulfill //处理过程中队列产生了变动,重来 if (t != tail || m == null || h != head) continue; // inconsistent read Object x = m.item; //如果m曾经被其余节点匹配过,或者m被勾销,或者匹配失败,就把m更换为头节点,持续主循环 //如果m没有被匹配也没有被勾销,则通过casItem的形式进行匹配,匹配实现后,m节点的isData会变更为反向 //即:request节点变更为data,data节点变更为request, //这个操作是为了在唤醒对应的阻塞过程后使得阻塞过程满足实现匹配的条件,相似于Stack的match赋值 if (isData == (x != null) || // m already fulfilled x == m || // m cancelled !m.casItem(x, e)) { // lost CAS advanceHead(h, m); // dequeue and retry continue; } //匹配实现的话,首节点出队列,须要留神,m节点并没有出队列,而是变为了首节点, //阻塞过程被唤醒后会把m节点解决为相似于dummy节点。首节点在下次匹配的时候会被跳过 advanceHead(h, m); // successfully fulfilled //唤醒m节点的阻塞过程 LockSupport.unpark(m.waiter); //返回 return (x != null) ? (E)x : e; } } }TransferQueue#awaitFulfillawaitFulfill的作用是通过自旋、或者阻塞以后线程来期待节点被匹配。 ...

March 8, 2023 · 3 min · jiezi

关于java:开源API越权漏洞检测系统推荐IDORdetecttool

置信大部分读者跟我一样,每天都在写各种API为Web利用提供数据反对,那么您是否有想过您的API是否足够平安呢? Web利用的平安是网络安全中不可漠视的要害方面。咱们必须确保其Web利用与后盾通信的平安,以避免数据泄露,因为这可能导致重大的财务损失和名誉受损。 而在Web利用的平安问题中,最常见的破绽之一是不平安的间接对象援用,简称:IDOR。即:当应用程序容许用户拜访他们不应该拜访的资源时,就会产生IDOR破绽。比方:SaaS软件的用户A拜访到了用户B的数据,这样的破绽是灾难性的,因为用户将不再信赖您提供的服务。 那么如何不便、快捷的检测IDOR破绽呢?明天就给大家举荐一个好用的开源工具:IDOR_detect_tool IDOR_detect_tool的应用简略,只须要上面几个步骤: 从 GitHub 存储库下载工具筹备好指标零碎的A、B两账号,依据零碎的鉴权逻辑(Cookie、header、参数等)将A账号信息配置config/config.yml,之后登录B账号应用B账号拜访,脚本会主动替换鉴权信息并重放,依据响应后果判断是否存在越权破绽生成报表,每次有新破绽都会主动增加到report/result.html中,通过浏览器关上点击具体条目能够开展/折叠对应的申请和响应如果您刚好在做这个内容,无妨看看这个开源我的项目! 开源地址:https://github.com/y1nglamore/IDOR_detect_tool 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

March 8, 2023 · 1 min · jiezi

关于java:Spring-Boot-MybatisX-王炸

1.什么是MybatisX?MybatisX 是一款基于 IDEA 的疾速开发插件,不便在应用mybatis以及mybatis-plus开始时简化繁琐的反复操作,进步开发速率。 2.应用MybatisX的益处节俭大量长久层代码开发工夫弱小的性能为业务编写提供各类反对配置简略,辞别各类简单的配置文件3.如何应用MybatisX?1.创立一个简略的数据库 2.创立一个简略的Springboot工程 3.在pom.xml文件中引入mybatis-plus依赖 <!--mybatisPlus--><dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version></dependency>举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practice4.在File->Settings->Plugins下载MybatiX插件 5.两下SHIFT键搜寻database进入数据库 6.新建Mysql连贯 输出用户、明码及数据库名 当Test Connection时会提醒这么一段话:这是时区未设置问题 依据提醒来到Advanced,找到severTimezone,将其设置为GMT(Greenwich Mean Time格林尼治规范工夫) 此时再测试连贯会发现曾经胜利 这时候咱们就能够看见咱们想要连贯的数据库和其对应的表等信息了 右键对应的表,咱们能够看到MybatiX-Generator 点击后咱们会看到这样一个页面,咱们能够在这个页面中设置须要打消的前后缀、文件寄存目录等... 点击Next,在上面是一些配置,咱们勾选Mybatis-Plus的最新版本Mybatix-Plus 3 和 简化开发的Lombok 点击Finish,咱们能够看到MybatisX为咱们主动生成了该表对应的实体类、Mapper文件、Service和绝对应的接口 在yaml中对数据库进行配置: application.yaml spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/user?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT username: root password: password管制层编写办法,应用到Mybatis-Plus中的条件结构器: package com.example.mybatixtest.controller;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.example.mybatixtest.pojo.User;import com.example.mybatixtest.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class TestController { @Autowired UserService userService; @GetMapping("/test") public User test(){ QueryWrapper<User> userQueryWrapper = new QueryWrapper<>(); userQueryWrapper.eq("user_id",1); User user = userService.getOne(userQueryWrapper); return user; }}拜访胜利 ...

March 8, 2023 · 1 min · jiezi

关于java:java如何控制线程按照顺序执行

1、应用Thread.join()办法能够在一个线程中调用另一个线程的join()办法,使得该线程期待另一个线程执行实现后再继续执行。能够通过在须要期待的线程前面调用join()办法的形式来控制线程的执行程序。 Thread t1 = new Thread(new Runnable() { public void run() { // 执行一些工作 }});Thread t2 = new Thread(new Runnable() { public void run() { // 期待t1线程执行实现 try { t1.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 继续执行一些工作 }});t1.start();t2.start();在这个例子中,t2线程在执行之前会期待t1线程执行实现,这样就能够保障t1先执行。 2、应用Lock和Condition能够应用Lock和Condition来控制线程的执行程序。Lock能够创立多个Condition对象,每个Condition对象能够管制一个线程的执行程序。应用Condition的await()办法能够使线程期待,应用signal()办法能够唤醒期待的线程。 class ShareResourceLock{ // 线程执行的条件 1:线程1执行 2:线程2执行 3:线程3执行 int number =1; // 锁 Lock lock = new ReentrantLock(); // 从锁中取得3个条件变量 Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); // 第一个线程run之后执行的办法 public void f1(){ lock.lock(); try { // 如果条件值不为1 就挂起期待 while(number!=1){ System.out.println(Thread.currentThread().getName() + " await..."); condition1.await(); } // 成心阻塞100毫秒,看看其余的线程会不会不再排队 int i= new Random().nextInt(2000); Integer sleepTime = 1000 + i; Thread.sleep(sleepTime); System.out.println(Thread.currentThread().getName() + " execute " + sleepTime); System.out.println("------1--------"); // 线程1 执行结束 把变量设置为2 number = 2; // 唤醒第2个条件变量 condition2.signal(); } catch (Exception e) { e.printStackTrace(); } finally { // 不论抛没抛出异样都要解锁,避免线程死锁 lock.unlock(); } } public void f2(){ lock.lock(); try { while(number!=2){ System.out.println(Thread.currentThread().getName() + " await..."); condition2.await(); } int i= new Random().nextInt(2000); Integer sleepTime = 1000 + i; Thread.sleep(sleepTime); System.out.println(Thread.currentThread().getName() + " execute " + sleepTime); System.out.println("------2--------"); number = 3; condition3.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void f3(){ lock.lock(); try { while(number!=3){ System.out.println(Thread.currentThread().getName() + " await..."); condition3.await(); } int i= new Random().nextInt(2000); Integer sleepTime = 1000 + i; Thread.sleep(sleepTime); System.out.println(Thread.currentThread().getName() + " execute " + sleepTime); System.out.println("------3--------"); number = 1; condition1.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } }}public class ThreadOrderExecute { public static void main(String[] args) throws InterruptedException { ShareResourceLock shareDataLock = new ShareResourceLock(); Thread t1 = new Thread(()->shareDataLock.f1(),"aa"); Thread t2 = new Thread(()->shareDataLock.f2(),"bb"); Thread t3 = new Thread(()->shareDataLock.f3(),"cc"); t1.start(); t2.start(); t3.start(); t1.join(); t2.join(); t3.join(); }}在这个例子中,t1线程执行实现后会唤醒t2线程,t2线程执行实现后会唤醒t3线程,这样就能够保障线程的执行程序。留神,await()和signal()办法必须在lock.lock()和lock.unlock()之间调用,否则会抛出IllegalMonitorStateException异样。 ...

March 7, 2023 · 2 min · jiezi

关于java:开发中相关功能流程图公众号

March 7, 2023 · 0 min · jiezi

关于java:自从用了-Stream代码更简洁优雅了

起源:blog.csdn.net/qq_41698074/article/details/108502976 前言尽管 stream在 Java8 中就曾经被引入,然而大多数人却没有去应用这个非常有用的个性,本文就通过介绍几个通过应用stream让代码更简洁、可读,来让你理解stream的不便之处。 技巧数组转汇合置信常常刷LeetCode的小伙伴,偶然会遇到须要将List与根本类型数组进行互转的状况,而后就须要写像上面这样的代码: // 将 List 元素存储到数组中List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));int[] arr = new int[list.size()];Integer[] temp = list.toArray(new Integer[0]);for (int i = 0; i < temp.length; i++) { arr[i] = temp[i];}// 将数组元素 存储到 List 中int[] arr = {1, 2, 3, 4, 5};List<Integer> list = new ArrayList<>();for (int val : arr) { list.add(val);}以上两个转换尽管写着还不算麻烦,然而每次都须要写一个循环,尤其在数组转List的时候还须要应用一个长期数组,都会让人看着很不难受,然而如果应用了stream就会大不一样,用stream实现了雷同性能的代码如下: // 将 List 元素存储到数组中List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));int[] arr = list.stream().mapToInt(Integer::intValue).toArray();// 将数组元素 存储到 List 中int[] arr = {1, 2, 3, 4, 5};List<Integer> list = IntStream.of(arr).boxed().collect(Collectors.toList());能够发现通过应用stream,咱们可能在写代码的时候更加连贯,代码也更加牢靠易保护,注意力也能够放在业务性能上,置信各位就算对lambda语法并不是太相熟,在浏览下面代码的时候,也很容易可能看懂。 ...

March 7, 2023 · 2 min · jiezi