xxl-job源码结构
17:28:40.711 logback [main] INFO c.x.j.e.core.config.XxlJobConfig - >>>>>>>>>>> xxl-job config init.
17:28:40.720 logback [main] INFO c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job register jobhandler success, name:commandJobHandler, jobHandler:com.xxl.job.executor.service.jobhandler.CommandJobHandler@144ab54
17:28:40.721 logback [main] INFO c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job register jobhandler success, name:demoJobHandler, jobHandler:com.xxl.job.executor.service.jobhandler.DemoJobHandler@2cfa2c4f
17:28:40.721 logback [main] INFO c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job register jobhandler success, name:httpJobHandler, jobHandler:com.xxl.job.executor.service.jobhandler.HttpJobHandler@6ecab872
17:28:40.721 logback [main] INFO c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job register jobhandler success, name:shardingJobHandler, jobHandler:com.xxl.job.executor.service.jobhandler.ShardingJobHandler@48eb9836
17:28:40.740 logback [main] INFO c.x.r.r.p.XxlRpcProviderFactory - >>>>>>>>>>> xxl-rpc, provider factory add service success. serviceKey = com.xxl.job.core.biz.ExecutorBiz, serviceBean = class com.xxl.job.core.biz.impl.ExecutorBizImpl
17:28:41.019 logback [main] INFO o.s.w.s.m.m.a.RequestMappingHandlerAdapter - Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5cdec700: startup date [Thu Aug 01 17:28:39 CST 2019]; root of context hierarchy
17:28:41.066 logback [main] INFO o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
17:28:41.067 logback [main] INFO o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
17:28:41.094 logback [main] INFO o.s.w.s.h.SimpleUrlHandlerMapping - Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
17:28:41.095 logback [main] INFO o.s.w.s.h.SimpleUrlHandlerMapping - Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
17:28:41.126 logback [main] INFO o.s.w.s.h.SimpleUrlHandlerMapping - Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
17:28:41.223 logback [Thread-8] INFO com.xxl.rpc.remoting.net.Server - >>>>>>>>>>> xxl-rpc remoting server start success, nettype = com.xxl.rpc.remoting.net.impl.netty_http.server.NettyHttpServer, port = 9999
17:28:41.300 logback [main] INFO o.s.j.e.a.AnnotationMBeanExporter - Registering beans for JMX exposure on startup
17:28:41.308 logback [main] INFO o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-9002"]
17:28:41.309 logback [main] INFO o.a.tomcat.util.net.NioSelectorPool - Using a shared selector for servlet write/read
17:28:41.321 logback [main] INFO o.s.b.c.e.t.TomcatEmbeddedServletContainer - Tomcat started on port(s): 9002 (http)
@Bean(initMethod = "start", destroyMethod = "destroy")
public XxlJobSpringExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppName(appName);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
@Bean(initMethod = “start”, destroyMethod = “destroy”)此处指明bean初始化时触发start方法
public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationContextAware {
@Override
public void start() throws Exception {
//初始化作业处理器仓库
initJobHandlerRepository(applicationContext);
// refresh GlueFactory
GlueFactory.refreshInstance(1);
//调用父类XxlJobExecutor的start方法
super.start();//[4]
}
private void initJobHandlerRepository(ApplicationContext applicationContext){
if (applicationContext == null) {
return;
}
//初始化作业处理器
//获取spring通过注解注册的bean实例,并从中取得作业handler并注册
Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHandler.class);
if (serviceBeanMap!=null && serviceBeanMap.size()>0) {
for (Object serviceBean : serviceBeanMap.values()) {
if (serviceBean instanceof IJobHandler){
String name = serviceBean.getClass().getAnnotation(JobHandler.class).value();
IJobHandler handler = (IJobHandler) serviceBean;
if (loadJobHandler(name) != null) {
throw new RuntimeException("xxl-job jobhandler naming conflicts.");
}
//注册作业handler,该方法继承自XxlJobExecutor
registJobHandler(name, handler);//[3]
}
}
}
}
}
XxlJobExecutor.java
//存储jobhandler
private static ConcurrentMap<String, IJobHandler> jobHandlerRepository
= new ConcurrentHashMap<String, IJobHandler>();
//注册handler,即把jobhandler实例存储
public static IJobHandler registJobHandler(String name, IJobHandler jobHandler){
logger.info(">>>>>>>>>>> xxl-job register jobhandler success, name:{}, jobHandler:{}",
name, jobHandler);
return jobHandlerRepository.put(name, jobHandler);
}
XxlJobExecutor.java
public void start() throws Exception {
//日志文件路径
XxlJobFileAppender.initLogPath(logPath);
//初始化RPC调用者,调度中心客户端,adminAddresses可能为多个地址即多个调度中心机器。
initAdminBizList(adminAddresses, accessToken);//[5]
//启动日志文件清理线程
JobLogFileCleanThread.getInstance().start(logRetentionDays);
//初始化触发器回调线程
TriggerCallbackThread.getInstance().start();
//初始化RPC提供服务者
port = port>0?port: NetUtil.findAvailablePort(9999);
ip = (ip!=null&&ip.trim().length()>0)?ip: IpUtil.getIp();
initRpcProvider(ip, port, appName, accessToken);//[3]
}
//XxlJobExecutor.java
private static List<AdminBiz> adminBizList;
private static Serializer serializer;
private void initAdminBizList(String adminAddresses, String accessToken) throws Exception {
serializer = Serializer.SerializeEnum.HESSIAN.getSerializer();
if (adminAddresses!=null && adminAddresses.trim().length()>0) {
for (String address: adminAddresses.trim().split(",")) {
if (address!=null && address.trim().length()>0) {
String addressUrl = address.concat(AdminBiz.MAPPING);
//new XxlRpcReferenceBean(...).getObject()
//动态代理,获取AdminBiz接口的实例对象
AdminBiz adminBiz = (AdminBiz) new XxlRpcReferenceBean(
NetEnum.NETTY_HTTP,
serializer,
CallType.SYNC,
LoadBalance.ROUND,
AdminBiz.class,
null,
3000,
addressUrl,
accessToken,
null,
null
).getObject();
if (adminBizList == null) {
adminBizList = new ArrayList<AdminBiz>();
}
adminBizList.add(adminBiz);
}
}
}
}
package com.xxl.rpc.remoting.invoker.reference;
XxlRpcReferenceBean.java
//动态代理,所有动态代理类的方法调用,都会交由InvocationHandler接口实现类里的invoke()方法去处理,
invoke()方法由rpc包的方法处理并放回对象
public Object getObject() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{this.iface},
new InvocationHandler() {...});
}
//返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
参考链接:Java的动态代理(dynamic proxy)
XxlJobExecutor.java
private void initRpcProvider(String ip, int port, String appName, String accessToken) throws Exception {
// init, provider factory
String address = IpUtil.getIpPort(ip, port);
Map<String, String> serviceRegistryParam = new HashMap<String, String>();
serviceRegistryParam.put("appName", appName);
serviceRegistryParam.put("address", address);
xxlRpcProviderFactory = new XxlRpcProviderFactory();
xxlRpcProviderFactory.initConfig(NetEnum.NETTY_HTTP, Serializer.SerializeEnum.HESSIAN.getSerializer(), ip, port, accessToken, ExecutorServiceRegistry.class, serviceRegistryParam);
// add services
xxlRpcProviderFactory.addService(ExecutorBiz.class.getName(), null, new ExecutorBizImpl());
// start
xxlRpcProviderFactory.start();
}
xxlRpcProviderFactory.java
public void addService(String iface, String version, Object serviceBean) {
String serviceKey = makeServiceKey(iface, version);
this.serviceData.put(serviceKey, serviceBean);
logger.info(">>>>>>>>>>> xxl-rpc, provider factory add service success. serviceKey = {}, serviceBean = {}", serviceKey, serviceBean.getClass());
}
xxlRpcProviderFactory.java
public void start() throws Exception {
this.serviceAddress = IpUtil.getIpPort(this.ip, this.port);
//生成Server实例 NettyHttpServer
this.server = (Server)this.netType.serverClass.newInstance();
//设置NettyHttpServer开始的回调服务
this.server.setStartedCallback(new BaseCallback() {
public void run() throws Exception {
if (XxlRpcProviderFactory.this.serviceRegistryClass != null) {
XxlRpcProviderFactory.this.serviceRegistry =
(ServiceRegistry)XxlRpcProviderFactory.this.serviceRegistryClass.newInstance();
XxlRpcProviderFactory.this.serviceRegistry.start(XxlRpcProviderFactory.this.serviceRegistryParam);
if (XxlRpcProviderFactory.this.serviceData.size() > 0) {
XxlRpcProviderFactory.this.serviceRegistry.registry(XxlRpcProviderFactory.this.serviceData.keySet(),
XxlRpcProviderFactory.this.serviceAddress);
}
}
}
});
//设置NettyHttpServer停止事件的回调服务
this.server.setStopedCallback(new BaseCallback() {
public void run() {
if (XxlRpcProviderFactory.this.serviceRegistry != null) {
if (XxlRpcProviderFactory.this.serviceData.size() > 0) {
XxlRpcProviderFactory.this.serviceRegistry.remove(XxlRpcProviderFactory.this.serviceData.keySet(), XxlRpcProviderFactory.this.serviceAddress);
}
XxlRpcProviderFactory.this.serviceRegistry.stop();
XxlRpcProviderFactory.this.serviceRegistry = null;
}
}
});
//NettyHttpServer
this.server.start(this);
}
com.xxl.rpc.remoting.net.Server - >>>>>>>>>>> xxl-rpc remoting server start success, nettype =com.xxl.rpc.remoting.net.impl.netty_http.server.NettyHttpServer, port = 9999
远程连接服务器启动成功,NettyHttpServer服务器端口为9999
执行器实际上是一个内嵌的Server,默认端口9999(配置项:xxl.job.executor.port)。
上述xxlRpcProviderFactory.start()中调用了静态类ExecutorServiceRegistry的start()方法
public static class ExecutorServiceRegistry extends ServiceRegistry {
@Override
public void start(Map<String, String> param) {
//启动执行器注册线程
ExecutorRegistryThread.getInstance().start(param.get("appName"), param.get("address"));
}
//...
}
ExecutorRegistryThread.java
public void start(final String appName, final String address){
// valid
if (appName==null || appName.trim().length()==0) {
logger.warn(">>>>>>>>>>> xxl-job, executor registry config fail, appName is null.");
return;
}
if (XxlJobExecutor.getAdminBizList() == null) {
logger.warn(">>>>>>>>>>> xxl-job, executor registry config fail, adminAddresses is null.");
return;
}
registryThread = new Thread(new Runnable() {
@Override
public void run() {
// 注册
while (!toStop) {
try {
RegistryParam registryParam =
new RegistryParam(RegistryConfig.RegistType.EXECUTOR.name(), appName, address);
for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
try {
//注册 adminBiz.registry(registryParam)
ReturnT<String> registryResult = adminBiz.registry(registryParam);
if (registryResult!=null && ReturnT.SUCCESS_CODE == registryResult.getCode()) {
registryResult = ReturnT.SUCCESS;
logger.info(">>>>>>>>>>> xxl-job registry success, registryParam:{}, registryResult:{}", new Object[]{registryParam, registryResult});
break;
} else {
logger.info(">>>>>>>>>>> xxl-job registry fail, registryParam:{}, registryResult:{}", new Object[]{registryParam, registryResult});
}
} catch (Exception e) {
logger.info(">>>>>>>>>>> xxl-job registry error, registryParam:{}", registryParam, e);
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
try {
TimeUnit.SECONDS.sleep(RegistryConfig.BEAT_TIMEOUT);
} catch (InterruptedException e) {
logger.warn(">>>>>>>>>>> xxl-job, executor registry thread interrupted, error msg:{}", e.getMessage());
}
}
try {
RegistryParam registryParam = new RegistryParam(RegistryConfig.RegistType.EXECUTOR.name(), appName, address);
for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
try {
// 注册移除
ReturnT<String> registryResult = adminBiz.registryRemove(registryParam);
if (registryResult!=null && ReturnT.SUCCESS_CODE == registryResult.getCode()) {
registryResult = ReturnT.SUCCESS;
logger.info(">>>>>>>>>>> xxl-job registry-remove success, registryParam:{}, registryResult:{}", new Object[]{registryParam, registryResult});
break;
} else {
logger.info(">>>>>>>>>>> xxl-job registry-remove fail, registryParam:{}, registryResult:{}", new Object[]{registryParam, registryResult});
}
} catch (Exception e) {
logger.info(">>>>>>>>>>> xxl-job registry-remove error, registryParam:{}", registryParam, e);
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
logger.info(">>>>>>>>>>> xxl-job, executor registry thread destory.");
}
});
registryThread.setDaemon(true);
registryThread.start();
}
package com.xxl.job.admin.service.impl;
AdminBizImpl.java
@Override
public ReturnT<String> registry(RegistryParam registryParam) {
//registryUpdate
int ret = xxlJobRegistryDao.registryUpdate(registryParam.getRegistGroup(),
registryParam.getRegistryKey(),
registryParam.getRegistryValue());
if (ret < 1) {
//registrySave
xxlJobRegistryDao.registrySave(registryParam.getRegistGroup(),
registryParam.getRegistryKey(),
registryParam.getRegistryValue());
}
return ReturnT.SUCCESS;
}
@Override
public ReturnT<String> registryRemove(RegistryParam registryParam) {
//registryDelete
xxlJobRegistryDao.registryDelete(registryParam.getRegistGroup(),
registryParam.getRegistryKey(),
registryParam.getRegistryValue());
return ReturnT.SUCCESS;
}