jfinal 集成 xxljob

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.jfinal.plugins</groupId>
    <artifactId>xxljob</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>com.jfinal</groupId>
            <artifactId>jfinal</artifactId>
            <version>4.9.03</version>
        </dependency>

        <dependency>
            <groupId>com.jfinal</groupId>
            <artifactId>jfinal-undertow</artifactId>
            <version>1.9</version>
        </dependency>

        <dependency>
            <groupId>com.xuxueli</groupId>
            <artifactId>xxl-job-core</artifactId>
            <version>2.3.0</version>
        </dependency>
    </dependencies>

</project>

xxl-job-executor.properties

### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
### xxl-job, access token
xxl.job.accessToken=
### xxl-job executor appname
xxl.job.executor.appname=xxl-job-executor-sample
### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null
xxl.job.executor.address=
### xxl-job executor server-info
xxl.job.executor.ip=127.0.0.1
xxl.job.executor.port=18000
### xxl-job executor log-path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### xxl-job executor log-retention-days
xxl.job.executor.logretentiondays=30

java代码:扫描借助波总的 PathScanner 代码。直接复制黏贴。

package com.jfinal.plugins;

import java.lang.annotation.*;

/**
 * @author zhangshiqiang on 2021-05-31.
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface XxlJobRegister {
}
package com.jfinal.plugins;

import com.jfinal.core.PathScanner;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.IPlugin;
import com.xxl.job.core.executor.impl.XxlJobSimpleExecutor;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @author zhangshiqiang on 2021-05-30.
 */
public class XxlJobPlugin implements IPlugin {

    private static final Prop config = PropKit.use("xxl-job-executor.properties");

    private XxlJobSimpleExecutor xxlJobSimpleExecutor;

    @Override
    public boolean start() {
        XxlJobSimpleExecutor xxlJobSimpleExecutor = new XxlJobSimpleExecutor();
        xxlJobSimpleExecutor.setAdminAddresses(config.get("xxl.job.admin.addresses"));
        xxlJobSimpleExecutor.setAppname(config.get("xxl.job.executor.appname"));
        xxlJobSimpleExecutor.setIp(config.get("xxl.job.executor.ip"));
        xxlJobSimpleExecutor.setPort(config.getInt("xxl.job.executor.port", 0));
        xxlJobSimpleExecutor.setAccessToken(config.get("xxl.job.accessToken"));
        xxlJobSimpleExecutor.setLogPath(config.get("xxl.job.executor.logpath"));
        xxlJobSimpleExecutor.setLogRetentionDays(config.getInt("xxl.job.executor.logretentiondays", 30));
        // 扫描注解类
        try {
            List<Object> xxlJobBeanList = xxlJobBeanList();
            xxlJobSimpleExecutor.setXxlJobBeanList(xxlJobBeanList);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        xxlJobSimpleExecutor.start();
        this.xxlJobSimpleExecutor = xxlJobSimpleExecutor;
        return true;
    }

    @Override
    public boolean stop() {
        if (xxlJobSimpleExecutor != null) {
            xxlJobSimpleExecutor.destroy();
        }
        return true;
    }

    private ClassLoader getClassLoader() {
        ClassLoader ret = Thread.currentThread().getContextClassLoader();
        return ret != null ? ret : XxlJobPlugin.class.getClassLoader();
    }

    private List<Object> xxlJobBeanList() throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        List<Object> list = new ArrayList<>();
        Enumeration<URL> urls = getClassLoader().getResources("");
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            if ("jar".equals(url.getProtocol())) {
                scanJar(url, list);
            } else if ("file".equals(url.getProtocol())) {
                File file = new File(url.getPath());
                String classPath = getClassPath(file);
                scanFile(file, classPath, list);
            }
        }
        return list;
    }

    private String getClassPath(File file) {
        String ret = file.getAbsolutePath();
        // 添加后缀,以便后续的 indexOf(bp) 可以正确获得下标值,因为 bp 确定有后缀
        if (!ret.endsWith(File.separator)) {
            ret = ret + File.separator;
        }
        return ret;
    }

    private void scanFile(File file, String classPath, List<Object> list) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files != null) {
                for (File fi : files) {
                    scanFile(fi, classPath, list);
                }
            }
        } else if (file.isFile()) {
            String fullName = file.getAbsolutePath();
            if (fullName != null && fullName.endsWith(".class")) {
                String className = fullName.substring(classPath.length(), fullName.length() - 6).replace(File.separatorChar, '.');
                Class<?> aClass = getClassLoader().loadClass(className);
                if (aClass.getAnnotation(XxlJobRegister.class) != null && list.stream().noneMatch(s -> s.getClass() == aClass)) {
                    Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
                    declaredConstructor.setAccessible(true);
                    list.add(declaredConstructor.newInstance());
                }
            }
        }
    }

    private void scanJar(URL url, List<Object> list) throws IOException {
        URLConnection urlConn = url.openConnection();
        if (urlConn instanceof JarURLConnection) {
            JarURLConnection jarUrlConn = (JarURLConnection) urlConn;
            try (JarFile jarFile = jarUrlConn.getJarFile()) {
                Enumeration<JarEntry> jarFileEntries = jarFile.entries();
                while (jarFileEntries.hasMoreElements()) {
                    JarEntry jarEntry = jarFileEntries.nextElement();
                    String en = jarEntry.getName();
                    // 只扫描 basePackage 之下的类
                    if (en.endsWith(".class")) {
                        // JarEntry.getName() 返回值中的路径分隔符在所有操作系统下都是 '/'
                        en = en.substring(0, en.length() - 6).replace('/', '.');
                        Class<?> aClass = getClassLoader().loadClass(en);
                        if (aClass.getAnnotation(XxlJobRegister.class) != null && list.stream().noneMatch(s -> s.getClass() == aClass)) {
                            Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
                            declaredConstructor.setAccessible(true);
                            list.add(declaredConstructor.newInstance());
                        }
                    }
                }
            } catch (ClassNotFoundException | NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}

测试代码

package com.jfinal.schedule;

import com.jfinal.plugins.XxlJobRegister;
import com.xxl.job.core.handler.annotation.XxlJob;

/**
 * @author zhangshiqiang on 2021-05-31.
 */
@XxlJobRegister
public class TestJfinal {

    @XxlJob("test")
    public void test() {
        System.out.println("测试jfinal定时器");
    }
}


评论区

zhangshiqiang

2021-06-01 14:09

File lib = new File("xx.jar")
JarFile jarFile = new JarFile(lib);