Spring Boot 2.0 Quartz - 使用非主数据源
Spring Boot 2.0 Quartz - Use non-primary datasource
我在我的应用程序中使用 Quartz 作为调度程序。尝试使用 Spring 引导 2.0 功能。我在配置中有 2 个不同的数据源。一个用于应用程序,另一个用于调度程序。如何使用非主数据源(在本例中为 schedulerDataSource)作为 Quartz 的数据源?请帮忙。
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>wlthint3client</artifactId>
<version>12.2.1.2</version>
<scope>system</scope>
<systemPath>C:/Oracle/products/mw_home/wlserver/server/lib/wlthint3client.jar</systemPath>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc</artifactId>
<version>7</version>
<scope>system</scope>
<systemPath>C:/Oracle/products/mw_home/oracle_common/modules/oracle.jdbc/ojdbc7.jar</systemPath>
</dependency>
</dependencies>
application.yml
spring:
quartz:
job-store-type: jdbc
jdbc:
initialize-schema: never
properties:
org:
quartz:
scheduler:
instanceName: ETL
threadPool:
threadCount: 50
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
tablePrefix: QRTZ_
useProperties: true
scheduler:
datasource:
url: jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=XXXXXX)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XXXX)))
username: scheduler
password: XXXXXX
driver-class-name: oracle.jdbc.OracleDriver
t3:
datasource:
url: jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=XXXXXX)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XXXXXX)))
username: app
password: XXXXXX
driver-class-name: oracle.jdbc.OracleDriver
AppDataSource.java
@Configuration
public class AppDataSource
{
@Bean
@Primary
@ConfigurationProperties("t3.datasource")
public DataSourceProperties t3DataSourceProperties()
{
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("t3.datasource")
public HikariDataSource t3DataSource()
{
return t3DataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Bean
@ConfigurationProperties("scheduler.datasource")
public DataSourceProperties schedulerDataSourceProperties()
{
return new DataSourceProperties();
}
@Bean
@ConfigurationProperties("scheduler.datasource")
public HikariDataSource schedulerDataSource()
{
return schedulerDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Bean
public PlatformTransactionManager schedulerTransactionManager()
{
final DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(schedulerDataSource());
return transactionManager;
}
}
Application.java
package com.aaa.t3.starter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import com.spdji.aaa.jms.JmsService;
@ComponentScan("com.aaa.t3")
@SpringBootApplication(exclude = { ActiveMQAutoConfiguration.class, JmxAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })
public class Application
{
public static void main(String[] args)
{
ApplicationContext context = SpringApplication.run(Application.class, args);
JmsService jmsService = (JmsService) context.getBean("jmsService");
jmsService.sendMessage();
/*String[] beans = context.getBeanDefinitionNames();
Arrays.stream(beans).sorted().forEach(System.out::println);*/
}
}
尝试使用 SchedulerFactoryBeanCustomizer 修改数据源,但它仍然引用主数据源。
@Configuration
public class SchedulerConfig
{
private DataSource dataSource;
@Autowired
public SchedulerConfig(@Qualifier("schedulerDataSource") DataSource dataSource)
{
this.dataSource = dataSource;
}
@Bean
public SchedulerFactoryBeanCustomizer schedulerFactoryBeanCustomizer()
{
return bean -> bean.setDataSource(dataSource);
}
}
已使用调试器验证。 SchedulerConfig 中自动装配的数据源是调度器数据源,但之后被覆盖了。在QuartzAutoConfiguration.quartzDataSourceInitializer中添加了断点并检查了数据源。这不是调度程序数据源。这已被主要数据源覆盖。 Quartz 自动配置覆盖 SchedulerFactoryBeanCustomizer 自定义。我已经打开 github.com/spring-projects/spring-boot/issues/12780 来修复它。
这是 spring-boot 中的错误。作为解决方法,我删除了 spring.quartz.job-store-type 属性,然后在定制器中配置了 DataSource 和 PlatformTransactionManager。请参考以下更新代码:
@Configuration
public class SchedulerConfig
{
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
@Autowired
public SchedulerConfig(@Qualifier("schedulerDataSource") DataSource dataSource, @Qualifier("schedulerTransactionManager") PlatformTransactionManager transactionManager)
{
this.dataSource = dataSource;
this.transactionManager = transactionManager;
}
@Bean
public SchedulerFactoryBeanCustomizer schedulerFactoryBeanCustomizer()
{
return bean ->
{
bean.setDataSource(dataSource);
bean.setTransactionManager(transactionManager);
};
}
}
您可以通过自己构建 SchedulerFactoryBean
来自定义数据源:
@Bean
public SchedulerFactoryBean schedulerFactory() {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
bean.setDataSource(schedulerDataSource());
return bean;
}
或者,在Spring Boot 2中,你可以使用SchedulerFactoryBeanCustomizer
。这将允许您自定义由自动配置器实例化的 bean,这可能会减少工作量。
@Configuration
public class SchedulerConfig {
DataSource dataSource;
@Autowired
public SchedulerConfig(@Qualifier("scheduler.datasource") DataSource dataSource) {
this.dataSource = dataSource;
}
@Bean
public SchedulerFactoryBeanCustomizer schedulerFactoryBeanCustomizer()
{
return bean -> bean.setDataSource(dataSource);
}
}
这是 spring-boot 中的错误。作为解决方法,我删除了 spring.quartz.job-store-type 属性,然后在定制器中配置了 DataSource 和 PlatformTransactionManager。请参考以下更新代码:
@Configuration
public class SchedulerConfig
{
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
@Autowired
public SchedulerConfig(@Qualifier("schedulerDataSource") DataSource dataSource, @Qualifier("schedulerTransactionManager") PlatformTransactionManager transactionManager)
{
this.dataSource = dataSource;
this.transactionManager = transactionManager;
}
@Bean
public SchedulerFactoryBeanCustomizer schedulerFactoryBeanCustomizer()
{
return bean ->
{
bean.setDataSource(dataSource);
bean.setTransactionManager(transactionManager);
};
}
}
我通过排除DataSourceAutoConfiguration.class
解决了这个问题
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class,
并自定义调度程序实例如下:
@Bean("qzDataSource")
@Qualifier("qzDataSource")
public HikariDataSource qzDataSource() {
return qzDataSourceProperties().initializeDataSourceBuilder()
.type(HikariDataSource.class).build();
}
@Bean
public PlatformTransactionManager quartzDataSourceTransactionManager(@Qualifier("qzDataSource") DataSource qzDataSource) {
final DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(qzDataSource);
return transactionManager;
}
@Bean
public SchedulerFactoryBean schedulerFactory(@Qualifier("qzDataSource") DataSource qzDataSource) {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
bean.setDataSource(qzDataSource);
bean.setTransactionManager(quartzDataSourceTransactionManager(qzDataSource));
return bean;
}
@Bean
public Scheduler scheduler() {
return schedulerFactory(qzDataSource()).getScheduler();
}
我的完整代码是https://github.com/guzhangyu/learn-spring-cloud/tree/master/springboot-quartz
我在我的应用程序中使用 Quartz 作为调度程序。尝试使用 Spring 引导 2.0 功能。我在配置中有 2 个不同的数据源。一个用于应用程序,另一个用于调度程序。如何使用非主数据源(在本例中为 schedulerDataSource)作为 Quartz 的数据源?请帮忙。
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>wlthint3client</artifactId>
<version>12.2.1.2</version>
<scope>system</scope>
<systemPath>C:/Oracle/products/mw_home/wlserver/server/lib/wlthint3client.jar</systemPath>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc</artifactId>
<version>7</version>
<scope>system</scope>
<systemPath>C:/Oracle/products/mw_home/oracle_common/modules/oracle.jdbc/ojdbc7.jar</systemPath>
</dependency>
</dependencies>
application.yml
spring:
quartz:
job-store-type: jdbc
jdbc:
initialize-schema: never
properties:
org:
quartz:
scheduler:
instanceName: ETL
threadPool:
threadCount: 50
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
tablePrefix: QRTZ_
useProperties: true
scheduler:
datasource:
url: jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=XXXXXX)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XXXX)))
username: scheduler
password: XXXXXX
driver-class-name: oracle.jdbc.OracleDriver
t3:
datasource:
url: jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=XXXXXX)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XXXXXX)))
username: app
password: XXXXXX
driver-class-name: oracle.jdbc.OracleDriver
AppDataSource.java
@Configuration
public class AppDataSource
{
@Bean
@Primary
@ConfigurationProperties("t3.datasource")
public DataSourceProperties t3DataSourceProperties()
{
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("t3.datasource")
public HikariDataSource t3DataSource()
{
return t3DataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Bean
@ConfigurationProperties("scheduler.datasource")
public DataSourceProperties schedulerDataSourceProperties()
{
return new DataSourceProperties();
}
@Bean
@ConfigurationProperties("scheduler.datasource")
public HikariDataSource schedulerDataSource()
{
return schedulerDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Bean
public PlatformTransactionManager schedulerTransactionManager()
{
final DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(schedulerDataSource());
return transactionManager;
}
}
Application.java
package com.aaa.t3.starter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import com.spdji.aaa.jms.JmsService;
@ComponentScan("com.aaa.t3")
@SpringBootApplication(exclude = { ActiveMQAutoConfiguration.class, JmxAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })
public class Application
{
public static void main(String[] args)
{
ApplicationContext context = SpringApplication.run(Application.class, args);
JmsService jmsService = (JmsService) context.getBean("jmsService");
jmsService.sendMessage();
/*String[] beans = context.getBeanDefinitionNames();
Arrays.stream(beans).sorted().forEach(System.out::println);*/
}
}
尝试使用 SchedulerFactoryBeanCustomizer 修改数据源,但它仍然引用主数据源。
@Configuration
public class SchedulerConfig
{
private DataSource dataSource;
@Autowired
public SchedulerConfig(@Qualifier("schedulerDataSource") DataSource dataSource)
{
this.dataSource = dataSource;
}
@Bean
public SchedulerFactoryBeanCustomizer schedulerFactoryBeanCustomizer()
{
return bean -> bean.setDataSource(dataSource);
}
}
已使用调试器验证。 SchedulerConfig 中自动装配的数据源是调度器数据源,但之后被覆盖了。在QuartzAutoConfiguration.quartzDataSourceInitializer中添加了断点并检查了数据源。这不是调度程序数据源。这已被主要数据源覆盖。 Quartz 自动配置覆盖 SchedulerFactoryBeanCustomizer 自定义。我已经打开 github.com/spring-projects/spring-boot/issues/12780 来修复它。
这是 spring-boot 中的错误。作为解决方法,我删除了 spring.quartz.job-store-type 属性,然后在定制器中配置了 DataSource 和 PlatformTransactionManager。请参考以下更新代码:
@Configuration
public class SchedulerConfig
{
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
@Autowired
public SchedulerConfig(@Qualifier("schedulerDataSource") DataSource dataSource, @Qualifier("schedulerTransactionManager") PlatformTransactionManager transactionManager)
{
this.dataSource = dataSource;
this.transactionManager = transactionManager;
}
@Bean
public SchedulerFactoryBeanCustomizer schedulerFactoryBeanCustomizer()
{
return bean ->
{
bean.setDataSource(dataSource);
bean.setTransactionManager(transactionManager);
};
}
}
您可以通过自己构建 SchedulerFactoryBean
来自定义数据源:
@Bean
public SchedulerFactoryBean schedulerFactory() {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
bean.setDataSource(schedulerDataSource());
return bean;
}
或者,在Spring Boot 2中,你可以使用SchedulerFactoryBeanCustomizer
。这将允许您自定义由自动配置器实例化的 bean,这可能会减少工作量。
@Configuration
public class SchedulerConfig {
DataSource dataSource;
@Autowired
public SchedulerConfig(@Qualifier("scheduler.datasource") DataSource dataSource) {
this.dataSource = dataSource;
}
@Bean
public SchedulerFactoryBeanCustomizer schedulerFactoryBeanCustomizer()
{
return bean -> bean.setDataSource(dataSource);
}
}
这是 spring-boot 中的错误。作为解决方法,我删除了 spring.quartz.job-store-type 属性,然后在定制器中配置了 DataSource 和 PlatformTransactionManager。请参考以下更新代码:
@Configuration
public class SchedulerConfig
{
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
@Autowired
public SchedulerConfig(@Qualifier("schedulerDataSource") DataSource dataSource, @Qualifier("schedulerTransactionManager") PlatformTransactionManager transactionManager)
{
this.dataSource = dataSource;
this.transactionManager = transactionManager;
}
@Bean
public SchedulerFactoryBeanCustomizer schedulerFactoryBeanCustomizer()
{
return bean ->
{
bean.setDataSource(dataSource);
bean.setTransactionManager(transactionManager);
};
}
}
我通过排除DataSourceAutoConfiguration.class
解决了这个问题@SpringBootApplication(exclude = DataSourceAutoConfiguration.class,
并自定义调度程序实例如下:
@Bean("qzDataSource")
@Qualifier("qzDataSource")
public HikariDataSource qzDataSource() {
return qzDataSourceProperties().initializeDataSourceBuilder()
.type(HikariDataSource.class).build();
}
@Bean
public PlatformTransactionManager quartzDataSourceTransactionManager(@Qualifier("qzDataSource") DataSource qzDataSource) {
final DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(qzDataSource);
return transactionManager;
}
@Bean
public SchedulerFactoryBean schedulerFactory(@Qualifier("qzDataSource") DataSource qzDataSource) {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
bean.setDataSource(qzDataSource);
bean.setTransactionManager(quartzDataSourceTransactionManager(qzDataSource));
return bean;
}
@Bean
public Scheduler scheduler() {
return schedulerFactory(qzDataSource()).getScheduler();
}
我的完整代码是https://github.com/guzhangyu/learn-spring-cloud/tree/master/springboot-quartz