分布式任务调度核心流程(xxl-job)
之前简单分析过定时任务的几种实现,但是都是单机本地的实现,现在看一下分布式的任务调度,开源的xxl-job的实现,因为其中的内容较多,这次我们就只看一下其中的任务调度部分,没有关注其中的一些分支逻辑,虽然也很重要 xxl-job的整体执行流程如下图所示 其中主要分为调度器和执行器,调度器用来根据配置信息,在特定的条件下调用执行器中的对应任务进行任务的执行 执行器配置 可以看一下xxl-job提供的spring boot为例的执行器,其中需要配置执行器的名称等信息 123456789# 设置调度中心的地址(执行时会有一些接口相关的调用交互)xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin### 执行器的名称 AppNamexxl.job.executor.appname=xxl-job-executor-sample### 可选,默认是自己当前的地址xxl.job.executor.address=### 执行器使用的IP和端口xxl.job.executor.ip=xxl.job.executor.port...
Clojure学习文档
本文主要对Clojure官网中的基础教程部分进行一下整理,对应地址https://clojure.org/guides/learn/syntax 函数 创建函数 定义一个函数,名称为 greet, 参数为name 1234(defn greet [name] (str "Hello, " name));; 或者使用如下方式(def greet (fn [name] (str "Hello, " name))) 使用 12user=> (greet "students")"Hello, students" 函数重载 12345678910(defn messenger ([] (messenger "Hello world!")) ([msg] (println msg)));; 使用user=> (messenger)Hello world!user => (messenger "Hello class!")Hello class! 可变...
SpEL使用
Spring Expression Language(SpEL) 是一个表达式语言,可以用来在运行时查询和操作对象图,比较类似于EL表达式,相比其他的表达式语言,可以更好的与Spring集成,如果使用Spring的话,也可以不用再引入额外的依赖 同时它也是可以单独引入并且使用的,这里我们主要就是看一下单独使用的情况下它能做什么以及如何使用 首先需要引入依赖包 12345<dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.3.12</version></dependency> 普通表达式求值 123456789101112ExpressionParser parser = new SpelExpressionParser();String helloWorld = parser.parseExpression(...
Spring循环依赖分析
我们在使用Spring开发的时候,可能有的时候不小心就会写出来循环依赖,但是大部分情况下都能正常运行,不需要我们特别关注,这是因为Spring进行了相关的处理等 循环依赖的处理还依赖于bean的作用范围,bean的注入方式等,这里我们就以单例模式,属性注入的方式来分析一下Spring对于循环依赖的处理 我们以如下场景为例来进行分析,有ServiceA和ServiceB两个Bean, 它们互相依赖 1234567891011@Servicepublic class ServiceA { @Resource private ServiceB serviceB;}@Servicepublic class ServiceB { @Resource private ServiceA serviceA;} 先说结论,然后再进行操作和分析,spring的创建过程大致如下 处理循环依赖的关键就是其中的注册单例Bean工厂(singletonFactories)相关功能 首次获取ServiceA这个bean时,单例工厂中不存在,...
PF4J入门使用
写代码我们都知道要抽象,要封装变化,要实现开闭原则,比如对于很多相似的功能,我们可以将通用的功能抽象出来,然后把变化的不同的地方提取出去,比如模版模式、策略模式等都是实现类似的效果 比如对于策略模式,我们通常是定义一个接口,然后有不同的实现,这种是可以的,但是如果通用流程中要扩展的点较多的话,这些不同的实现也需要管理,可以把他们合并到一个单独的包中,再进一步,我们甚至可以将包单独提取出来,支持运行时加载包实现新增功能的支持 JDK对此功能的支持就是 SPI,但是它的限制较多,也不够灵活,比如dubbo就是自己定义了一套SPI的实现,这次我们来看另一个实现,pf4j 提供一套在基本框架中定义扩展点接口,然后通过不同的插件来实现扩展点的功能,来支持对新增开放对修改关闭 这次我们就来学习一下它的使用 使用 比如我们有一套通用的流程,假设是下单流程,不同的业务线等对于下单都有一些特殊点,但是它们的基本流程是相似的,这时候我们就可以先定义好通用的流程,不同的地方预留出扩展点接口,使用 pf4j 的流程如下 先定义好扩展点接口(需要定义单独的包,因为基本应用和各个扩展点的包都依赖它) 定...
Thrift(三)-协议使用
Thrift的关键其实就是在定义好结构后,通过某种序列化方式进行网络传输交互,一般定义结构可以使用IDL的方式来描述各个字段属性等信息,这种方式可以支持跨语言的使用。对于纯Java的应用,也可以通过在类中添加注解的方式来实现,即把IDL中需要定义的信息,通过注解和注解中的信息来进行描述,同样可以达到定义结构的目的 定义好结构之后,就可以通过对应的TProtocol将数据结构进行发送和接收的序列化和反序列化即可,这次我们主要看下TProtocol中的一个实现–TBinaryProtocol 之前我们也看过thrift支持的一些结构类型,如struct、string、map、list等,具体可以看下对应枚举 12345678910111213141516public final class TType { public static final byte STOP = 0; public static final byte VOID = 1; public static final byte BOOL = 2; public stat...
Thrift(二)-处理流程分析
之前介绍过thrift使用, 但是只知道使用总是不够满足,这次我们接着之前的代码,来看下这个具体的实现和处理流程,在介绍之前先看下几个重要的接口 传输层 TTransport : 负责数据传输(大部分场景为负责网络传输) 协议层 TProtocol: 负责进行数据结构的序列化与反序列化(依赖TTransport 进行数据传输及读取) 处理层 TProcessor : 使用协议和传输接口进行具体处理处理 server初始化 再次看下Server的初始化启动代码 123456789101112// 创建传输层ServerTransportTServerTransport serverTransport = new TServerSocket(12345);// 实例化接口实现类// 构造Server参数(TProcessor, TTransport, TProtocol-默认TBinaryProtocol)UserService.Processor<UserServiceImpl> processor = new UserService.Processor<&g...
Thrift(一)-快速入门
Thrift是facebook开发的一款轻量级的跨语言的RPC实现,它为数据传输、数据序列化和应用层的处理提供了清晰的抽象和实现。它的代码生成器使用简单的定义语言来生成跨语言的代码,来构建可互操作的RPC客户端和服务端。这篇文章主要简单介绍一下thrift的使用 使用 thrift的使用可以分为如下几个步骤 使用thrift的接口描述语言(IDL)定义好数据类型和服务接口 安装thrift代码生成工具,来生成对应语言的客户端和服务端代码 服务端需要对具体的服务接口实现逻辑进行编码实现 编写初始化代码进行服务端/客户端的启动或调用 下面我们来分别具体看一下 使用IDL定义数据类型和服务接口 因为要实现跨语言的通信,那么就不能使用任何一种语言来定义数据类型和接口,所以thrift提供了IDL来定义相关的信息,其中支持的信息包括 基本类型、结构体、容器、异常、服务接口 等 基本类型 bool byte i16 (有符号的16位整型) i32 (有符号的32位整型) i64 (有符号的64位整型) double (64位浮点数) string (字符串) 因为有的语言没有无符号...
Maven生命周期与插件笔记
工作中大部分Java项目都是基于maven来进行项目的构建等工作,但是对于maven这个高频用到的工具其实了解程度还不够,下面主要是学习《Maven实战》中记录的关于生命周期与插件相关的笔记 maven生命周期与插件 maven的生命周期是从大量项目和构建工作中总结抽象出来的对所有构建过程进行的抽象和统一,这个生命周期包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有构建步骤 虽然maven抽象出了生命周期的概念,但是它并没有对相关的功能进行实现,就像它是负责定义了接口,但是具体实现是由插件来完成,这样可以很好的保证自身的轻量和扩展性 而对于maven插件,还有个插件目标的概念,就是可以认为一个插件本身是可以提供很多种功能的,一种功能就是一个插件目标,比如对于 maven-dependency-plugin 这个插件,我们通过执行mvn dependency:help可以看到它有21个插件目标,截取部分内容如下,其中就包含我们平时分析依赖使用的mvn dependency:tree(其中冒号前面是插件前缀,冒号后面是该插件的目标) 123456...
定时任务实现原理浅析
如果我们有想固定间隔时间执行的任务等,自己实现的一种方式是可以新启动一个线程,在其中sleep固定的时间后执行,但是这种方式在任务多的时候肯定是不行的。现在已经有很多现成的工具我们可以直接使用,这里主要介绍一下JDK的ScheduledThreadPoolExecutor与Netty的HashedWheelTimer,看一下它们的实现原理 ScheduledThreadPoolExecutor ScheduledThreadPoolExecutor是JDK自带的一个用于执行周期任务的线程池,用法大致如下 123456// 创建任务线程池ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);// 提交任务executor.schedule(() -> System.out.println("111"), 1, TimeUnit.SECONDS);executor.scheduleAtFixedRate(() -> System.out.println(&q...
