【知识积累】saturn集成springboot2.*

背景:公司项目使用的是SpringCloud版本是Hoxton,Springboot版本是2.3.4,而定时任务框架定为Saturn,但是Saturn支持的Springboot的最新版本为1.5.16,不兼容目前的项目,所以对Saturn进行改造。此文使用的是Saturn内嵌的方式。

 

一、安装Mysql和Zookeeper

JDK : 1.8

MySQL:5.7.23

ZooKeeper: 3.4.8

二、执行SQL

2.1、创建数据库

CREATE DATABASE saturn CHARACTER SET utf8 COLLATE utf8_general_ci;

2.2、schema创建

这里获取最新的schema.sql。如果希望获得其他版本的schema,可以在源代码的其他tag上获取。

执行schema.sql。

三、安装Console

3.1、下载

Releases · vipshop/Saturn · GitHub 中点击最新版本的“Console Zip File”,下载得到saturn-console-{version}-exec.jar,将之放到合适的目录。

3.2、启动

java -DSATURN_CONSOLE_DB_URL=jdbc:mysql://localhost:3306/saturn -DSATURN_CONSOLE_DB_USERNAME=root -DSATURN_CONSOLE_DB_PASSWORD=123456 -jar saturn-console-3.5.1-exec.jar

注:数据库账号密码为root 123456

3.3、访问

http://localhost:9088

四、配置ZK集群

  五、添加域,绑定ZK集群

 六、配置console绑定ZK集群

 注:default是console的id,test是zk集群的id

 七、Maven配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/>
    </parent>

    <groupId>com.darren.center</groupId>
    <artifactId>saturn-springboot2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>saturn-springboot2</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <saturn.version>3.5.1</saturn.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.vip.saturn</groupId>
            <artifactId>saturn-embed-spring</artifactId>
            <version>${saturn.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

八、application.properties配置

saturnConsoleURI=http://localhost:9088
saturnHome=F:/saturn/saturn-executor-3.5.1
saturnAppNamespace=www.abc.com
saturnStdout=true
multiMode=true

注:执行器地址要使用反斜杠

九、配置Saturn

package com.darren.center.saturnspringboot2.configuration;

import com.vip.saturn.embed.EmbeddedSaturn;
import com.vip.saturn.job.spring.AbstractSpringSaturnApplication;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import java.lang.management.ManagementFactory;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;

/**
 * Author: Darren
 * Date: 2021-12-18 08:50:43
 * Version: 1.0
 * Description:
 * 因为嵌入式使用Saturn,其打包方式、运行方式、运行jvm参数都依赖于工程的主框架(比如Spring、Tomcat等),造成Saturn ClassLoader不能与业务ClassLoader分离,从而带来的日志分离、包冲突等问题,
 * 而且导致Executor一键重启、自动升级等功能失效。所以,我们不建议使用嵌入式。
 */
@Component
public class SaturnConfig extends AbstractSpringSaturnApplication implements ApplicationListener {

    protected final Log logger = LogFactory.getLog(this.getClass());
    private EmbeddedSaturn embeddedSaturn;
    /**
     * 如果设置true,那么当启动或停止Executor时出现异常,将只打印Warn日志,不抛出异常,不影响Spring容器的运行;
     * 如果设置false,则不仅打印日志,而且会抛出异常,影响Spring容器的启动和停止
     */
    private boolean ignoreExceptions = false;
    private static final String DELIMITER = "@-@";
    /**
     * Saturn console 地址
     */
    @Value("${saturnConsoleURI}")
    private String saturnConsoleURI;
    /**
     * Satrun执行器位置
     */
    @Value("${saturnHome}")
    private String saturnHome;
    /**
     * 命名空间
     */
    @Value("${saturnAppNamespace}")
    private String saturnAppNamespace;
    /**
     * 是否将日志输出至标准输出
     */
    @Value("${saturnStdout}")
    private boolean saturnStdout;
    /**
     * 是否开启单机多事例模式
     */
    @Value("${multiMode}")
    private boolean multiMode;

    public SaturnConfig() {
    }

    @Override
    public void init() {
    }

    @Override
    public void destroy() {
    }


    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        try {
            if (event instanceof ContextRefreshedEvent) {
                ContextRefreshedEvent contextRefreshedEvent = (ContextRefreshedEvent)event;
                this.applicationContext = contextRefreshedEvent.getApplicationContext();
                if (this.embeddedSaturn == null) {
                    String executorName = this.getExecutorName(multiMode);
                    System.setProperty("VIP_SATURN_CONSOLE_URI", saturnConsoleURI);
                    System.setProperty("saturn.home", saturnHome);
                    System.setProperty("saturn.app.namespace", saturnAppNamespace);
                    System.setProperty("saturn.app.executorName", executorName);
                    // 注意,开启saturn-executor的日志输出到控制台,只用于开发环境
                    if (saturnStdout) {
                        System.setProperty("saturn.stdout", "true");
                    }

                    logger.info("---统一定时任务[UJP-CORE-EXECUTOR]启动ing----");
                    this.embeddedSaturn = new EmbeddedSaturn();
                    this.embeddedSaturn.setSaturnApplication(this);
                    this.embeddedSaturn.start();

                    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                        @Override
                        public void run() {
                            logger.info("停止执行器中...");
                            try {
                                String s = String.format("%s/rest/v1/namespaces/%s/executors/%s", saturnConsoleURI,
                                        saturnAppNamespace, executorName);
                                URL url = new URL(s);
                                HttpURLConnection con = (HttpURLConnection) url.openConnection();
                                con.setRequestMethod("DELETE");
                                con.setConnectTimeout(3000);
                                con.setReadTimeout(3000);
                                con.getResponseCode();
                                con.disconnect();
                            } catch (Exception e) {
                                logger.error("停止执行器时清理执行器出错了", e);
                            }
                        }
                    }));
                    logger.info("---统一定时任务[UJP-CORE-EXECUTOR]启动成功----");
                }
            } else if (event instanceof ContextClosedEvent && this.embeddedSaturn != null) {
                this.embeddedSaturn.stopGracefully();
                this.embeddedSaturn = null;
            }
        } catch (Exception var3) {
            logger.error("---统一定时任务[UJP-CORE-EXECUTOR]启动失败----", var3);
            if (!this.ignoreExceptions) {
                throw new RuntimeException(var3);
            }
        }

    }

    /**
     * 获取执行器名称
     * @param multiMode
     * @return
     */
    private final String getExecutorName(boolean multiMode) {
        StringBuilder sb = new StringBuilder(this.getHostName());
        if (multiMode) {
            String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
            sb.append(DELIMITER).append(pid);
        }
        return sb.toString();
    }

    /**
     * 获取主机名
     * @return
     */
    private final String getHostName() {
        String hn = "UNKNOWN_HOST_NAME";
        try {
            hn = InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            logger.warn("获取主机名失败,请使用`hostnamectl`命令配置", e);
        }
        return hn;
    }

    public boolean isIgnoreExceptions() {
        return this.ignoreExceptions;
    }

    public void setIgnoreExceptions(boolean ignoreExceptions) {
        this.ignoreExceptions = ignoreExceptions;
    }

    public String getSaturnConsoleURI() {
        return saturnConsoleURI;
    }

    public void setSaturnConsoleURI(String saturnConsoleURI) {
        this.saturnConsoleURI = saturnConsoleURI;
    }

    public String getSaturnHome() {
        return saturnHome;
    }

    public void setSaturnHome(String saturnHome) {
        this.saturnHome = saturnHome;
    }

    public String getSaturnAppNamespace() {
        return saturnAppNamespace;
    }

    public void setSaturnAppNamespace(String saturnAppNamespace) {
        this.saturnAppNamespace = saturnAppNamespace;
    }

    public boolean isSaturnStdout() {
        return saturnStdout;
    }

    public void setSaturnStdout(boolean saturnStdout) {
        this.saturnStdout = saturnStdout;
    }

    public boolean isMultiMode() {
        return multiMode;
    }

    public void setMultiMode(boolean multiMode) {
        this.multiMode = multiMode;
    }

    /*
    @Bean
    public EmbeddedSpringSaturnApplication embeddedSpringSaturnApplication() {
        EmbeddedSpringSaturnApplication embeddedSpringSaturnApplication = new EmbeddedSpringSaturnApplication();
        embeddedSpringSaturnApplication.setIgnoreExceptions(false);
        return embeddedSpringSaturnApplication;
    }
*/

}

