Selaa lähdekoodia

添加xxl-job和apollo示例

Yue 2 vuotta sitten
vanhempi
sitoutus
830647fc81

+ 11 - 0
vber-job/vber-job-test/Dockerfile

@@ -0,0 +1,11 @@
+FROM openjdk:8-jre-slim
+MAINTAINER YUE
+
+ENV PARAMS=""
+
+ENV TZ=Asia/Shanghai
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+ADD vber-job-test-*.jar /app.jar
+
+ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /app.jar $PARAMS"]

+ 89 - 0
vber-job/vber-job-test/pom.xml

@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.vber</groupId>
+        <artifactId>vber-job</artifactId>
+        <version>2.4.0</version>
+    </parent>
+
+    <artifactId>vber-job-test</artifactId>
+    <packaging>jar</packaging>
+    <description>spring boot 测试xxl-job 及 apollo</description>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <!-- Import dependency management from Spring Boot (依赖管理:继承一些默认的依赖,工程需要依赖的jar包的管理,申明其他dependency的时候就不需要version) -->
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-parent</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <!-- spring-boot-starter-web (spring-webmvc + tomcat) -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Spring Boot 配置处理器 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <!-- xxl-job-core -->
+        <dependency>
+            <groupId>com.xuxueli</groupId>
+            <artifactId>xxl-job-core</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+
+        <!-- apollo -->
+        <dependency>
+            <groupId>com.ctrip.framework.apollo</groupId>
+            <artifactId>apollo-client</artifactId>
+            <version>2.1.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.28</version>
+            <scope>compile</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <!-- spring-boot-maven-plugin (提供了直接运行项目的插件:如果是通过parent方式继承spring-boot-starter-parent则不用此插件) -->
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 16 - 0
vber-job/vber-job-test/src/main/java/com/vber/JobTestApplication.java

@@ -0,0 +1,16 @@
+package com.vber;
+
+import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+//使用apollo配置中心获取配置信息
+@EnableApolloConfig
+public class JobTestApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(JobTestApplication.class, args);
+    }
+
+}

+ 16 - 0
vber-job/vber-job-test/src/main/java/com/vber/config/JobConfig.java

@@ -0,0 +1,16 @@
+package com.vber.config;
+
+import com.vber.config.properties.JobExecutorProperties;
+import com.vber.config.properties.JobProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Component
+public class JobConfig {
+    @Bean
+    public JobProperties getJobConfig() {
+        JobProperties jp = new JobProperties();
+        jp.setExecutor(new JobExecutorProperties());
+        return jp;
+    }
+}

+ 13 - 0
vber-job/vber-job-test/src/main/java/com/vber/config/VberConfig.java

@@ -0,0 +1,13 @@
+package com.vber.config;
+
+import com.vber.config.properties.VberProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class VberConfig {
+    @Bean
+    public VberProperties getVberConfig() {
+        return new VberProperties();
+    }
+}

+ 18 - 0
vber-job/vber-job-test/src/main/java/com/vber/config/properties/JobExecutorProperties.java

@@ -0,0 +1,18 @@
+package com.vber.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties("xxl-job.executor")
+public class JobExecutorProperties {
+    String appName;
+    String address;
+    String ip;
+    int port;
+    String logPath;
+    int logRetentionDays;
+}
+

+ 14 - 0
vber-job/vber-job-test/src/main/java/com/vber/config/properties/JobProperties.java

@@ -0,0 +1,14 @@
+package com.vber.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@Data
+@ConfigurationProperties(prefix = "xxl-job")
+public class JobProperties {
+    String adminAddresses;
+    String accessToken;
+    JobExecutorProperties executor;
+}
+
+

+ 16 - 0
vber-job/vber-job-test/src/main/java/com/vber/config/properties/VberProperties.java

@@ -0,0 +1,16 @@
+package com.vber.config.properties;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@lombok.Data
+@Component
+public class VberProperties {
+
+    @Value("${vber.name:iwb}")
+    String name;
+    @Value("${vber.index:10}")
+    Integer index;
+    @Value("${apollo.bootstrap.namespaces}")
+    String namespaces;
+}

+ 28 - 0
vber-job/vber-job-test/src/main/java/com/vber/service/controller/TestController.java

