Spring boot下使用Quartz--多实例解决方案

来源:互联网 发布:kol粉丝数据分析 编辑:程序博客网 时间:2024/05/23 11:14

公司项目在发到生产后启了2个实例,导致调度同时执行,起先使用了事务隔离和数据库控制执行版本,不过不是很好,不是最佳的解决方案,查了资料Quartz本身支持多实例,稍加配置即可。
此篇文章在Spring boot下使用Quartz 基础上进行修改,建议阅读完之后再看
1. 下载quartz
官网
我用的是2.2.3

2. 创建表
下载下来tar包后解压后打开
quartz-2.2.3\docs\dbTables
找到你需要的数据库sql文件执行
例如:我用的是PG,执行的是tables_postgres.sql文件里的sql

3. 新增配置文件

import java.util.Properties;import javax.sql.DataSource;import org.quartz.Scheduler;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.autoconfigure.AutoConfigureAfter;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.quartz.SchedulerFactoryBean;@Configuration@AutoConfigureAfter(DruidAutoConfiguration.class)//在该类之后执行,为了使用dataSource,(DruidAutoConfiguration是连接数据库配置文件,参考文末)public class QuartzConfig {    @Autowired    private DataSource dataSource;    /**     * 设置属性     */    private Properties quartzProperties() {        Properties prop = new Properties();        prop.put("org.quartz.scheduler.instanceName", "quartzScheduler");        prop.put("org.quartz.scheduler.instanceId", "AUTO");        prop.put("org.quartz.scheduler.skipUpdateCheck", "true");        prop.put("org.quartz.scheduler.jmx.export", "true");        // Configure JobStore        // #JobDataMaps是否都为String类型        // prop.put("org.quartz.jobStore.useProperties", "true");//不要用,报错        prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");        // PG专用        prop.put("org.quartz.jobStore.driverDelegateClass",                "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate");        // job注入datasource        // prop.put("org.quartz.jobStore.dataSource","druid");//#使用JNDI数据源的时候,数据源的名字        prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");        // 开启集群        // #ture则此实例需要参加到集群中        prop.put("org.quartz.jobStore.isClustered", "true");        // #调度实例失效的检查时间间隔        prop.put("org.quartz.jobStore.clusterCheckinInterval", "20000");        // prop.put("org.quartz.jobStore.dataSource", "myDS");        // 这是 JobStore 能处理的错过触发的 Trigger 的最大数量        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");        // #容许的最大作业延长时间        prop.put("org.quartz.jobStore.misfireThreshold", "60000");        //值为 true 时告知 Quartz(当使用 JobStoreTX 或 CMT)         //调用 JDBC 连接的 setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE) 方法        //这有助于阻止某些数据库在高负载和长时间事物时锁的超时。        prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");        prop.put("org.quartz.jobStore.selectWithLockSQL",                "SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE");        // Configure ThreadPool        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");        prop.put("org.quartz.threadPool.threadCount", "50");        prop.put("org.quartz.threadPool.threadPriority", "5");        prop.put("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread",                "true");        /*         * prop.put("org.quartz.dataSource.myDS.driver", myDSDriver);         * prop.put("org.quartz.dataSource.myDS.URL", myDSURL);         * prop.put("org.quartz.dataSource.myDS.user", myDSUser);         * prop.put("org.quartz.dataSource.myDS.password", myDSPassword);         * System.out.println("myDSMaxConnections:" + myDSMaxConnections);         * prop.put("org.quartz.dataSource.myDS.maxConnections",         * myDSMaxConnections);         */        prop.put("org.quartz.plugin.triggHistory.class",                "org.quartz.plugins.history.LoggingJobHistoryPlugin");        prop.put("org.quartz.plugin.shutdownhook.class",                "org.quartz.plugins.management.ShutdownHookPlugin");        prop.put("org.quartz.plugin.shutdownhook.cleanShutdown", "true");        return prop;    }    @Bean    public SchedulerFactoryBean schedulerFactoryBean() {//得到schedulerFactoryBean,并注入多实例参数        SchedulerFactoryBean factory = new SchedulerFactoryBean();        // this allows to update triggers in DB when updating settings in config        // file:        // 用于quartz集群,QuartzScheduler        // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了        factory.setOverwriteExistingJobs(true);        // 用于quartz集群,加载quartz数据源        factory.setDataSource(dataSource);        // QuartzScheduler 延时启动,应用启动完10秒后 QuartzScheduler 再启动        factory.setStartupDelay(10);        // 用于quartz集群,加载quartz数据源配置        factory.setQuartzProperties(quartzProperties());        factory.setAutoStartup(true);        // applicationContextSchedulerContextKey:        // 是org.springframework.scheduling.quartz.SchedulerFactoryBean这个类中把spring上下        // 文以key/value的方式存放在了quartz的上下文中了,可以用applicationContextSchedulerContextKey所定义的key得到对应的spring上下文        // factory.setApplicationContextSchedulerContextKey("applicationContext");        // factory.setConfigLocation(new        // FileSystemResource(this.getClass().getResource("/quartz.properties").getPath()));        return factory;    }    //得到scheduler    @Bean    public Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) {        return schedulerFactoryBean.getScheduler();    }}

