- 博客(91)
- 收藏
- 关注
原创 PlantUML——类图
可见性符号publicprotectedprivate在Java中,类用class关键字、接口使用interface关键字,而抽象类使用abstract class,枚举类使用enum。在PlantUML中,我们同样可用用class、interface、abstract class和enum来分别表示出类、接口、抽象类和枚举。
2024-12-07 12:08:51
2136
1
原创 Java基础——(五)接口与内部类
假设我们现在有一个订单类,要求每次在支付订单的时候,能打印相关的日志,以方便后续去排查信息,在打印日志的时候,我们希望是异步打印的,一般情况下,我们可以在支付订单后,手动创建相关的线程并提交给线程池进行执行。在一个典型的基于抽象的设计中,一个接口有一个或多个实现类,接口要新增方法,所有的实现都要新增这个方法的实现,否则就不满足接口的约束,默认接口方法是处理这类问题的解决方案,通过在接口添加默认方法不需要修改实现类,接口新增的默认方法在实现类中直接可用。
2024-12-01 14:56:06
817
原创 Java基础——(四)继承
尽管我们这里将所有雇员对象都声明为Employee类型,但是在实例化对象是,因为staff[0]引用的是Manager对象,所以在getSalary时调用的是Manager类中的getSalary方法,也就是说虚拟机直到实际引用的对象类型,并且能够正确地调用相应的方法。参数与String[]完全一样。在下面代码中,我们定义一个包含三个雇员的数组,然后将经理和普通雇员都放到数组中,在循环中输出每个人的薪水,此时会看到1和2仅输出基本薪水,而0输出的是基本薪水加奖金,因为0对应的是Manager对象。
2024-12-01 10:41:59
1384
原创 Java基础——(三)对象和类
OOP:Object Oriented Programming,面向对象编程;OOD:Object Oriented Design,面向对象设计;OOA:Object Oriented Analyse,面向对象分析。面向对象程序设计(OOP)是当今主流的程序设计泛型。Java是完全面向对象的一门编程语言,它将一切以对象为载体去进行结构化设计和编程。在以前的编程,是面向过程的,比如实现一个算术运算1+1=2,这种通过一个简单的语句就能实现。
2024-11-30 20:48:58
1021
原创 PlantUML——时序图
在注册链路中,首先用户在浏览器上填写注册表单,点击发送按钮,会调用后端的注册服务去创建注册信息,在注册服务中,会调用账号服务创建对应的账号信息,以及绑定一些关联关系,创建成功后,调用登录服务去生成对应的登录token,下发登录态,最后发送相关的注册消息给下游。在时序图中,一般我们还会对每一个参与的角色,画上相关的生命线,用于表示对象的调用过程。首先,打开IDEA,找到setting,然后选择plugins,搜索PlantUML,找到如下插件,点击下载,然后重启idea,即可使用plantUML插件。
2024-11-17 14:10:56
3501
1
原创 TrieTree在区划查询的应用
trie是一种树状的数据结构根代表一个空字符串每个节点存储一个字符并有多个子节点,每个节点对应一个可能的字符每个树节点代表一个单词或一个前缀字符串如上图所示,对于区域划分,我们将区划全称依次加入到TrieTree后,生成的TrieTree的部分结构上图所示。在这棵TrieTree树中,叶子节点都是在我们数据库中真实存在的区划名称,而中间节点,有一些只是起到链接作用,而有一些也是数据库中真实存在的区划名称,比如广东、广西。@Data/*** 链接词,如广、东、汕、头*//**
2024-10-27 14:20:15
1142
原创 流程引擎实现(二)——排他网关
对于节点与节点之间的联系,是通过sequenceFlow来实现的,而目前我们的sequenceFlow只有source和target这两个信息,前者表示来源,后者表示去处,此时的sequenceFlow是没有阻塞条件的,当出现一个source有多个target时,我们可以在sequenceFlow加上阻塞条件,用于根据上下文信息,决策需要走哪一条路径。最后,修改ActivitiManager类,对排他网关做定制处理,根据网关返回的凭证值,决策出下一个节点是哪一个。
2024-10-05 11:51:28
1405
1
原创 SpringBoot日志打印实践
一般情况下,我们的项目会分为不同的模块,每一个模块承担不同的职责,比如bussiness模块,主要是负责业务逻辑代码的实现,业务逻辑编排等;在logback-spring.xml中,我们虽然能配置日志打印的格式,但是不够灵活,因此,我们可以添加一个日志打印工具类,通过该工具类,来自定义项目中的日志打印格式,以方便后续更好地通过日志排查、定位问题。对于不同的模块,我们希望将日志输出到不同的文件当中,从而协助我们后续定位问题以及建设不同模块下的监控,包括基础服务监控、业务成功率监控等。
2024-10-04 14:48:21
2223
原创 流程引擎实现(一)——串行流程实现
目前主流的开源流程引擎有activiti、flowable、camunda,在我的实际工作项目中,也用到了流程引擎,基于对流程引擎的好奇和兴趣,决定自己实现一个简单的流程引擎,一方面是锻炼自己的编程能力,另一方面是加深自己对流程引擎的一些理解和认识,下面是具体的实现思路。无论是什么类型的流程引擎,在执行的时候,都是依据配置文件中配置的流程执行顺序,挨个执行相应的流程节点,通过这些流程节点的活动和编排的顺序,完成相关的业务逻辑,从而对外提供服务。我们将这些类型,抽象到相关的枚举类中。
2024-10-03 12:45:30
1421
原创 Service层瘦身思考
在上述代码中,将每一个步骤都抽取为对应的方法,思路相对比较清晰,但这建立在业务逻辑相对稳定、简单的前提下,当后续业务逻辑开始改动,比如需要使用md5对密码进行加密、根据入参决定用户权限、通过jwt创建登录态token等等,此时我们虽然能在这些方法的基础上进行修改或新增,但是这些方法后续会越来越大,不利于后续的维护,此外,我们将这些步骤都堆积在service类中,不利于后续的职责分离。最后,创建配置类,将这些执行器按照顺序添加到RegisterFlow注册流程中,从而实现流程执行器在流程中的编排。
2024-10-03 12:43:49
994
原创 手撸XXL-JOB(四)——远程调用定时任务
Socket是Java网络编程的基本组件之一,用于在应用程序之间提供双向通信,Socket提供了一种标准的接口,允许应用程序通过网络发送和接收数据,在Java中,Socket可以分为客户端Socket和服务端Socket两种类型。YangJobClientManager负责监听端口和管理定时任务的执行,它会监听我们配置的yang-job.execute.port端口号,然后当接收到消息时,将消息转为入参,并取出对应的定时任务执行类,执行对应的代码。
2024-05-14 21:31:55
1435
1
原创 手撸XXL-JOB(三)——本地定时任务管理平台
为解决上述问题,我们可以通过事件的方式,进行解耦。在我的第一份实习中,遇到的项目,就是用事件的方式,来进行解耦,一开始我很不理解这种方式,因为发送的事件太多了,从开始到结束将近10个事件,每次看代码都要从一个事件处理类,跳到另一个事件处理类,但是后来看了一些DDD的书籍后,有点理解这种做法了,这种应该就是属于领域事件,因为这些事件,将不同子域串联起来,比如从收单到支付再到账户等域,通过领域事件,将这些不同的域串联起来,此外又不会使两个域之间存在强耦合的代码,从而方便后续的维护。
2024-05-14 21:05:28
1112
原创 手撸XXL-JOB(二)——定时任务管理
在上一节中,我们介绍了SpringBoot中关于定时任务的执行方式,以及ScheduledExecutorService接口提供的定时任务执行方法。假设我们现在要写类似XXL-JOB这样的任务调度平台,那么,对于任务的管理,是尤为重要的。接下来我们将一步一步,实现一个任务调度管理类。
2024-05-14 21:04:44
1511
原创 手撸XXL-JOB(一)——定时任务的执行
启动项目,执行结果如下。我们可以看到,executeFixedDelay在任务执行完毕后,间隔5秒才执行下一个任务,也就是说,两个任务之间间隔7秒,而executeFixedRate在任务执行开始后,间隔5秒执行下一个任务,也就是两个任务之间间隔5秒。fixedDelay和fixedRate很相似,但又略有不同,其中fixedDelay表示在某次任务执行完毕后,间隔fixedDelay的时间再执行,而fixedRate表示在某次任务执行开始后,间隔fixedRate的时间再执行。
2024-05-14 21:03:43
1656
原创 Redis学习6——Redis分布式锁
Redisson是一个在Redis基础上实现的Java驻内存数据网络,它不仅提供一系列的分布式java常用对象,还提供许多分布式服务,其宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能将精力更多集中在处理业务逻辑上。
2024-05-06 10:36:04
1369
原创 Redis学习5——Redis应用之签到
在很多时候,我们遇到用户签到的场景,用户进入应用时,获取用户当天的签到情况,如果没有签到,用户可以签到,一般这种功能,可以通过set数据结构或bitMap来实现,但bitMap和set相比,其占用的空间更小,因此我们选择使用bitMap来实现签到的功能。位图由一系列二进制位组成,每个位可以被设置为1或0,当我们在处理需要高效存储和操作大量二进制位数据的适合,位图是一个非常有用的工具。我们通过Redis可视化工具,查看bit的值,可以看出其二进制值与我们操作的一致。
2024-05-06 10:35:28
568
原创 Redis学习4——Redis应用之限流
Redis作为一个内存数据库其读写速度非常快,并且支持原子操作,这使得它非常适合处理频繁的请求,一般情况下,我们会使用Redis作为缓存数据库,但处理做缓存数据库之外,Redis的应用还十分广泛,比如这一节,我们将讲解Redis在限流方面的应用。我们可以将请求打造成一个zset数组,每一次请求进来时,value保持一致,可以用UUID生成,然后score用当前时间戳表示,通过range方法,来获取某个时间范围内,请求的个数,然后根据这个个数与限流值对比,当大于限流值时,进行限流操作。
2024-05-06 10:14:25
1416
1
原创 Redis学习3——Redis应用之缓存
注意,不能先删除cache,在写db,因为在并发的情况下,可能存在,请求1删除缓存,然后写db,并且写db操作还没结束,这时请求2获取缓存,此时因为缓存被删除了,因此会从数据库读数据, 并存入缓存,这个时候的数据是未更新的,当请求2结束后,请求1写db结束,此时就会造成数据库和缓存中的数据不一致。上面的代码,存在一些问题,当请求1查询id=1的用户,从缓存中查询不到时,会查询数据库,然后将数据更新到数据库,然后请求2查询id=1的用户,从缓存中查询到,便直接返回,这是理想的情况。
2024-05-06 10:13:43
1286
原创 Redis学习2——SpringBoot整合Redis,Redis工具类
依赖和配置pom.xmlSpringBoot整合Redis,需要引入spring-boot-starter-data-redis依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </depen
2024-05-06 10:13:04
725
原创 Redis学习1——redis简介、基础
Redis(Remote Dictonary Server) 是由Salvatore Sanfilippo开发的key-value缓存数据库,基于C语言开发。目前市面上,Redis和MongoDB是当前使用最广泛的NoSQL,而就Redis技术而言,它的性能十分优越,可以支持每秒十几万此的读/写操作,其性能远超数据库,并且还支持集群、分布式、主从同步等配置,原则上可以无限扩展,让更多的数据存储在内存中,更让人欣慰的是它还支持一定的事务能力,这保证了高并发的场景下数据的安全和一致性。
2024-05-06 10:12:19
895
1
原创 手撸Mybatis(五)——连接数据库进行insert,update和delete
可以看出,这里因为我们使用的是parameterType是int而不是java.lang.Integer,所以会报错,但是一般情况下,像int,float,long等小写,一般我们也会使用的,而且用的频率比java.lang.Integer的频率更大,那么,我们其实可以添加一个假名,将int这些小写的方式和对应的包装类关联起来。首先,我们在IUserMapper接口上,添加一个updateUserById方法。再次运行测试方法,这次没有报错了,然后我们查看数据库,结果如下,说明删除成功了。
2024-05-03 16:22:16
890
原创 手撸Mybatis(四)——连接数据库进行简单查询
这里将和结果相关的解析,抽取到parseResult方法中,此外,因为数据库是字段是下划线格式,类的属性是驼峰格式,因此,这里引入了Guava依赖,方便使用它的CaseFormat类进行格式转化。首先,我们修改DefaultMybatisSqlSession中,在该类中,执行我们的sql语句,其中,执行sql和对sql查询结果进行处理的内容,收敛在execute方法中。首先,我们修改MybatisSqlStatement,添加resultType字段。
2024-05-03 16:20:46
1238
原创 手撸Mybatis(三)——收敛SQL操作到SqlSession
在上一章,当我们调用mapper的方法时,最终是通过在MapperProxy中获取对应的MybatisStatement,然后打印出sql信息的,但是如果后续操作数据库是,也在MapperProxy中执行sql的话,不太方便管理。在上一章中,我们实现了读取mapper配置并构造相关的mapper代理对象,读取mapper.xml文件中的sql信息等操作,现在,在上一章的基础上,我们接着开始链接数据库,通过封装JDBC,来实现我们数据库操作。在使用jdbc之前,我们先引入mysql的依赖。
2024-05-03 16:17:46
1611
1
原创 手撸Mybatis(二)—— 配置项的获取
然后修改MapperProxy,接收MybatisSqlStatement数组,在执行的时候,根据执行方法,找到对应的MybatisSqlStatement,获取mapper Xml对应的sql语句,并打印出来。在mybatis中,一般我们会定义一个mapper-config.xml文件,来配置数据库连接的相关信息,以及我们的mapperxml文件存放目录。mybatis-config.xml的内容如下,对于每一个环境,都有对应的数据源信息,此外,mappers标签存储的是mapper.xml文件的位置。
2024-05-03 16:16:22
564
原创 手撸Mybatis(一)——代理mapper
在使用mybatis的时候,我们一般只需要定义mapper的接口,并添加相应的@Mapper注解,然后实现对应的xml文件即可,而不需要对mapper接口进行具体的实现。其实本质上,这些mapper接口是有实现的,但不是我们手动通过implement来实现,而是通过代理的方式进行实现。因此,对于Mybatis的手撸,首先要关注的,就是如何对mapper进行代理。像上述的这种方法,我们每次要获取一个Mapper,就要new一个对应的MapperProxyFactory,这样不太方便。然后创建对应的测试方法。
2024-05-03 16:14:38
459
原创 Executor线程池
Executors是一个工厂类,提供了创建几种预配置线程池实例地方法,如果不需要应用任何自定义地微调,可以调用这些方法创建默认配置地线程池。Executors工厂类提供地线程池有以下几种:1)newCachedThreadPool(): 创建一个可缓存地线程池,这个线程池地线程数量可以根据需要自动扩展,如果有可用的空闲线程,就会重用它们;如果没有可用的线程,就会创建一个新线程,适用于执行大量的短期异步任务。
2024-04-29 11:10:30
844
原创 继承和多态
多态是方法或对象具有多种形态。它的前提是两个对象(类)之间存在继承关系,也就是说它是建立在继承的基础上的。一个对象的编译类型与运行类型可以不一致,编译类型在定义对象时就确定了,不能改变,而运行类型是可以变化的。@OverrideSystem.out.println("学生在学习");@OverrideSystem.out.println("老师在教学生");
2023-10-15 20:31:11
281
原创 SpringBoot整合Swagger3.0
controller层,用@Tag注解描述这个controller类的具体功能,然后@Operation注解描述某个方法的具体功能,@Parameters用来记录方法中需要的参数,每个参数的含义。启动项目,访问http://localhost:8080/documentation/swagger-ui/index.html。我们配置Security的配置类,来解除对接口文档访问的拦截。在dto类里面,使用schema来描述类的信息和类的属性。重启项目,然后重新访问接口文档,发现被拦截了。
2023-05-23 10:25:09
1974
原创 dubbo处理自定义异常
在实际项目中,我们不可避免地需要使用自定义的异常,一般这个异常会继承RuntimeException,然后我们通过@RestControllerAdvice注解,拦截业务异常类,做一些处理,但是在使用dubbo构建项目时,会发现provider抛出自定义异常,然后在消费者端,不会捕捉到我们的自定义异常,而是以RuntimeException的形式被捕获。
2023-05-20 19:15:30
2639
原创 SpringBoot整合Caffeine
Caffeine 是基于Java 8 开发的、提供了近乎最佳命中率的高性能本地缓存组件,Spring5 开始不再支持 Guava Cache,改为使用 Caffeine。Caffeine与其他本地缓存的性能比较如下:1 . 自动加载条目到缓存中,可选异步方式2 . 可以基于大小剔除3 . 可以设置过期时间,时间可以从上次访问或上次写入开始计算4 . 异步刷新5 . keys自动包装在弱引用中6 . values自动包装在弱引用或软引用中7 . 条目剔除通知8 . 缓存访问统计。
2023-05-15 14:36:07
5363
1
原创 使用TrieTree(字典树)来实现敏感词过滤
字典树(TrieTree),是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串,如01字典树)。主要思想是利用字符串的公共前缀来节约存储空间。很好地利用了串的公共前缀,节约了存储空间。字典树主要包含两种操作,插入和查找。字典树具有以下规则:-1. 根节点不包含字符,其他节点包含一个字符。从根节点到某一节点经过的字符连接起来构成一个字符串。如图中的 him 、 her 、 cat 、 no 、 nova。一个字符串与 Trie 树中的一条路径对应。
2023-05-01 14:36:52
1913
原创 SpringBoot自定义注解
修饰符:访问修饰符必须为public,不写默认为pubic;关键字:关键字为@interface;注解名称:注解名称为自定义注解的名称注解类型元素:注解类型元素是注解中内容,根据需要标志参数,例如上面的注解的value;Annotation型定义为@interface, 所有的Annotation会自动继承java.lang.Annotation这一接口,并且不能再去继承别的类或是接口.参数成员只能用public或默认(default)这两个访问权修饰。
2023-04-30 14:17:40
5448
1
原创 SpringBoot中线程池应用
比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断,或者其它原因导致的任务暂停而带来的影响。I/O 密集型任务(2N): 这种任务应用起来,系统会用大部分的时间来处理 I/O 交互,而线程在处理 I/O 的时间段内不会占用 CPU 来处理,这时就可以将 CPU 交出给其它线程使用。1.2 不同业务用不同的线程池。配置线程池的时候要根据当前业务的情况对当前线程池进行配置,因为不同的业务的并发以及对资源的使用情况都不同,而且当多个业务使用同一个线程池时,可能会因为线程池使用不当导致死锁。
2023-04-22 18:43:18
3338
1
原创 dubbo学习
而与Failsafe不同的是,Failback策略会将这次调用加入内存中的失败列表中,对于这个列表中的失败调用,会在另一个线程中进行异步重试,重试如果再发生失败,则会忽略,即使重试调用成功,原来的调用方也感知不到了。Dubbo调用类别有四种,分别是同步,异步,并行以及广播调用。在特殊场景下,异步调用可提高性能,比如要远程调用A、B、C,分别用时1s,2s,3s,如果是同步的话,用时6秒,如果异步调用,同时去执行这三个接口,理想情况下用时3秒,不过前提是ABC这三个方法没有参数依赖并且没有顺序依赖。
2023-03-25 15:52:13
261
学生管理系统1.0(SpringBoot+mybatisPlus+thymeleaf)
2023-10-15
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人