@@ -0,0 +1,28 @@
+package com.vber.service.controller;
+
+import com.vber.config.properties.VberProperties;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+@RestController
+public class TestController {
+    private final VberProperties vberProperties;
+
+
+    public TestController(VberProperties vberProperties) {
+        this.vberProperties = vberProperties;
+    }
+
+
+    @GetMapping("t")
+    public Map<String, Object> test() {
+        Map<String, Object> map = new LinkedHashMap<>();
+        map.put("name", vberProperties.getName());
+        map.put("index", vberProperties.getIndex());
+        map.put("namespaces", vberProperties.getNamespaces());
+        return map;
+    }
+}

+ 52 - 0
vber-job/vber-job-test/src/main/java/com/vber/service/executor/JobExecutor.java

@@ -0,0 +1,52 @@
+package com.vber.service.executor;
+
+import com.vber.config.properties.JobProperties;
+import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Component
+public class JobExecutor {
+
+    private final Logger logger = LoggerFactory.getLogger(JobExecutor.class);
+
+    //@Autowired
+    //JobProperties jobProperties;
+
+    @Bean
+    public XxlJobSpringExecutor xxlJobExecutor(JobProperties getJobConfig) {
+        logger.info(">>>>>>>>>>> xxl-job config init.");
+        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
+        xxlJobSpringExecutor.setAdminAddresses(getJobConfig.getAdminAddresses());
+        xxlJobSpringExecutor.setAppname(getJobConfig.getExecutor().getAppName());
+        xxlJobSpringExecutor.setAddress(getJobConfig.getExecutor().getAddress());
+        xxlJobSpringExecutor.setIp(getJobConfig.getExecutor().getIp());
+        xxlJobSpringExecutor.setPort(getJobConfig.getExecutor().getPort());
+        xxlJobSpringExecutor.setAccessToken(getJobConfig.getAccessToken());
+        xxlJobSpringExecutor.setLogPath(getJobConfig.getExecutor().getLogPath());
+        xxlJobSpringExecutor.setLogRetentionDays(getJobConfig.getExecutor().getLogRetentionDays());
+
+        return xxlJobSpringExecutor;
+    }
+
+    /**
+     * 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP;
+     *
+     *      1、引入依赖:
+     *          <dependency>
+     *             <groupId>org.springframework.cloud</groupId>
+     *             <artifactId>spring-cloud-commons</artifactId>
+     *             <version>${version}</version>
+     *         </dependency>
+     *
+     *      2、配置文件,或者容器启动变量
+     *          spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'
+     *
+     *      3、获取IP
+     *          String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
+     */
+
+
+}

+ 261 - 0
vber-job/vber-job-test/src/main/java/com/vber/service/jobhandler/JobTestHandle.java

