新疆后端项目
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
<?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.renkang</groupId>
|
||||
<artifactId>functional-modules</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>renkang-starter-batch</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-batch</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
package com.renkang.batch.configure;
|
||||
|
||||
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
|
||||
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
|
||||
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.springframework.batch.core.configuration.annotation.BatchConfigurer;
|
||||
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.batch.BatchDataSource;
|
||||
import org.springframework.boot.autoconfigure.batch.BatchDataSourceScriptDatabaseInitializer;
|
||||
import org.springframework.boot.autoconfigure.batch.BatchProperties;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.jdbc.support.JdbcTransactionManager;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/9
|
||||
*/
|
||||
@AutoConfiguration(
|
||||
before = {
|
||||
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class,
|
||||
DynamicDataSourceAutoConfiguration.class
|
||||
}
|
||||
)
|
||||
@EnableConfigurationProperties({RenkangBatchProperties.class, BatchProperties.class})
|
||||
@EnableBatchProcessing
|
||||
public class BatchAutoConfiguration {
|
||||
|
||||
private final BatchProperties batchProperties;
|
||||
|
||||
private final RenkangBatchProperties renkangBatchProperties;
|
||||
|
||||
private final DynamicDataSourceProperties dynamicDataSourceProperties;
|
||||
|
||||
public BatchAutoConfiguration(
|
||||
BatchProperties batchProperties,
|
||||
RenkangBatchProperties renkangBatchProperties,
|
||||
DynamicDataSourceProperties dynamicDataSourceProperties
|
||||
) {
|
||||
this.batchProperties = batchProperties;
|
||||
this.renkangBatchProperties = renkangBatchProperties;
|
||||
this.dynamicDataSourceProperties = dynamicDataSourceProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public PlatformTransactionManager bizTransactionManager(DataSource dataSource, TransactionManagerCustomizers transactionManagerCustomizers) {
|
||||
JdbcTransactionManager bizTransactionManager = new JdbcTransactionManager(dataSource);
|
||||
transactionManagerCustomizers.customize(bizTransactionManager);
|
||||
return bizTransactionManager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BatchConfigurer batchConfigurer(
|
||||
@BatchDataSource DataSource dataSource,
|
||||
TransactionManagerCustomizers transactionManagerCustomizers,
|
||||
@Qualifier("batchTaskExecutor") TaskExecutor taskExecutor) {
|
||||
return new CustomBatchConfigurer(batchProperties, dataSource, transactionManagerCustomizers, taskExecutor);
|
||||
}
|
||||
|
||||
@Bean("batchTaskExecutor")
|
||||
@ConditionalOnProperty(prefix = "renkang.batch", name = "async", havingValue = "true", matchIfMissing = false)
|
||||
public TaskExecutor asyncBatchTaskExecutor() {
|
||||
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
|
||||
taskExecutor.setCorePoolSize(16);
|
||||
taskExecutor.setThreadNamePrefix("Job-Pool-");
|
||||
taskExecutor.setMaxPoolSize(32);
|
||||
taskExecutor.setQueueCapacity(16);
|
||||
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
|
||||
taskExecutor.afterPropertiesSet();
|
||||
return taskExecutor;
|
||||
}
|
||||
|
||||
@Bean("batchTaskExecutor")
|
||||
@ConditionalOnProperty(prefix = "renkang.batch", name = "async", havingValue = "false", matchIfMissing = true)
|
||||
public TaskExecutor syncBatchTaskExecutor() {
|
||||
return new SyncTaskExecutor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public DataSource dataSource(List<DynamicDataSourceProvider> providers) {
|
||||
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(providers);
|
||||
dataSource.setPrimary(dynamicDataSourceProperties.getPrimary());
|
||||
dataSource.setStrict(dynamicDataSourceProperties.getStrict());
|
||||
dataSource.setStrategy(dynamicDataSourceProperties.getStrategy());
|
||||
dataSource.setP6spy(dynamicDataSourceProperties.getP6spy());
|
||||
dataSource.setSeata(dynamicDataSourceProperties.getSeata());
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "renkang.batch", name = "jdbc-url")
|
||||
@BatchDataSource
|
||||
public DataSource batchDataSource() {
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setJdbcUrl(renkangBatchProperties.getJdbcUrl());
|
||||
config.setUsername(renkangBatchProperties.getUsername());
|
||||
config.setPassword(renkangBatchProperties.getPassword());
|
||||
config.setDriverClassName(renkangBatchProperties.getDriverClassName());
|
||||
return new HikariDataSource(config);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BatchDataSourceScriptDatabaseInitializer batchDataSourceInitializer(
|
||||
DataSource dataSource,
|
||||
@BatchDataSource ObjectProvider<DataSource> batchDataSource,
|
||||
BatchProperties properties
|
||||
) {
|
||||
return new BatchDataSourceScriptDatabaseInitializer(batchDataSource.getIfAvailable(() -> dataSource),
|
||||
properties.getJdbc());
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.renkang.batch.configure;
|
||||
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
|
||||
import org.springframework.boot.autoconfigure.batch.BasicBatchConfigurer;
|
||||
import org.springframework.boot.autoconfigure.batch.BatchProperties;
|
||||
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/9
|
||||
*/
|
||||
public class CustomBatchConfigurer extends BasicBatchConfigurer {
|
||||
|
||||
private TaskExecutor taskExecutor;
|
||||
|
||||
/**
|
||||
* Create a new {@link BasicBatchConfigurer} instance.
|
||||
*
|
||||
* @param properties the batch properties
|
||||
* @param dataSource the underlying data source
|
||||
* @param transactionManagerCustomizers transaction manager customizers (or
|
||||
* {@code null})
|
||||
*/
|
||||
protected CustomBatchConfigurer(BatchProperties properties, DataSource dataSource, TransactionManagerCustomizers transactionManagerCustomizers) {
|
||||
super(properties, dataSource, transactionManagerCustomizers);
|
||||
}
|
||||
|
||||
public CustomBatchConfigurer(BatchProperties properties, DataSource dataSource, TransactionManagerCustomizers transactionManagerCustomizers, TaskExecutor taskExecutor) {
|
||||
super(properties, dataSource, transactionManagerCustomizers);
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JobLauncher createJobLauncher() throws Exception {
|
||||
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
|
||||
jobLauncher.setJobRepository(getJobRepository());
|
||||
if (taskExecutor != null) {
|
||||
jobLauncher.setTaskExecutor(taskExecutor);
|
||||
}
|
||||
jobLauncher.afterPropertiesSet();
|
||||
return jobLauncher;
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.renkang.batch.configure;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/9
|
||||
*/
|
||||
@ConfigurationProperties("renkang.batch")
|
||||
@Data
|
||||
public class RenkangBatchProperties {
|
||||
|
||||
private String jdbcUrl;
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private String driverClassName;
|
||||
|
||||
private Integer writeSize = 100;
|
||||
|
||||
private boolean async = false;
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.renkang.batch.job;
|
||||
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/11
|
||||
*/
|
||||
public abstract class AbstractSimpleTasklet implements Tasklet {
|
||||
|
||||
private ExecutionContext jobExecutionContext;
|
||||
|
||||
private ExecutionContext stepExecutionContext;
|
||||
|
||||
/**
|
||||
* Task执行方法
|
||||
*
|
||||
* @return 返回 {@link ExitStatus#COMPLETED} 视为成功,其他均视为失败,将执行 {@link AbstractSimpleTasklet#onError(Throwable)} 方法
|
||||
*/
|
||||
public abstract ExitStatus doExecute();
|
||||
|
||||
/**
|
||||
* 任务执行失败时,执行的方法,可以是 {@link AbstractSimpleTasklet#doExecute()} 方法
|
||||
* 返回了失败或产生异常
|
||||
*
|
||||
* @param throwable 若返回了失败,则 {@link Throwable} 为null
|
||||
* @throws Exception 抛出的异常,可以抛出自定义异常
|
||||
*/
|
||||
public abstract void onError(Throwable throwable) throws Exception;
|
||||
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||
setExecutionContext(contribution);
|
||||
try {
|
||||
ExitStatus exitStatus = doExecute();
|
||||
if (exitStatus == ExitStatus.COMPLETED) {
|
||||
return setComplete(contribution, chunkContext);
|
||||
} else {
|
||||
contribution.setExitStatus(exitStatus);
|
||||
onError(null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
onError(e);
|
||||
throw e;
|
||||
}
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
|
||||
public ExecutionContext getJobExecutionContext() {
|
||||
return jobExecutionContext;
|
||||
}
|
||||
|
||||
private void setJobExecutionContext(StepContribution contribution) {
|
||||
jobExecutionContext = contribution.getStepExecution()
|
||||
.getJobExecution()
|
||||
.getExecutionContext();
|
||||
}
|
||||
|
||||
public ExecutionContext getStepExecutionContext() {
|
||||
return stepExecutionContext;
|
||||
}
|
||||
|
||||
private void setStepExecutionContext(StepContribution contribution) {
|
||||
stepExecutionContext = contribution.getStepExecution()
|
||||
.getExecutionContext();
|
||||
}
|
||||
|
||||
private void setExecutionContext(StepContribution contribution) {
|
||||
setJobExecutionContext(contribution);
|
||||
setStepExecutionContext(contribution);
|
||||
}
|
||||
|
||||
private RepeatStatus setComplete(StepContribution contribution, ChunkContext chunkContext) {
|
||||
contribution.setExitStatus(ExitStatus.COMPLETED);
|
||||
chunkContext.setComplete();
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
com.renkang.batch.configure.BatchAutoConfiguration
|
||||
Reference in New Issue
Block a user