十、编写JOB

package com.darren.center.saturnspringboot2.job;

import com.darren.center.saturnspringboot2.service.DemoService;
import com.vip.saturn.job.AbstractSaturnJavaJob;
import com.vip.saturn.job.SaturnJobExecutionContext;
import com.vip.saturn.job.SaturnJobReturn;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * Author: Darren
 * Date: 2021-12-18 08:24:37
 * Version: 1.0
 * Description:
 */
@Component
public class DemoJob extends AbstractSaturnJavaJob {

    private static final Logger log = LoggerFactory.getLogger(DemoJob.class);

    @Resource
    private DemoService demoService;

    @Override
    public SaturnJobReturn handleJavaJob(String jobName, Integer shardItem, String shardParam,
                                         SaturnJobExecutionContext shardingContext) throws InterruptedException {
        log.info("{} is running, item is {}", jobName, shardItem);
        demoService.doing();
        return new SaturnJobReturn();
    }

}
package com.darren.center.saturnspringboot2.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * Author: Darren
 * Date: 2021-12-18 08:25:06
 * Version: 1.0
 * Description:
 */
@Service
public class DemoService {

    private static final Logger log = LoggerFactory.getLogger(DemoService.class);

    public void doing() {
        log.info("DemoService is doing...");
    }

}

十一、在Console添加自己的JOB

11.1、填写配合的域名www.abc.com

11.2、配置JOB

11.3、启动JOB任务调度

 十二、本地启动自己的JOB

十三、优化点

  • 当executor下线后,自动删除;
  • 支持单机多实例模式;

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值