@@ -0,0 +1,261 @@
+package com.vber.service.jobhandler;
+
+import com.vber.config.properties.VberProperties;
+import com.xxl.job.core.context.XxlJobHelper;
+import com.xxl.job.core.handler.annotation.XxlJob;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * XxlJob开发示例(Bean模式)
+ * <p>
+ * 开发步骤:
+ * 1、任务开发:在Spring Bean实例中,开发Job方法;
+ * 2、注解配置:为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")",注解value值对应的是调度中心新建任务的JobHandler属性的值。
+ * 3、执行日志:需要通过 "XxlJobHelper.log" 打印执行日志;
+ * 4、任务结果:默认任务结果为 "成功" 状态,不需要主动设置;如有诉求,比如设置任务结果为失败,可以通过 "XxlJobHelper.handleFail/handleSuccess" 自主设置任务结果;
+ *
+ * @author xuxueli 2019-12-11 21:52:51
+ */
+@Component
+public class JobTestHandle {
+    private static final Logger logger = LoggerFactory.getLogger(JobTestHandle.class);
+
+    private final VberProperties vberProperties;
+
+    public JobTestHandle(VberProperties getVberConfig) {
+        this.vberProperties = getVberConfig;
+    }
+
+    /**
+     * 1、简单任务示例(Bean模式)
+     */
+    @XxlJob("vberTestHandler")
+    public void vberTestHandler() throws Exception {
+        XxlJobHelper.log("XXL-JOB, Hello World." + vberProperties.getName());
+
+        for (int i = 0; i < 5; i++) {
+            XxlJobHelper.log("beat at:" + i);
+            XxlJobHelper.log("beat at:" + vberProperties.getIndex());
+            TimeUnit.SECONDS.sleep(2);
+        }
+        // default success
+    }
+
+
+    /**
+     * 2、分片广播任务
+     */
+    @XxlJob("shardingJobHandler")
+    public void shardingJobHandler() throws Exception {
+
+        // 分片参数
+        int shardIndex = XxlJobHelper.getShardIndex();
+        int shardTotal = XxlJobHelper.getShardTotal();
+
+        XxlJobHelper.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
+
+        // 业务逻辑
+        for (int i = 0; i < shardTotal; i++) {
+            if (i == shardIndex) {
+                XxlJobHelper.log("第 {} 片, 命中分片开始处理", i);
+            } else {
+                XxlJobHelper.log("第 {} 片, 忽略", i);
+            }
+        }
+
+    }
+
+
+    /**
+     * 3、命令行任务
+     */
+    @XxlJob("commandJobHandler")
+    public void commandJobHandler() throws Exception {
+        String command = XxlJobHelper.getJobParam();
+        int exitValue = -1;
+
+        BufferedReader bufferedReader = null;
+        try {
+            // command process
+            ProcessBuilder processBuilder = new ProcessBuilder();
+            processBuilder.command(command);
+            processBuilder.redirectErrorStream(true);
+
+            Process process = processBuilder.start();
+            //Process process = Runtime.getRuntime().exec(command);
+
+            BufferedInputStream bufferedInputStream = new BufferedInputStream(process.getInputStream());
+            bufferedReader = new BufferedReader(new InputStreamReader(bufferedInputStream));
+
+            // command log
+            String line;
+            while ((line = bufferedReader.readLine()) != null) {
+                XxlJobHelper.log(line);
+            }
+
+            // command exit
+            process.waitFor();
+            exitValue = process.exitValue();
+        } catch (Exception e) {
+            XxlJobHelper.log(e);
+        } finally {
+            if (bufferedReader != null) {
+                bufferedReader.close();
+            }
+        }
+
+        if (exitValue == 0) {
+            // default success
+        } else {
+            XxlJobHelper.handleFail("command exit value(" + exitValue + ") is failed");
+        }
+
+    }
+
+
+    /**
+     * 4、跨平台Http任务
+     * 参数示例:
+     * "url: http://www.baidu.com\n" +
+     * "method: get\n" +
+     * "data: content\n";
+     */
+    @XxlJob("httpJobHandler")
+    public void httpJobHandler() throws Exception {
+
+        // param parse
+        String param = XxlJobHelper.getJobParam();
+        if (param == null || param.trim().length() == 0) {
+            XxlJobHelper.log("param[" + param + "] invalid.");
+
+            XxlJobHelper.handleFail();
+            return;
+        }
+
+        String[] httpParams = param.split("\n");
+        String url = null;
+        String method = null;
+        String data = null;
+        for (String httpParam : httpParams) {
+            if (httpParam.startsWith("url:")) {
+                url = httpParam.substring(httpParam.indexOf("url:") + 4).trim();
+            }
+            if (httpParam.startsWith("method:")) {
+                method = httpParam.substring(httpParam.indexOf("method:") + 7).trim().toUpperCase();
+            }
+            if (httpParam.startsWith("data:")) {
+                data = httpParam.substring(httpParam.indexOf("data:") + 5).trim();
+            }
+        }
+
+        // param valid
+        if (url == null || url.trim().length() == 0) {
+            XxlJobHelper.log("url[" + url + "] invalid.");
+
+            XxlJobHelper.handleFail();
+            return;
+        }
+        if (method == null || !Arrays.asList("GET", "POST").contains(method)) {
+            XxlJobHelper.log("method[" + method + "] invalid.");
+
+            XxlJobHelper.handleFail();
+            return;
+        }
+        boolean isPostMethod = method.equals("POST");
+
+        // request
+        HttpURLConnection connection = null;
+        BufferedReader bufferedReader = null;
+        try {
+            // connection
+            URL realUrl = new URL(url);
+            connection = (HttpURLConnection) realUrl.openConnection();
+
+            // connection setting
+            connection.setRequestMethod(method);
+            connection.setDoOutput(isPostMethod);
+            connection.setDoInput(true);
+            connection.setUseCaches(false);
+            connection.setReadTimeout(5 * 1000);
+            connection.setConnectTimeout(3 * 1000);
+            connection.setRequestProperty("connection", "Keep-Alive");
+            connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
+            connection.setRequestProperty("Accept-Charset", "application/json;charset=UTF-8");
+
+            // do connection
+            connection.connect();
+
+            // data
+            if (isPostMethod && data != null && data.trim().length() > 0) {
+                DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream());
+                dataOutputStream.write(data.getBytes(StandardCharsets.UTF_8));
+                dataOutputStream.flush();
+                dataOutputStream.close();
+            }
+
+            // valid StatusCode
+            int statusCode = connection.getResponseCode();
+            if (statusCode != 200) {
+                throw new RuntimeException("Http Request StatusCode(" + statusCode + ") Invalid.");
+            }
+
+            // result
+            bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
+            StringBuilder result = new StringBuilder();
+            String line;
+            while ((line = bufferedReader.readLine()) != null) {
+                result.append(line);
+            }
+            String responseMsg = result.toString();
+
+            XxlJobHelper.log(responseMsg);
+
+        } catch (Exception e) {
+            XxlJobHelper.log(e);
+
+            XxlJobHelper.handleFail();
+        } finally {
+            try {
+                if (bufferedReader != null) {
+                    bufferedReader.close();
+                }
+                if (connection != null) {
+                    connection.disconnect();
+                }
+            } catch (Exception e2) {
+                XxlJobHelper.log(e2);
+            }
+        }
+
+    }
+
+    /**
+     * 5、生命周期任务示例:任务初始化与销毁时,支持自定义相关逻辑;
+     */
+    @XxlJob(value = "demoJobHandler2", init = "init", destroy = "destroy")
+    public void demoJobHandler2() throws Exception {
+        XxlJobHelper.log("XXL-JOB, Hello World.");
+    }
+
+    public void init() {
+        logger.info("init");
+    }
+
+    public void destroy() {
+        logger.info("destroy");
+    }
+
+
+}