4. 修改ServiceImpl实现类的scheduler注入方式
一些调度器操作

@Service@Slf4jpublic class SchedulerServiceImpl implements SchedulerService {    @Autowired    private  Scheduler scheduler;    内容省略,跟上一遍文章一样。}

文末. (仅供参考)
连接数据库的配置文件
DruidAutoConfiguration.java

import java.sql.SQLException;import javax.sql.DataSource;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.autoconfigure.AutoConfigureBefore;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import com.alibaba.druid.pool.DruidDataSource;@Configuration@EnableConfigurationProperties(DruidProperties.class)@ConditionalOnClass(DruidDataSource.class)@ConditionalOnProperty(prefix = "druid", name = "url")@AutoConfigureBefore(DataSourceAutoConfiguration.class)public class DruidAutoConfiguration {    @Autowired    private DruidProperties properties;    @Bean    public DataSource dataSource() {        System.out.println(DataConverterUtil.object2Json(properties));        System.out.println(DataConverterUtil.object2Json(properties));        System.out.println(DataConverterUtil.object2Json(properties));        System.out.println(DataConverterUtil.object2Json(properties));        DruidDataSource dataSource = new DruidDataSource();        dataSource.setUrl(properties.getUrl());        dataSource.setUsername(properties.getUsername());        dataSource.setPassword(properties.getPassword());        if (properties.getInitialSize() > 0) {            dataSource.setInitialSize(properties.getInitialSize());        }        if (properties.getMinIdle() > 0) {            dataSource.setMinIdle(properties.getMinIdle());        }        if (properties.getMaxActive() > 0) {            dataSource.setMaxActive(properties.getMaxActive());        }        dataSource.setTestOnBorrow(properties.isTestOnBorrow());        try {            dataSource.init();        } catch (SQLException e) {            throw new RuntimeException(e);        }        return dataSource;    }}

DruidProperties .java

import org.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties(prefix = "druid")public class DruidProperties {    private String url;    private String username;    private String password;    private String driverClass;    private int     maxActive;    private int     minIdle;    private int     initialSize;    private boolean testOnBorrow;    public String getUrl() {        return url;    }    public void setUrl(String url) {        this.url = url;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }    public String getDriverClass() {        return driverClass;    }    public void setDriverClass(String driverClass) {        this.driverClass = driverClass;    }    public int getMaxActive() {        return maxActive;    }    public void setMaxActive(int maxActive) {        this.maxActive = maxActive;    }    public int getMinIdle() {        return minIdle;    }    public void setMinIdle(int minIdle) {        this.minIdle = minIdle;    }    public int getInitialSize() {        return initialSize;    }    public void setInitialSize(int initialSize) {        this.initialSize = initialSize;    }    public boolean isTestOnBorrow() {        return testOnBorrow;    }    public void setTestOnBorrow(boolean testOnBorrow) {        this.testOnBorrow = testOnBorrow;    }}

application.properties

## 需要修改数据库连接信息druid.url=jdbc:postgresql://11.11.11.11:7443/testdruid.driver-class=org.postgresql.Driverdruid.username=testdatadruid.password=yang1234druid.initial-size=1druid.min-idle=1druid.max-active=20druid.test-on-borrow=true

喜欢请点赞,不懂请留言^^

原创粉丝点击