• xxl-job整合到微服务



    前言

    公司项目改造为微服务之后,单个项目可能起多个实例,决定采用xxl-job进行管理定时任务。原生的xxl-job不能满足项目需要,将xxl-job作为微服务引入项目。


    一、xxl-job引入

    1. 下载源码xxl-job源码
    2. 下载下来的开源包有三个目录:xxl-job-admin、xxl-job-core和xxl-job-executor-samples
      xxl-job-admin是分布式任务平台的服务端兼管理台,xxl-job-core是公共依赖包,xxl-job-executor-samples是例子。
    3. 将xxl-job-admin与xxl-job-core集成到我们的微服务中。

    二、xxl-job改造为微服务

    1.修改配置文件

    数据库地址写到了nacos里,从nacos里取

    ### actuator
    management:
      health:
        mail:
          enabled: false
      server:
        base-path: /actuator
    
    ### web
    server:
      port: 8088
      servlet:
        context-path: /xxl-job-admin
    ### xxl-job, datasource
    spring:
      datasource:                          
        url: ${blade.datasource.xxl.url}
        username: ${blade.datasource.xxl.username}
        password: ${blade.datasource.xxl.password}
        driver-class-name: com.mysql.cj.jdbc.Driver
        type: com.zaxxer.hikari.HikariDataSource
        hikari:
          minimum-idle: 10
          maximum-pool-size: 30
          auto-commit: true
          idle-timeout: 30000
          pool-name: HikariCP
          max-lifetime: 900000
          connection-timeout: 10000
          connection-test-query: SELECT 1
          validation-timeout: 1000
      mvc:
        servlet:
          load-on-startup: 0
        static-path-pattern: /static/**
      ### freemarker
      freemarker:
        templateLoaderPath: classpath:/templates/
        suffix: .ftl
        charset: UTF-8
        request-context-attribute: request
        settings.number_format: 0.##########
      mail:
        host: smtp.qq.com
        port: 25
        username: xxxxxxxxxxxx
        from: xxxxxxxxxxxxx
        password: xxxxxxxxxx
        properties:
          mail:
            smtp:
              auth: true
              starttls:
                enable: true
                required: true
              socketFactory:
                class: javax.net.ssl.SSLSocketFactory
      web:
        resources:
          static-locations: classpath:/static/
    
    # Mybatis-plus
    mybatis-plus:
      mapper-locations: classpath*:mybatis-mapper/*.xml
    
    ### xxl-job, access token
    xxl:
      job:
        accessToken: default_token
        i18n: zh_CN
        triggerpool:
          fast:
            max: 200
          slow:
            max: 100
        logretentiondays: 30
    
    minio:
      enabled: false
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    2.修改启动器

    @EnableDiscoveryClient
    @MapperScan({"com.xxl.job.admin.dao"})
    @EnableAutoConfiguration(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
    @BladeCloudApplication
    public class XxlJobAdminApplication {
    
    	public static void main(String[] args) {
    		BladeApplication.run(AppConstant.APPLICATION_XXL_NAME, XxlJobAdminApplication.class, args);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.修改pom

            <dependency>
                <groupId>com.eastsoftgroupId>
                <artifactId>blade-commonartifactId>
                <version>${eastsoft.common.version}-SNAPSHOTversion>
            dependency>
            <dependency>
                <groupId>org.springbladegroupId>
                <artifactId>blade-core-cloudartifactId>
                <version>${blade.tool.version}version>
            dependency>
            <dependency>
                <groupId>org.springbladegroupId>
                <artifactId>blade-core-secureartifactId>
                <version>${blade.tool.version}version>
            dependency>
            <dependency>
                <groupId>org.springbladegroupId>
                <artifactId>blade-core-socialartifactId>
                <version>${blade.tool.version}version>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    三、xxl-job增加feign接口

    1.xxl-job-core修改

    (1)增加feign接口,fallback没列出来

    这里因为xxl-job-admin设置了context-path,需要在@FeignClient中增加path

    package com.xxl.job.core.feign;
    
    import com.eastsoft.common.constant.AppConstant;
    import com.xxl.job.core.biz.model.ReturnT;
    import com.xxl.job.core.vo.XxlJobInfoVo;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import java.util.List;
    import java.util.Map;
    
    /**
     * xxlJobInfo Feign实现类
     *
     * @author run
     */
    @FeignClient(
    	value = AppConstant.APPLICATION_XXL_NAME,
    	fallback = IJobInfoClientFallback.class,
    	path = "xxl-job-admin"
    )
    public interface IJobInfoClient {
    
    	String API_PREFIX = "/client";
    
    	@PostMapping(API_PREFIX + "/addXxlJob")
    	ReturnT<String> addXxlJob(
    		@RequestBody XxlJobInfoVo xxlJobInfoVo
    	);
    
    	@PostMapping(API_PREFIX + "/updateXxlJob")
    	ReturnT<String> updateXxlJob(
    		@RequestBody XxlJobInfoVo xxlJobInfoVo
    	);
    
    	@GetMapping(API_PREFIX + "/removeXxlJob")
    	ReturnT<String> removeXxlJob(
    		@RequestParam("id") int id
    	);
    
    	@GetMapping(API_PREFIX + "/stopXxlJob")
    	ReturnT<String> stopXxlJob(
    		@RequestParam("id") int id
    	);
    
    	@GetMapping(API_PREFIX + "/startXxlJob")
    	ReturnT<String> startXxlJob(
    		@RequestParam("id") int id
    	);
    
    	@GetMapping(API_PREFIX + "/triggerXxlJob")
    	ReturnT<String> triggerXxlJob(
    		@RequestParam("id") int id,
    		@RequestParam("executorParam") String executorParam,
    		@RequestParam("addressList") String addressList
    	);
    
    	@GetMapping(API_PREFIX + "/nextTriggerTimeXxlJob")
    	ReturnT<List<String>> nextTriggerTimeXxlJob(
    		@RequestParam("scheduleType") String scheduleType,
    		@RequestParam("scheduleConf") String scheduleConf
    	);
    
    	@PostMapping(API_PREFIX + "/getXxlJobPageList")
    	Map<String, Object> getXxlJobPageList(
    		@RequestParam(required = false, defaultValue = "0") int start,
    		@RequestParam(required = false, defaultValue = "10") int length,
    		@RequestParam("jobGroup") int jobGroup,
    		@RequestParam("triggerStatus") int triggerStatus,
    		@RequestParam("jobDesc") String jobDesc,
    		@RequestParam("executorHandler") String executorHandler,
    		@RequestParam("author") String author
    	);
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    (2)增加一个xxlJobInfoVo,用来对应xxl-jbo-admin中的xxlJobInfo
    package com.xxl.job.core.vo;
    
    import lombok.Data;
    
    import java.util.Date;
    
    /**
     * xxl-job info
     *
     * @author xuxueli  2016-1-12 18:25:49
     */
    @Data
    public class XxlJobInfoVo {
    
    	private int id;				// 主键ID
    
    	private int jobGroup;		// 执行器主键ID
    	private String jobDesc;
    
    	private Date addTime;
    	private Date updateTime;
    
    	private String author;		// 负责人
    	private String alarmEmail;	// 报警邮件
    
    	private String scheduleType;			// 调度类型
    	private String scheduleConf;			// 调度配置,值含义取决于调度类型
    	private String misfireStrategy;			// 调度过期策略
    
    	private String executorRouteStrategy;	// 执行器路由策略
    	private String executorHandler;		    // 执行器,任务Handler名称
    	private String executorParam;		    // 执行器,任务参数
    	private String executorBlockStrategy;	// 阻塞处理策略
    	private int executorTimeout;     		// 任务执行超时时间,单位秒
    	private int executorFailRetryCount;		// 失败重试次数
    
    	private String glueType;		// GLUE类型	#com.xxl.job.core.glue.GlueTypeEnum
    	private String glueSource;		// GLUE源代码
    	private String glueRemark;		// GLUE备注
    	private Date glueUpdatetime;	// GLUE更新时间
    
    	private String childJobId;		// 子任务ID,多个逗号分隔
    
    	private int triggerStatus;		// 调度状态:0-停止,1-运行
    	private long triggerLastTime;	// 上次调度时间
    	private long triggerNextTime;	// 下次调度时间
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    (3)修改pom
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-openfeign-coreartifactId>
            dependency>
            <dependency>
                <groupId>com.eastsoftgroupId>
                <artifactId>blade-commonartifactId>
                <version>${eastsoft.common.version}-SNAPSHOTversion>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    (4)deploy到私服

    xxl-job-admin将xxl-job-core作为jar包引用,其它需要使用xxl-job的服务只需要引用jar包

    2.xxl-job-admin修改

    (1)启动器增加注解
    @EnableFeignClients({"com.xxl"})
    
    • 1
    (2)实现feign接口
    package com.xxl.job.admin.feign;
    
    /**
     * @title: JobInfoClient
     * @Description []
     * @Author lhz
     * @Date: 2022/8/31 0031 09:44
     * @Version 1.0
     */
    
    import com.xxl.job.admin.controller.annotation.PermissionLimit;
    import com.xxl.job.admin.core.model.XxlJobInfo;
    import com.xxl.job.admin.core.thread.JobScheduleHelper;
    import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
    import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
    import com.xxl.job.admin.core.util.I18nUtil;
    import com.xxl.job.admin.service.XxlJobService;
    import com.xxl.job.core.biz.model.ReturnT;
    import com.xxl.job.core.feign.IJobInfoClient;
    import com.xxl.job.core.util.DateUtil;
    import com.xxl.job.core.vo.XxlJobInfoVo;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.annotation.Resource;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    
    
    /**
     * AlarmConfigService Feign实现类
     *
     * @author run
     */
    @RestController
    public class JobInfoClient implements IJobInfoClient {
    
    	@Resource
    	private XxlJobService xxlJobService;
    
    	@Override
    	public ReturnT<String> addXxlJob(@RequestBody XxlJobInfoVo xxlJobInfoVo) {
    		return xxlJobService.add(toEntity(xxlJobInfoVo));
    	}
    
    	@Override
    	public ReturnT<String> updateXxlJob(XxlJobInfoVo xxlJobInfoVo) {
    		return xxlJobService.update(toEntity(xxlJobInfoVo));
    	}
    
    	@Override
    	public ReturnT<String> removeXxlJob(int id) {
    		return xxlJobService.remove(id);
    	}
    
    	@Override
    	public ReturnT<String> stopXxlJob(int id) {
    		return xxlJobService.stop(id);
    	}
    
    	@Override
    	public ReturnT<String> startXxlJob(int id) {
    		return xxlJobService.start(id);
    	}
    
    	@Override
    	public ReturnT<String> triggerXxlJob(int id, String executorParam, String addressList) {
    		if (executorParam == null) {
    			executorParam = "";
    		}
    
    		JobTriggerPoolHelper.trigger(id, TriggerTypeEnum.MANUAL, -1, null, executorParam, addressList);
    		return ReturnT.SUCCESS;
    	}
    
    	@Override
    	public ReturnT<List<String>> nextTriggerTimeXxlJob(String scheduleType, String scheduleConf) {
    		XxlJobInfo paramXxlJobInfo = new XxlJobInfo();
    		paramXxlJobInfo.setScheduleType(scheduleType);
    		paramXxlJobInfo.setScheduleConf(scheduleConf);
    
    		List<String> result = new ArrayList<>();
    		try {
    			Date lastTime = new Date();
    			for (int i = 0; i < 5; i++) {
    				lastTime = JobScheduleHelper.generateNextValidTime(paramXxlJobInfo, lastTime);
    				if (lastTime != null) {
    					result.add(DateUtil.formatDateTime(lastTime));
    				}
    				else {
    					break;
    				}
    			}
    		}
    		catch (Exception e) {
    			return new ReturnT<List<String>>(ReturnT.FAIL_CODE,
    				(I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")) + e.getMessage());
    		}
    		return new ReturnT<List<String>>(result);
    	}
    
    	@Override
    	public Map<String, Object> getXxlJobPageList(int start, int length, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
    		return xxlJobService.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
    	}
    
    	private XxlJobInfo toEntity(XxlJobInfoVo xxlJobInfoVo){
    		XxlJobInfo xxlJobInfo = new XxlJobInfo();
    		xxlJobInfo.setId(xxlJobInfoVo.getId());
    		xxlJobInfo.setJobGroup(xxlJobInfoVo.getJobGroup());
    		xxlJobInfo.setJobDesc(xxlJobInfoVo.getJobDesc());
    		xxlJobInfo.setAddTime(xxlJobInfoVo.getAddTime());
    		xxlJobInfo.setUpdateTime(xxlJobInfoVo.getUpdateTime());
    		xxlJobInfo.setAuthor(xxlJobInfoVo.getAuthor());
    		xxlJobInfo.setAlarmEmail(xxlJobInfoVo.getAlarmEmail());
    		xxlJobInfo.setScheduleType(xxlJobInfoVo.getScheduleType());
    		xxlJobInfo.setScheduleConf(xxlJobInfoVo.getScheduleConf());
    		xxlJobInfo.setMisfireStrategy(xxlJobInfoVo.getMisfireStrategy());
    		xxlJobInfo.setExecutorRouteStrategy(xxlJobInfoVo.getExecutorRouteStrategy());
    		xxlJobInfo.setExecutorHandler(xxlJobInfoVo.getExecutorHandler());
    		xxlJobInfo.setExecutorParam(xxlJobInfoVo.getExecutorParam());
    		xxlJobInfo.setExecutorBlockStrategy(xxlJobInfoVo.getExecutorBlockStrategy());
    		xxlJobInfo.setExecutorTimeout(xxlJobInfoVo.getExecutorTimeout());
    		xxlJobInfo.setExecutorFailRetryCount(xxlJobInfoVo.getExecutorFailRetryCount());
    		xxlJobInfo.setGlueType(xxlJobInfoVo.getGlueType());
    		xxlJobInfo.setGlueSource(xxlJobInfoVo.getGlueSource());
    		xxlJobInfo.setGlueRemark(xxlJobInfoVo.getGlueRemark());
    		xxlJobInfo.setGlueUpdatetime(xxlJobInfoVo.getGlueUpdatetime());
    		xxlJobInfo.setChildJobId(xxlJobInfoVo.getChildJobId());
    		xxlJobInfo.setTriggerStatus(xxlJobInfoVo.getTriggerStatus());
    		xxlJobInfo.setTriggerLastTime(xxlJobInfoVo.getTriggerLastTime());
    		xxlJobInfo.setTriggerNextTime(xxlJobInfoVo.getTriggerNextTime());
    
    		return xxlJobInfo;
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    (3)绕过xxl-job的权限
    package com.xxl.job.admin.controller.interceptor;
    
    import com.xxl.job.admin.controller.annotation.PermissionLimit;
    import com.xxl.job.admin.core.model.XxlJobUser;
    import com.xxl.job.admin.core.util.I18nUtil;
    import com.xxl.job.admin.service.LoginService;
    import org.springframework.stereotype.Component;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.AsyncHandlerInterceptor;
    
    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * 权限拦截
     *
     * @author xuxueli 2015-12-12 18:09:04
     */
    @Component
    public class PermissionInterceptor implements AsyncHandlerInterceptor {
    
    	private static final List<String> SKIP_URL = new ArrayList<>(Arrays.asList(
    		"/xxl-job-admin/client/addXxlJob",
    		"/xxl-job-admin/client/updateXxlJob",
    		"/xxl-job-admin/client/removeXxlJob",
    		"/xxl-job-admin/client/stopXxlJob",
    		"/xxl-job-admin/client/startXxlJob",
    		"/xxl-job-admin/client/triggerXxlJob",
    		"/xxl-job-admin/client/nextTriggerTimeXxlJob",
    		"/xxl-job-admin/client/getXxlJobPageList"
    	));
    	@Resource
    	private LoginService loginService;
    
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    		if (!(handler instanceof HandlerMethod)) {
    			return true;	// proceed with the next interceptor
    		}
    
    		String url = request.getRequestURI();
    
    		// if need login
    		boolean needLogin = !SKIP_URL.contains(url);
    		boolean needAdminuser = false;
    		HandlerMethod method = (HandlerMethod)handler;
    		PermissionLimit permission = method.getMethodAnnotation(PermissionLimit.class);
    		if (permission!=null) {
    			needLogin = permission.limit();
    			needAdminuser = permission.adminuser();
    		}
    
    		if (needLogin) {
    			XxlJobUser loginUser = loginService.ifLogin(request, response);
    			if (loginUser == null) {
    				response.setStatus(302);
    				response.setHeader("location", request.getContextPath()+"/toLogin");
    				return false;
    			}
    			if (needAdminuser && loginUser.getRole()!=1) {
    				throw new RuntimeException(I18nUtil.getString("system_permission_limit"));
    			}
    			request.setAttribute(LoginService.LOGIN_IDENTITY_KEY, loginUser);
    		}
    
    		return true;	// proceed with the next interceptor
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    四、xxl-job自动化注册

    xxl-job自动化注册放到了项目公共使用的一个common包里,参考的项目:xxl-job自动化注册

    使用的xxl-job-admin的address是从nacos获取服务列表,支持集群部署

    1.common包

    在这里插入图片描述

    2.代码

    package com.eastsoft.common.annotation;
    
    import com.eastsoft.common.config.xxl.XxlJobAutoConfiguration;
    import org.springframework.context.annotation.Import;
    
    import java.lang.annotation.*;
    
    /**
     *
     * 激活xxl-job配置
     * @author aiden
     * @date 2021/9/29 3:45 下午
     * @return
     */
    @Target({ ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Import({ XxlJobAutoConfiguration.class })
    public @interface EnableXxlJob {
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    
    package com.eastsoft.common.config.xxl;
    
    import com.eastsoft.common.constant.AppConstant;
    import com.eastsoft.common.properties.XxlExecutorProperties;
    import com.eastsoft.common.properties.XxlJobProperties;
    import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.cloud.client.discovery.DiscoveryClient;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.env.Environment;
    import org.springframework.util.StringUtils;
    
    import java.util.stream.Collectors;
    
    /**
     *
     * xxl-job自动装配
     * @author aiden
     * @date 2021/9/29 4:38 下午
     * @return
     */
    @Configuration(proxyBeanMethods = false)
    @EnableAutoConfiguration
    @EnableConfigurationProperties(XxlJobProperties.class)
    @Slf4j
    public class XxlJobAutoConfiguration {
    
    	/**
    	 * 配置xxl-job 执行器,提供自动发现 xxl-job-admin 能力
    	 * @param xxlJobProperties xxl 配置
    	 * @param environment 环境变量
    	 * @param discoveryClient 注册发现客户端
    	 * @return
    	 */
    	@Bean
    	public XxlJobSpringExecutor xxlJobSpringExecutor(XxlJobProperties xxlJobProperties, Environment environment,
    			DiscoveryClient discoveryClient) {
    		XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
    		XxlExecutorProperties executor = xxlJobProperties.getExecutor();
    		// 应用名默认为服务名
    		String appName = executor.getAppname();
    		if (!StringUtils.hasText(appName)) {
    			appName = environment.getProperty("spring.application.name");
    		}
    		xxlJobSpringExecutor.setAppname(appName);
    		xxlJobSpringExecutor.setAddress(executor.getAddress());
    		xxlJobSpringExecutor.setIp(executor.getIp());
    		xxlJobSpringExecutor.setPort(executor.getPort());
    		xxlJobSpringExecutor.setAccessToken(xxlJobProperties.getAccessToken());
    		xxlJobSpringExecutor.setLogPath(executor.getLogPath());
    		xxlJobSpringExecutor.setLogRetentionDays(executor.getLogRetentionDays());
    
    		// 如果配置为空则获取注册中心的服务列表 "http://nacos:8848/xxl-job-admin"
    		if (!StringUtils.hasText(xxlJobProperties.getAdmin().getAddresses())) {
    			String serverList = discoveryClient.getServices().stream().filter(s -> s.contains(AppConstant.APPLICATION_XXL_NAME))
    					.flatMap(s -> discoveryClient.getInstances(s).stream()).map(instance -> String
    							.format("http://%s:%s/%s", instance.getHost(), instance.getPort(), AppConstant.APPLICATION_XXL_NAME_ADMIN))
    					.collect(Collectors.joining(","));
    			xxlJobSpringExecutor.setAdminAddresses(serverList);
    
    			log.info(">>>>>>>>>>> xxl-job-admin serverList:{}", serverList);
    		}
    		else {
    			xxlJobSpringExecutor.setAdminAddresses(xxlJobProperties.getAdmin().getAddresses());
    		}
    
    		return xxlJobSpringExecutor;
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    package com.eastsoft.common.properties;
    import lombok.Data;
    
    /**
     *
     * xxl-job管理平台配置
     * @author aiden
     * @date 2021/9/29 3:45 下午
     * @return
     */
    @Data
    public class XxlAdminProperties {
    
    	/**
    	 * 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。 执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
    	 */
    	private String addresses;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    package com.eastsoft.common.properties;
    
    import lombok.Data;
    
    /**
     *
     * xxl-job执行器配置
     * @author aiden
     * @date 2021/9/29 3:50 下午
     * @return
     */
    @Data
    public class XxlExecutorProperties {
    
    	/**
    	 * 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
    	 */
    	private String appname;
    
    	/**
    	 * 服务注册地址,优先使用该配置作为注册地址 为空时使用内嵌服务 ”IP:PORT“ 作为注册地址 从而更灵活的支持容器类型执行器动态IP和动态映射端口问题
    	 */
    	private String address;
    
    	/**
    	 * 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP ,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和
    	 * "调度中心请求并触发任务"
    	 */
    	private String ip;
    
    	/**
    	 * 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
    	 */
    	private Integer port = 0;
    
    	/**
    	 * 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
    	 */
    	private String logPath = "logs/applogs/xxl-job/jobhandler";
    
    	/**
    	 * 执行器日志保存天数 [选填] :值大于3时生效,启用执行器Log文件定期清理功能,否则不生效;
    	 */
    	private Integer logRetentionDays = 30;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    package com.eastsoft.common.properties;
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.context.properties.NestedConfigurationProperty;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     *
     * xxl-job配置
     * @author aiden
     * @date 2021/9/29 3:45 下午
     * @return
     */
    @Data
    @ConfigurationProperties("xxl.job")
    public class XxlJobProperties {
    
    	@NestedConfigurationProperty
    	private XxlAdminProperties admin = new XxlAdminProperties();
    
    	@NestedConfigurationProperty
    	private XxlExecutorProperties executor = new XxlExecutorProperties();
    
    	private String accessToken = "";
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    五、common包里存在minio配置,而xxl-job不需要使用使用minio,却需要进行minio配置,排除掉minio配置加载

    1.创建MinioCondition

    package com.eastsoft.common.config;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    /**
     * @title: MinioCondition
     * @Description []
     * @Author lhz
     * @Date: 2022/9/1 0001 14:08
     * @Version 1.0
     */
    
    public class MinioCondition implements Condition {
    
    	@Override
    	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    		return Boolean.parseBoolean(context.getEnvironment().getProperty("minio.enabled"));
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.MinioConfig更改

    package com.eastsoft.common.config.minio;
    
    import com.eastsoft.common.config.MinioCondition;
    import io.minio.MinioClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * description: 获取配置文件信息
     *
     * @author: weirx
     * @time: 2021/8/25 9:50
     */
    @Configuration
    @EnableConfigurationProperties(MinioPropertiesConfig.class)
    public class MinioConfig {
    
        @Autowired
        private MinioPropertiesConfig minioPropertiesConfig;
    
    
        /**
         * 初始化 MinIO 客户端
         */
    	@Conditional(MinioCondition.class)
        @Bean
        public MinioClient minioClient() {
            MinioClient minioClient = MinioClient.builder()
                    .endpoint(minioPropertiesConfig.getEndpoint())
                    .credentials(minioPropertiesConfig.getAccessKey(), minioPropertiesConfig.getSecretKey())
                    .build();
            return minioClient;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    3.xxl-job更改

    启动器更改

    @ComponentScan(excludeFilters= {@ComponentScan.Filter(type= FilterType.ASSIGNABLE_TYPE, value= {MinioUtil.class, XxlJobAutoConfiguration.class})})
    
    • 1

    xml配置更改

    minio:
      enabled: false
    
    • 1
    • 2

    参考文章

    xxl-job详细使用指南

    springboot启动的时候排除加载项

    [读书笔记] 二、条件注解@Conditional,组合注解,元注解

    SpringCloud微服务实战——搭建企业级开发框架(四十三):集成分布式任务调度平台XXL-JOB,实现定时任务功能

  • 相关阅读:
    KeeWiDB:兼容Redis协议,领跑NoSQL
    macOS 中 Apple Distribution 与 Apple Development 证书不受信任解决方法
    #循循渐进学51单片机#变量进阶与点阵LED#not.6
    【系统设计】S3 对象存储
    C语言 error LNK2019: 无法解析的外部符号
    最新前端技术趋势——菜鸟必看
    发布四大战略举措,亚马逊云科技看准了中国云市场的哪些新机会?
    linux syslog日志转发服务端、客户端配置
    047:vue+openlayers:双击鼠标显示品牌代言人名片(示例代码)
    Android OpenGLES3.0 开发 :光照基础
  • 原文地址:https://blog.csdn.net/weixin_43854673/article/details/126626032