+ 32 - 0
vber-job/vber-job-test/src/main/resources/application.yml

@@ -0,0 +1,32 @@
+# 开发环境配置
+server:
+  port: 6071
+
+# 日志配置
+logging:
+  config: classpath:logback.xml
+
+# xxl-job配置
+xxl-job:
+  admin-addresses: http://47.112.30.247:4605
+  access-token: iwb_net
+  executor:
+    address:
+    app-name: vber-test-job
+    ip:
+    port: 9999
+    log-path: /data/applogs/xxl-job/jobhandler
+    log-retention-days: 10
+
+app:
+  id: job-test
+apollo:
+  meta: http://192.168.0.82:8080       # Apollo 配置中心地址
+  #cluster: default                       # 指定使用哪个集群的配置
+  cache-dir: /java_test_opt/data/                   # 为了防止配置中心无法连接等问题,Apollo 会自动将配置本地缓存一份。
+  bootstrap:
+    enabled: true                        # 是否开启 Apollo
+    namespaces: application              # Namespace 的配置,默认 application
+    eagerLoad:
+      enabled: false                      # 是否将 Apollo 加载提到初始化日志系统之前
+

+ 29 - 0
vber-job/vber-job-test/src/main/resources/logback.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration debug="false" scan="true" scanPeriod="1 seconds">
+
+    <contextName>logback</contextName>
+    <property name="log.path" value="/data/applogs/job-test/xxl-job-test.log"/>
+
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${log.path}.%d{yyyy-MM-dd}.zip</fileNamePattern>
+        </rollingPolicy>
+        <encoder>
+            <pattern>%date %level [%thread] %logger{36} [%file : %line] %msg%n
+            </pattern>
+        </encoder>
+    </appender>
+
+    <root level="info">
+        <appender-ref ref="console"/>
+        <appender-ref ref="file"/>
+    </root>
+
+</configuration>