码农参上

其他

用代码实现流水线部署,像诗一般优雅

removePrefixs.add("passjava-modules/passjava-module-account/passjava-module-account-core/target")
4月5日 下午 1:55
其他

除了关系型数据库外,还有好几种数据库类型呢

NoSQL,这种类型的数据库结构比较简单,就是一个键对应一个值,当然,值的类型可能有很多。由于结构简单,所以这种类型的存储可以有很高的读取写入速度,所以对读写性能要求比较高的环境可以用
2023年11月1日
其他

大厂都在用的Git代码管理规范

messages可以达到3个重要的目的:加快代码review的流程帮助我们编写良好的版本发布日志让之后的维护者了解代码里出现特定变化和feature被添加的原因Angular
2023年9月4日
其他

简化本地Feign调用,老手教你这么玩

哈喽大家好啊,我是Hydra。在平常的工作中,OpenFeign作为微服务间的调用组件使用的非常普遍,接口配合注解的调用方式突出一个简便,让我们能无需关注内部细节就能实现服务间的接口调用。但是工作中用久了,发现Feign也有些使用起来麻烦的地方,下面先来看一个问题,再看看我们在工作中是如何解决,以达到简化Feign使用的目的。先看问题在一个项目开发的过程中,我们通常会区分开发环境、测试环境和生产环境,如果有的项目要求更高的话,可能还会有个预生产环境。开发环境作为和前端开发联调的环境,一般使用起来都比较随意,而我们在进行本地开发的时候,有时候也会将本地启动的微服务注册到注册中心nacos上,方便进行调试。这样,注册中心的一个微服务可能就会拥有多个服务实例,就像下面这样:眼尖的小伙伴肯定发现了,这两个实例的ip地址有一点不同。线上环境现在一般使用容器化部署,通常都是由流水线工具打成镜像然后扔到docker中运行,因此我们去看一下服务在docker容器内的ip:可以看到,这就是注册到nacos上的服务地址之一,而列表中192开头的另一个ip,则是我们本地启动的服务的局域网地址。看一下下面这张图,就能对整个流程一目了然了。总结一下:两个service都是通过宿主机的ip和port,把自己的信息注册到nacos上线上环境的service注册时使用docker内部ip地址本地的service注册时使用本地局域网地址那么这时候问题就来了,当我本地再启动一个serviceB,通过FeignClient来调用serviceA中的接口时,因为Feign本身的负载均衡,就可能把请求负载均衡到两个不同的serviceA实例。如果这个调用请求被负载均衡到本地serviceA的话,那么没什么问题,两个服务都在同一个192.168网段内,可以正常访问。但是如果负载均衡请求到运行在docker内的serviceA的话,那么问题来了,因为网络不通,所以会请求失败:说白了,就是本地的192.168和docker内的虚拟网段172.17属于纯二层的两个不同网段,不能互访,所以无法直接调用。那么,如果想在调试时把请求稳定打到本地服务的话,有一个办法,就是指定在FeignClient中添加url参数,指定调用的地址:@FeignClient(value
2023年6月9日
其他

从实现到原理,聊聊Java中的SPI动态扩展

八股文背多了,相信大家都听说过一个词,SPI扩展。有的面试官就很喜欢问这个问题,SpringBoot的自动装配是如何实现的?基本上,你一说是基于spring的SPI扩展机制,再把spring.factories文件和EnableAutoConfiguration提一下,那么这个问题就答的八九不离十了。就像四五年前,我去面试的时候被问到这个问题,SPI动态扩展机制这几个词从嘴里一说出来,就把面试官唬的一愣一愣的。可能他们也没见过这么能装逼的,一句话能简简单单说明白,非要拽一个听上去很高大上的词。话说回来,被唬住的可不止是面试官,其实还有我自己。至于SPI扩展究竟是个啥,是怎么实现的,我当时也根本不明白。不过现在的面试就是这样,对线八股文,要想唬住面试官,就得先唬住自己。那么我们今天暂且不提spring的SPI扩展,先来看看java本身自带的SPI扩展机制是怎么一回事。1、简介SPI的全称是Service
2023年2月15日
其他

Paxos分布式系统共识算法?我愿称其为点歌算法…

哈喽大家好啊,我是Hydra。分布式系统共识算法Paxos相信大家都不陌生,它被称为最难理解的算法不是没有道理的,首先,它的发表之路就充满了坎坷。1990年,莱斯利·兰伯特大佬写了一篇论文,举了一个城邦选举的例子来介绍Paxos算法,然而大佬的幽默感并未得到审稿人的认可,论文未发表成功…1998年,兰伯特重新发表论文《The
2022年10月21日
其他

魔改xxl-job,彻底告别手动配置任务!

哈喽大家好啊,我是Hydra。xxl-job是一款非常优秀的任务调度中间件,轻量级、使用简单、支持分布式等优点,让它广泛应用在我们的项目中,解决了不少定时任务的调度问题。我们都知道,在使用过程中需要先到xxl-job的任务调度中心页面上,配置执行器executor和具体的任务job,这一过程如果项目中的定时任务数量不多还好说,如果任务多了的话还是挺费工夫的。假设项目中有上百个这样的定时任务,那么每个任务都需要走一遍绑定jobHander后端接口,填写cron表达式这个流程…我就想问问,填多了谁能不迷糊?于是出于功能优化(偷懒)这一动机,前几天我萌生了一个想法,有没有什么方法能够告别xxl-job的管理页面,能够让我不再需要到页面上去手动注册执行器和任务,实现让它们自动注册到调度中心呢。分析分析一下,其实我们要做的很简单,只要在项目启动时主动注册executor和各个jobHandler到调度中心就可以了,流程如下:有的小伙伴们可能要问了,我在页面上创建执行器的时候,不是有一个选项叫做自动注册吗,为什么我们这里还要自己添加新执行器?其实这里有个误区,这里的自动注册指的是会根据项目中配置的xxl.job.executor.appname,将配置的机器地址自动注册到这个执行器的地址列表中。但是如果你之前没有手动创建过执行器,那么是不会给你自动添加一个新执行器到调度中心的。既然有了想法咱们就直接开干,先到github上拉一份xxl-job的源码下来:https://github.com/xuxueli/xxl-job/https://github.com/xuxueli/xxl-job/整个项目导入idea后,先看一下结构:结合着文档和代码,先梳理一下各个模块都是干什么的:xxl-job-admin:任务调度中心,启动后就可以访问管理页面,进行执行器和任务的注册、以及任务调用等功能了xxl-job-core:公共依赖,项目中使用到xxl-job时要引入的依赖包xxl-job-executor-samples:执行示例,分别包含了springboot版本和不使用框架的版本为了弄清楚注册和查询executor和jobHandler调用的是哪些接口,我们先从页面上去抓一个请求看看:好了,这样就能定位到xxl-job-admin模块中/jobgroup/save这个接口,接下来可以很容易地找到源码位置:按照这个思路,可以找到下面这几个关键接口:/jobgroup/pageList:执行器列表的条件查询/jobgroup/save:添加执行器/jobinfo/pageList:任务列表的条件查询/jobinfo/add:添加任务但是如果直接调用这些接口,那么就会发现它会跳转到xxl-job-admin的的登录页面:其实想想也明白,出于安全性考虑,调度中心的接口也不可能允许裸调的。那么再回头看一下刚才页面上的请求就会发现,它在Headers中添加了一条名为XXL_JOB_LOGIN_IDENTITY的cookie:至于这条cookie,则是在通过用户名和密码调用调度中心的/login接口时返回的,在返回的response可以直接拿到。只要保存下来,并在之后每次请求时携带,就能够正常访问其他接口了。到这里,我们需要的5个接口就基本准备齐了,接下来准备开始正式的改造工作。改造我们改造的目的是实现一个starter,以后只要引入这个starter就能实现executor和jobHandler的自动注册,要引入的关键依赖有下面两个:
2022年9月23日
其他

Redis6通信协议升级至RESP3,一口气看完13种新数据类型

message$9Get-Reply在上面的这段回复中需要注意,收到的两个回复中第一个是推送数据的类型,第二个才是真正回复的数据内容。注意!这里在文档中有一句提示:虽然下面的演示使用的是Simple
2022年4月21日
其他

编译实战 | 手摸手教你在Windows环境下运行Redis6.x

哈喽大家好啊,我是没事就愿意瞎捣鼓的Hydra。不知道有没有小伙伴像我一样,平常开发中用的是windows操作系统,有时候想装点什么软件,一看只支持linux系统,无奈要么启动虚拟机、要么装在云服务器上。这不前几天又是这样,刚想用一下Redis
2022年4月2日
其他

基于Spring接口,集成Caffeine+Redis两级缓存

在上一篇文章Redis+Caffeine两级缓存,让访问速度纵享丝滑中,我们介绍了3种整合Caffeine和Redis作为两级缓存使用的方法,虽然说能够实现功能,但实现手法还是太粗糙了,并且遗留了一些问题没有处理。本文将在上一篇的基础上,围绕两个方面进行进一步的改造:JSR107定义了缓存使用规范,spring中提供了基于这个规范的接口,所以我们可以直接使用spring中的接口进行Caffeine和Redis两级缓存的整合改造在分布式环境下,如果一台主机的本地缓存进行修改,需要通知其他主机修改本地缓存,解决分布式环境下本地缓存一致性问题好了,在明确了需要的改进问题后,下面我们开始正式修改。改造在上篇文章的v3版本中,我们使用自定义注解的方式实现了两级缓存通过一个注解管理的功能。本文我们换一种方式,直接通过扩展spring提供的接口来实现这个功能,在进行整合之前,我们需要简单了解一下JSR107缓存规范。JSR107
2022年3月31日
其他

Redis+Caffeine两级缓存,让访问速度纵享丝滑

在高性能的服务架构设计中,缓存是一个不可或缺的环节。在实际的项目中,我们通常会将一些热点数据存储到Redis或MemCache这类缓存中间件中,只有当缓存的访问没有命中时再查询数据库。在提升访问速度的同时,也能降低数据库的压力。随着不断的发展,这一架构也产生了改进,在一些场景下可能单纯使用Redis类的远程缓存已经不够了,还需要进一步配合本地缓存使用,例如Guava
2022年3月18日
其他

5道面试题,拿捏String底层原理!

String字符串是我们日常工作中常用的一个类,在面试中也是高频考点,这里Hydra精心总结了一波常见但也有点烧脑的String面试题,一共5道题,难度从简到难,来一起来看看你能做对几道吧。本文基于jdk8版本中的String进行讨论,文章例子中的代码运行结果基于Java
2022年2月11日
其他

动图图解GC算法 - 让垃圾回收动起来!

提到Java中的垃圾回收,我相信很多小伙伴和我一样,第一反应就是面试必问了,你要是没背过点GC算法、收集器什么的知识,出门都不敢说自己背过八股文。说起来还真是有点尴尬,工作中实际用到这方面知识的场景真是不多,并且这东西学起来也很枯燥,但是奈何面试官就是爱问,我们能有什么办法呢?既然已经卷成了这样,不学也没有办法,Hydra牺牲了周末时间,给大家画了几张动图,希望通过这几张图,能够帮助大家对垃圾收集算法有个更好的理解。废话不多说,首先还是从基础问题开始,看看怎么判断一个对象是否应该被回收。判断对象存活垃圾回收的根本目的是利用一些算法进行内存的管理,从而有效的利用内存空间,在进行垃圾回收前,需要判断对象的存活情况,在jvm中有两种判断对象的存活算法,下面分别进行介绍。1、引用计数算法在对象中添加一个引用计数器,每当有一个地方引用它时计数器就加
2021年9月26日
自由知乎 自由微博
其他

面试官:说说什么是泛型的类型擦除?

HashMap();System.out.println(Arrays.asList(map.getClass().getTypeParameters()));最终也只能够获取到:[K,
2021年8月24日
其他

String s="a"+"b"+"c",到底创建了几个对象?

s2=UUID.randomUUID().toString()+"Hydra";编译器能够在编译期就得到s1的值是hello
2021年8月16日
其他

面试侃集合 | DelayQueue篇

面试官:好久不见啊,上次我们聊完了PriorityBlockingQueue,今天我们再来聊聊和它相关的DelayQueue吧?Hydra:就知道你前面肯定给我挖了坑,DelayQueue也是一个无界阻塞队列,但是和之前我们聊的其他队列不同,不是所有类型的元素都能够放进去,只有实现了Delayed接口的对象才能放进队列。Delayed对象具有一个过期时间,只有在到达这个到期时间后才能从队列中取出。面试官:有点意思,那么它有什么使用场景呢?Hydra:不得不说,由于DelayQueue的精妙设计,使用场景还是蛮多的。例如在电商系统中,如果有一笔订单在下单30分钟内没有完成支付,那么就需要自动取消这笔订单。还有,如果我们缓存了一些数据,并希望这些缓存在一定时间后失效的话,也可以使用延迟队列将它从缓存中删除。以电商系统为例,可以简单看一下这个流程:面试官:看起来和任务调度有点类似啊,它们之间有什么区别吗?Hydra:任务调度更多的偏向于定时的特性,是在指定的时间点或时间间隔执行特定的任务,而延迟队列更多偏向于在指定的延迟时间后执行任务。相对任务调度来说,上面举的例子中的延迟队列场景都具有高频率的特性,使用定时任务来实现它们的话会显得有些过于笨重了。面试官:好了,你也白话了半天了,能动手就别吵吵,还是先给我写个例子吧。Hydra:好嘞,前面说过存入队列的元素要实现Delayed接口,所以我们先定义这么一个类:public
2021年6月28日
其他

Redis:我是如何与客户端进行通信的

能达到10万级别。在我的手下有数不清的小弟,他们会时不时到我这来存放或者取走一些数据,我管他们叫做客户端,还给他们起了英文名叫
2021年6月22日
其他

面试侃集合 | ArrayBlockingQueue篇

2")).start();}在代码中创建队列时就往里放入了7个元素,然后创建两个线程各自从队列中取出元素。对队列的操作也非常简单,只用到了操作队列中出队方法take,运行结果如下:Thread
2021年5月17日
其他

Java筑基 - JNI到底是个啥

-jni生成c/c++风格的头文件(在jdk10的新特性中已经删除了javah这一指令)。我们使用的jdk8简化了这一步骤,使其可以一步完成,在命令行窗口下执行命令:javac
2021年5月11日
其他

Java双刃剑之Unsafe类详解

前一段时间在研究juc源码的时候,发现在很多工具类中都调用了一个Unsafe类中的方法,出于好奇就想要研究一下这个类到底有什么作用,于是先查阅了一些资料,一查不要紧,很多资料中对Unsafe的态度都是这样的画风:其实看到这些说法也没什么意外,毕竟Unsafe这个词直译过来就是“不安全的”,从名字里我们也大概能看来Java的开发者们对它有些不放心。但是作为一名极客,不能你说不安全我就不去研究了,毕竟只有了解一项技术的风险点,才能更好的避免出现这些问题嘛。下面我们言归正传,先通过简单的介绍来对Unsafe类有一个大致的了解。Unsafe类是一个位于sun.misc包下的类,它提供了一些相对底层方法,能够让我们接触到一些更接近操作系统底层的资源,如系统的内存资源、cpu指令等。而通过这些方法,我们能够完成一些普通方法无法实现的功能,例如直接使用偏移地址操作对象、数组等等。但是在使用这些方法提供的便利的同时,也存在一些潜在的安全因素,例如对内存的错误操作可能会引起内存泄漏,严重时甚至可能引起jvm崩溃。因此在使用Unsafe前,我们必须要了解它的工作原理与各方法的应用场景,并且在此基础上仍需要非常谨慎的操作,下面我们正式开始对Unsafe的学习。Unsafe
2021年4月29日
其他

Java实现基于朴素贝叶斯的情感词分析

1……这里对训练的模型进行保存,所以如果后续有同样的分类任务时,可以直接在训练集的基础上进行计算,对于分类速度要求较高的任务,能够有效的提高计算的速度。3、加载模型加载训练好的模型:private
2021年4月18日
其他

图文详解Java对象内存布局

作为一名Java程序员,我们在日常工作中使用这款面向对象的编程语言时,做的最频繁的操作大概就是去创建一个个的对象了。对象的创建方式虽然有很多,可以通过new、反射、clone、反序列化等不同方式来创建,但最终使用时对象都要被放到内存中,那么你知道在内存中的java对象是由哪些部分组成、又是怎么存储的吗?本文将基于代码进行实例测试,详细探讨对象在内存中的组成结构。全文目录结构如下:1、对象内存结构概述2、JOL
2021年3月27日
其他

Feign核心源码解析

Feign作为一个声明式的Http服务客户端,通过接口加注解的方式,就能够完成对服务提供方接口的调用,极大的简化了我们在调用服务时的工作。那么在只有接口的条件下,Feign是如何基于接口实现服务调用的呢?在之前的代理模式及mybatis实现原理的文章中,我们知道了可以通过动态代理的方式生成代理对象。Feign是否这样实现的呢,我们从源码角度进行分析。01初始化阶段首先看一下Feign的开启注解@EnableFeignClients:@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(FeignClientsRegistrar.class)public
2020年6月3日
其他

Spring Boot零配置启动原理

在创建传统SpringMVC项目时,需要复杂的配置文件,例如:1、web.xml,加载配置spring容器,配置拦截器2、application.xml,配置扫描包,扫描业务类3、springmvc.xml,扫描controller,视图解析器等……而Spring
2020年5月14日
其他

MyBatis 执行流程及源码解析

我们在日常工作中广泛使用mybatis作为数据持久层框架,但是mybatis的执行流程是怎么样的,你了解过吗。本文将从源码角度,带你分析mybatis的工作原理。先看一个简单的例子,以Service调用Mapper接口为例:public
2020年4月19日