quartz动态任务-查看文章

quartz动态任务

发表于:2018-07-28 11:18:47 分类:JAVA 阅读:679次

TIM图片20180728102259.png

目前采用的方式是启动核心调试系统,然后在系统本地硬盘指定一个动态class读取文件夹。


有任务时,在原核心项目下新建一个任务包开始编码。编码完成后编译,取到当前任务的包下的所有class,上传至上一步的文件夹。

然后通过web管理端新建任务,任务class名填入当前任务的全包路径,任务名填入任务描述,填入时间表达式。

添加任务.png

保存后,控制器收到请求就会去指定的文件夹查找class并加载。接着,创建仓库实例和sericce实例并加入spring容器管理。最后由调度器调度该任务。

添加任务代码:

public void addJob(String jarName, String jobClassName, String jobGroupName, String cronExpression,HttpServletRequest request) throws Exception {
    // 启动调度器
    scheduler.start();
    //构建job信息
    JobDetail jobDetail = JobBuilder.newJob(getClass(rootPath, jarName,request).getClass()).withIdentity(jobClassName, jobGroupName).build();
    //表达式调度构建器(即任务执行的时间)
    CronScheduleBuilder scheduleBuilder = cronSchedule(cronExpression);
    //按新的cronExpression表达式构建一个新的trigger
    Trigger trigger = newTrigger().withIdentity(jobClassName, jobGroupName).withSchedule(scheduleBuilder).build();
    try {
        scheduler.scheduleJob(jobDetail, trigger);
    } catch (SchedulerException e) {
        throw new Exception("创建定时任务失败");
    }
}
/**
     * 加载指定路径下的所有class文件,并返回指定名称的class对象
     *
     * @param rootPath      指定的路径
     * @param classFileName 需要返回的class文件名
     * @return
     * @throws Exception
     */
    private Class<?> loadClassFromPath(String rootPath, String classFileName,HttpServletRequest request) throws Exception {

        // 设置class文件所在根路径
      
        File clazzPath = new File(rootPath);
        Class<?> res = null;
        if (clazzPath.exists() && clazzPath.isDirectory()) {
            Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
            boolean accessible = method.isAccessible();
            try {
                if (accessible == false) {
                    method.setAccessible(true);
                }
                // 设置类加载器
                URLClassLoader classLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader().getParent();
                // 将当前类路径加入到类加载器中
                method.invoke(classLoader, clazzPath.toURI().toURL());
            } finally {
                method.setAccessible(accessible);
            }
            // 获取路径长度
            int clazzPathLen = clazzPath.getAbsolutePath().length() + 1;
            Stack<File> stack = new Stack<>();
            stack.push(clazzPath);
            // 遍历类路径
            while (stack.isEmpty() == false) {
                File path = stack.pop();
                File[] classFiles = path.listFiles(new FileFilter() {
                    public boolean accept(File pathname) {
                        return pathname.isDirectory() || pathname.getName().endsWith(".class");
                    }
                });
                for (File subFile : classFiles) {
                    if (subFile.isDirectory()) {
                        stack.push(subFile);
                    } else {
                        // 文件名称
                        String className = subFile.getAbsolutePath();
                        className = className.substring(clazzPathLen, className.length() - 6);
                        className = className.replace(File.separatorChar, '.');
                        // 加载Class类
                        Class<?> clazz = Class.forName(className);
                        if (className.endsWith("Repository")) {
                            repositoryClasses.add(clazz);
                        } else if (className.endsWith("ServiceImpl")) {
                            serviceClasses.add(clazz);
                        }
                        System.out.println("读取应用程序类文件[class=" + className + "]");
                        if (className.equals(classFileName)) {
                            res = clazz;
                        }
                    }
                }
            }
        }
        autowiredReposotoryAndSevice(request);
        return res;
    }
private void autowiredReposotoryAndSevice(HttpServletRequest request) throws Exception {
    for (Class clazz : repositoryClasses) {
        registerBean(clazz,request);
    }
    repositoryClasses.clear();
    for (Class clazz : serviceClasses) {
        registerBean(clazz,request);
    }
    serviceClasses.clear();
}

private void registerBean(Class clazz,HttpServletRequest request) throws Exception {
    WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());
    DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context.getAutowireCapableBeanFactory();
    DataSource dataSource = (DataSource) factory.getBean("dataSource");
    Object bean = null;
    String name = clazz.getName();
    try {
        context.getBean(name);
    } catch (Exception e) {
        bean = factory.createBean(clazz, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
        if (name.contains("Repository")) {
            Field field = clazz.getDeclaredField("dataSource");
            field.setAccessible(true);
            field.set(bean, dataSource);
        }
        context.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(bean, name);
        factory.registerSingleton(name, bean);
    }
}

最坑的地方应该就是指定了文件读取class时经常会报找不到核心项目中依赖的class。

查了好久资料最终找到了这篇博客:

https://blog.csdn.net/briblue/article/details/54973413

最后通用反射当前线程的上下文加载器的父加载器,终于解决问题——基础薄弱,这块卡了很久。

Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);            boolean accessible = method.isAccessible();            try {                if (accessible == false) {                    method.setAccessible(true);                }                // 设置类加载器                URLClassLoader classLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader().getParent();            // 将当前类路径加入到类加载器中                method.invoke(classLoader, clazzPath.toURI().toURL());            } finally {                method.setAccessible(accessible);            }


关键词:quartz


验证码: