elastic-job源码(1)- job自动装配
<dependency>
<groupId>org.apache.shardingsphere.elasticjob</groupId>
<artifactId>elasticjob-lite-spring-boot-starter</artifactId>
<version>${latest.version}</version>
</dependency>
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.apache.shardingsphere.elasticjob.lite.spring.boot.job.ElasticJobLiteAutoConfiguration
/**
* ElasticJob-Lite auto configuration.
*/
@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter(DataSourceAutoConfiguration.class) /**
* elastic job 开关
* elasticjob.enabled.ture默认为true
*/
@ConditionalOnProperty(name = "elasticjob.enabled", havingValue = "true", matchIfMissing = true) /**
* 导入
* ElasticJobRegistryCenterConfiguration.class 注册中心配置
* ElasticJobTracingConfiguration.class job事件追踪配置
* ElasticJobSnapshotServiceConfiguration.class 快照配置
*/
@Import({ElasticJobRegistryCenterConfiguration.class, ElasticJobTracingConfiguration.class, ElasticJobSnapshotServiceConfiguration.class}) /**
* job相关配置信息
*/
@EnableConfigurationProperties(ElasticJobProperties.class)
public class ElasticJobLiteAutoConfiguration { @Configuration(proxyBeanMethods = false)
/**
* ElasticJobBootstrapConfiguration.class 创建job beans 注入spring容器
* ScheduleJobBootstrapStartupRunner.class 执行类型为ScheduleJobBootstrap.class 的job开始运行
*/
@Import({ElasticJobBootstrapConfiguration.class, ScheduleJobBootstrapStartupRunner.class})
protected static class ElasticJobConfiguration {
}
}
public void init() {
log.debug("Elastic job: zookeeper registry center init, server lists is: {}.", zkConfig.getServerLists());
CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()
//设置zookeeper 服务器地址
.connectString(zkConfig.getServerLists())
//设置重试机制
.retryPolicy(new ExponentialBackoffRetry(zkConfig.getBaseSleepTimeMilliseconds(), zkConfig.getMaxRetries(), zkConfig.getMaxSleepTimeMilliseconds()))
//设置命名空间,zookeeper节点名称
.namespace(zkConfig.getNamespace());
//设置session超时时间
if (0 != zkConfig.getSessionTimeoutMilliseconds()) {
builder.sessionTimeoutMs(zkConfig.getSessionTimeoutMilliseconds());
}
//设置连接超时时间
if (0 != zkConfig.getConnectionTimeoutMilliseconds()) {
builder.connectionTimeoutMs(zkConfig.getConnectionTimeoutMilliseconds());
}
if (!Strings.isNullOrEmpty(zkConfig.getDigest())) {
builder.authorization("digest", zkConfig.getDigest().getBytes(StandardCharsets.UTF_8))
.aclProvider(new ACLProvider() { @Override
public List<ACL> getDefaultAcl() {
return ZooDefs.Ids.CREATOR_ALL_ACL;
} @Override
public List<ACL> getAclForPath(final String path) {
return ZooDefs.Ids.CREATOR_ALL_ACL;
}
});
}
client = builder.build();
//zookeeper 客户端开始启动
client.start();
try {
//zookeeper 客户端一直连接
if (!client.blockUntilConnected(zkConfig.getMaxSleepTimeMilliseconds() * zkConfig.getMaxRetries(), TimeUnit.MILLISECONDS)) {
client.close();
throw new KeeperException.OperationTimeoutException();
}
//CHECKSTYLE:OFF
} catch (final Exception ex) {
//CHECKSTYLE:ON
RegExceptionHandler.handleException(ex);
}
}
第二件事: 配置事件追踪数据库,用于保存job运行记录
ElasticJobTracingConfiguration.java
/**
* Create a bean of tracing DataSource.
*
* @param tracingProperties tracing Properties
* @return tracing DataSource
*/
@Bean("tracingDataSource")
//spring中注入bean name 为tracingDataSource的job数据库连接信息
public DataSource tracingDataSource(final TracingProperties tracingProperties) {
//获取elastic-job 数据库配置
DataSourceProperties dataSource = tracingProperties.getDataSource();
if (dataSource == null) {
return null;
}
HikariDataSource tracingDataSource = new HikariDataSource();
tracingDataSource.setJdbcUrl(dataSource.getUrl());
BeanUtils.copyProperties(dataSource, tracingDataSource);
return tracingDataSource;
} /**
* Create a bean of tracing configuration.
*
* @param dataSource required by constructor
* @param tracingDataSource tracing ataSource
* @return a bean of tracing configuration
*/
@Bean
@ConditionalOnBean(DataSource.class)
@ConditionalOnProperty(name = "elasticjob.tracing.type", havingValue = "RDB")
public TracingConfiguration<DataSource> tracingConfiguration(final DataSource dataSource, @Nullable final DataSource tracingDataSource) {
/**
* dataSource 是业务数据库
* tracingDataSource 是job数据库
* 当配置elasticjob.tracing.type = RDB时,如果单独配置job数据库是,默认使用job数据库作为job运行轨迹的记录
* 但这边同时业务数据库和job追踪数据库同时注入是,mybatis-plus 结合@Table 使用的时候,很有可能找不到正确对应的数据源
*/
DataSource ds = tracingDataSource;
if (ds == null) {
ds = dataSource;
}
return new TracingConfiguration<>("RDB", ds);
}
通过elasticjob.tracing.type=RDB的配置开启事件追踪功能,这边job的事件追踪数据源可以和业务数据源配置不一样。
第三件事:解析所有job配置文件
ElasticJobBootstrapConfiguration.class
public void createJobBootstrapBeans() {
//获取job配置
ElasticJobProperties elasticJobProperties = applicationContext.getBean(ElasticJobProperties.class);
//获取单利注册对象
SingletonBeanRegistry singletonBeanRegistry = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
//获取注入zookeeper 客户端
CoordinatorRegistryCenter registryCenter = applicationContext.getBean(CoordinatorRegistryCenter.class);
//获取job事件追踪
TracingConfiguration<?> tracingConfig = getTracingConfiguration();
//构造JobBootstraps
constructJobBootstraps(elasticJobProperties, singletonBeanRegistry, registryCenter, tracingConfig);
}
重要的是constructJobBootstraps 这个方法,来看下
private void constructJobBootstraps(final ElasticJobProperties elasticJobProperties, final SingletonBeanRegistry singletonBeanRegistry,
final CoordinatorRegistryCenter registryCenter, final TracingConfiguration<?> tracingConfig) {
//遍历配置的每一个job
for (Map.Entry<String, ElasticJobConfigurationProperties> entry : elasticJobProperties.getJobs().entrySet()) {
ElasticJobConfigurationProperties jobConfigurationProperties = entry.getValue();
//校验 job class 和 type 都为空抛异常
Preconditions.checkArgument(null != jobConfigurationProperties.getElasticJobClass()
|| !Strings.isNullOrEmpty(jobConfigurationProperties.getElasticJobType()),
"Please specific [elasticJobClass] or [elasticJobType] under job configuration.");
//校验 job class 和 type 都有 报相互排斥
Preconditions.checkArgument(null == jobConfigurationProperties.getElasticJobClass()
|| Strings.isNullOrEmpty(jobConfigurationProperties.getElasticJobType()),
"[elasticJobClass] and [elasticJobType] are mutually exclusive."); if (null != jobConfigurationProperties.getElasticJobClass()) {
//通过class 注入job
registerClassedJob(entry.getKey(), entry.getValue().getJobBootstrapBeanName(), singletonBeanRegistry, registryCenter, tracingConfig, jobConfigurationProperties);
} else if (!Strings.isNullOrEmpty(jobConfigurationProperties.getElasticJobType())) {
//通过type 注入job
registerTypedJob(entry.getKey(), entry.getValue().getJobBootstrapBeanName(), singletonBeanRegistry, registryCenter, tracingConfig, jobConfigurationProperties);
}
}
}
private void registerClassedJob(final String jobName, final String jobBootstrapBeanName, final SingletonBeanRegistry singletonBeanRegistry, final CoordinatorRegistryCenter registryCenter,
final TracingConfiguration<?> tracingConfig, final ElasticJobConfigurationProperties jobConfigurationProperties) {
//获取job配置
JobConfiguration jobConfig = jobConfigurationProperties.toJobConfiguration(jobName);
//配置job事件追踪
jobExtraConfigurations(jobConfig, tracingConfig);
//获取job类型
ElasticJob elasticJob = applicationContext.getBean(jobConfigurationProperties.getElasticJobClass());
//没有配置cron表达式 就初始化为OneOffJobBootstrap对象,一次性任务
if (Strings.isNullOrEmpty(jobConfig.getCron())) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(jobBootstrapBeanName), "The property [jobBootstrapBeanName] is required for One-off job.");
singletonBeanRegistry.registerSingleton(jobBootstrapBeanName, new OneOffJobBootstrap(registryCenter, elasticJob, jobConfig));
} else {
//有配置cron表达式 就初始化为ScheduleJobBootstrap对象,定时任务
//设置bean name
String beanName = !Strings.isNullOrEmpty(jobBootstrapBeanName) ? jobBootstrapBeanName : jobConfig.getJobName() + "ScheduleJobBootstrap";
//注入ScheduleJobBootstrap对象为单利对象
singletonBeanRegistry.registerSingleton(beanName, new ScheduleJobBootstrap(registryCenter, elasticJob, jobConfig));
}
}
public JobScheduler(final CoordinatorRegistryCenter regCenter, final ElasticJob elasticJob, final JobConfiguration jobConfig) {
Preconditions.checkArgument(null != elasticJob, "Elastic job cannot be null.");
this.regCenter = regCenter;
//获取job监听器
Collection<ElasticJobListener> jobListeners = getElasticJobListeners(jobConfig);
// 集成所有操作zookeeper 节点的services,job 监听器
setUpFacade = new SetUpFacade(regCenter, jobConfig.getJobName(), jobListeners);
//获取当前job名称
String jobClassName = JobClassNameProviderFactory.getProvider().getJobClassName(elasticJob);
//zookeeper节点 {namespace}/{jobclassname}/config 放置job配置信息
this.jobConfig = setUpFacade.setUpJobConfiguration(jobClassName, jobConfig);
// 集成所有操作zookeeper 节点的services
schedulerFacade = new SchedulerFacade(regCenter, jobConfig.getJobName());
jobFacade = new LiteJobFacade(regCenter, jobConfig.getJobName(), jobListeners, findTracingConfiguration().orElse(null));
//检验job配置
validateJobProperties();
//定义job执行器
jobExecutor = new ElasticJobExecutor(elasticJob, this.jobConfig, jobFacade);
//监听器里注入GuaranteeService
setGuaranteeServiceForElasticJobListeners(regCenter, jobListeners);
//创建定时任务,开始执行
jobScheduleController = createJobScheduleController();
}
看下createJobScheduleController
private JobScheduleController createJobScheduleController() {
JobScheduleController result = new JobScheduleController(createScheduler(), createJobDetail(), getJobConfig().getJobName());
//注册job
JobRegistry.getInstance().registerJob(getJobConfig().getJobName(), result);
//注册器开始运行
registerStartUpInfo();
return result;
}
看下registerStartUpInfo方法
public void registerStartUpInfo(final boolean enabled) {
//开始所有的监听器
listenerManager.startAllListeners();
//选举leader /{namespace}/leader/election/instance 放置选举出来的服务器
leaderService.electLeader();
//{namespace}/{ipservers} 设置enable处理
serverService.persistOnline(enabled);
//临时节点 /{namespave}/instances 放置运行服务实例信息
instanceService.persistOnline();
//开启一个异步服务
if (!reconcileService.isRunning()) {
reconcileService.startAsync();
}
}
@Override
public void run(final String... args) {
log.info("Starting ElasticJob Bootstrap.");
applicationContext.getBeansOfType(ScheduleJobBootstrap.class).values().forEach(ScheduleJobBootstrap::schedule);
log.info("ElasticJob Bootstrap started.");
}
elastic-job源码(1)- job自动装配的更多相关文章
- SpringBoot SpringApplication底层源码分析与自动装配
目录 抛出问题 @SpringBootApplication注解剖析 SpringApplication类剖析 第一步:配置SpringBoot Bean来源 第二步 :自动推断SpringBoot的 ...
- Spring源码解析-autowiring自动装配的实现
IoC容器提供了自动依赖装配的方式,为应用IoC容器提供很大的方便.在自动配置中,不需要显式的去指定Bean属性,只需要配置autowiring属性,IoC容器会根据这个属性配置,使用反射的方式查找属 ...
- Spring Ioc源码分析系列--自动注入循环依赖的处理
Spring Ioc源码分析系列--自动注入循环依赖的处理 前言 前面的文章Spring Ioc源码分析系列--Bean实例化过程(二)在讲解到Spring创建bean出现循环依赖的时候并没有深入去分 ...
- 【源码解析】自动配置的这些细节不知道,别说你会 springboot
spring-boot 相对于 spring,很重要的一个特点就是自动配置,使约定大于配置思想成功落地.xxx-spring-boot-starter 一系列引导器能够开箱即用,或者只需要很少的配置( ...
- Springboot 源码解析-自定装配
面试官经常会问你知道springboot的自定装配吗?它是怎么实现的吗?今天我们就来通过源码一起分析下它吧.首先我们先搭建一个springboot的简单项目,找到启动类, 然后通过这个注解我们进入到@ ...
- [微信跳转浏览器]微信跳转外部浏览器下载APP源码,可以实现自动跳转外部浏览器打开链接
基于微信后端开发了一款微信推广助手,使用了本程序生成的链接,用户在微信任意环境下点击链接或者扫描二维码,可以实现直接跳转手机默认浏览器并打开指定网页. 我们开发的此款跳转产品,应用范围广泛.除了下载A ...
- Maven引入依赖后自动下载并关联源码(Source)
好多用 Maven 的时候会遇到这样一个棘手的问题: 就是添加依赖后由于没有下载并关联源码,导致自动提示无法出现正确的方法名,而且不安装反编译器的情况下不能进入方法内部看具体实现 . 其实 eclip ...
- NhibernateProfiler-写个自动破解工具(源码)
04 2013 档案 [屌丝的逆袭系列]是个人都能破解之终结NhibernateProfiler-写个自动破解工具(源码) 摘要: 破解思路分析及手动破解 增加“附加到进程”功能--功能介绍增加“ ...
- C++、VC++、MFC网页自动注册、登陆、发帖、留言,QQ注册、QQ申请器源码、注册邮箱源码、自动发帖源码
C++.VC++.MFC网页自动注册.登陆.发帖.留言,QQ注册.QQ申请器源码.注册邮箱源码.自动发帖源码 参考资料: 自动登录yahoo邮箱http://blog.csdn.net/suisu ...
- 设置eclipse的Maven插件引入依赖jar包后自动下载并关联相应的源码(转)
好多用 Maven 的时候会遇到这样一个棘手的问题: 就是添加依赖后由于没有下载并关联源码,导致自动提示无法出现正确的方法名,而且不安装反编译器的情况下不能进入方法内部看具体实现 . 其实 eclip ...
随机推荐
- 用反证法说明List<Object>和List<String>不存在子父类关系可行吗?
看宋红康老师的Java基础视频讲解,视频中用反证法证明List
- 【Linux】虚拟机CentOS 7 磁盘扩容
[Linux]虚拟机CentOS 7 磁盘扩容 在有些时候,自己或者公司开的虚拟机的磁盘在一开始的时候没规划好,或者有磁盘扩容的需求(其实在系统日常运维的时候这个需求时常出现),那么这个时候又该怎么处 ...
- bbswitch与bumblebee配合使用
!建议查阅并使用archwiki的bumblebee方案 ! 安装NONFREE驱动 1.在终端中输入以下命令来检查已安装的驱动版本(我这次装manjaro是hybird440) inxi -G 2. ...
- 京东-Docker
关于 Docker 版本的<使用与更新>教程修订日期:2021年 3 月 14 日ㅤ 一.基础使用教程1. 进入与退出容器:docker exec -it jd /bin/bash注意:e ...
- unity更改c#文件名的小tip
今天偶然知道了一个在Unity中更改代码文件名的小技巧--最好先在Unity的project视图里找到文件,改完后再去visual studio等代码编辑器里改里面的类名. 以前都没注意,想起来要改某 ...
- 总结Unity查找物体的几种方法
Unity中经常需要查找对象,对应的API也有好几种,各自有不同的适用场合. 1. GameObject.Find 通过名字或路径查找游戏对象. GameObject.Find("GameO ...
- sqlserver数据库连接数相关问题
sql语句监控连接数量 SELECT ec.client_net_address , es.[program_name] , es.[host_name] , es.login_name , COUN ...
- LeetCode224 基本计算器
idea:刚开始是打算分类讨论,建立了数字栈和字符栈,按照传入字符当时两个栈的基本情况分类,结果讨论完之后分类太麻烦,导致分析完了之后漏洞不少.我觉得这道题难点在于括号和负号的处理,一开始将导致计算机 ...
- SDK测试标准
测试分类 具体测试项 测试内容 测试方法 文档测试 接口清单 接口清单是否完整,正确,包含提供给开发者的协议所有字段的定义和解释 人工检查 更新说明 要说明新增,删除的接口定义 Demo示例 显示如何 ...
- mxnet的broadcast_power() 注释错误
用relationnet时,发现broadcast_power()的源码中的注释如下: 官方文档中的注释如下: 怎么算都算不出它这个结果... 自己用mxnet实验了一把,发现是注释错了,代码如下: