如何解决考虑在您的配置中定义一个“org.springframework.transaction.jta.JtaTransactionManager”类型的 bean
我正在使用 spring 云任务和 spring 批处理库开发一个 spring 云任务应用程序。我还创建了一个包含 spring 云任务和 spring 批处理配置的 spring 启动库,并将该库添加为依赖于 spring 云任务的项目。运行应用程序时出现以下错误
Consider defining a bean of type 'org.springframework.transaction.jta.JtaTransactionManager' in your configuration.
主类:
import com.batch.common.config.batchcommonconfig.CronJobConfig;
import com.batch.common.config.batchcommonconfig.DbConfig;
import com.batch.common.config.batchcommonconfig.TaskJobConfig;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.cloud.task.configuration.EnableTask;
import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
@SpringBootApplication
@EnableBatchProcessing
@EnableTask
@EnableAutoConfiguration(exclude = {SimpleTaskAutoConfiguration.class,DataSourceAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
public class SpringBatchApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBatchApplication.class,args);
}
}
DemoCronJobConfiguration 类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.*;
import org.springframework.batch.core.job.SimpleJob;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.tasklet.taskletStep;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.jta.JtaTransactionManager;
import javax.sql.DataSource;
@Configuration
@Import({CronJobConfig.class,TaskJobConfig.class,DbConfig.class})
public class DemoCronJobConfiguration {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Qualifier("h2DataSource")
private DataSource h2DataSource;
@Autowired
private JtaTransactionManager transactionManager;
@Bean
public Job demoJob(@Autowired JobRepository batchJobRepository) {
SimpleJob job = new SimpleJob("demoJob");
String runParameter = "run.id";
job.setSteps(java.util.Arrays.asList(demoJobStep(batchJobRepository)));
job.setJobRepository(batchJobRepository);
job.setJobParametersIncrementer(new JobParametersIncrementer() {
@Override
public JobParameters getNext(JobParameters parameters) {
if (parameters==null || parameters.isEmpty()) {
return new JobParametersBuilder().addLong(runParameter,1L).toJobParameters();
}
long id = parameters.getLong(runParameter,1L) + 1;
return new JobParametersBuilder().addLong(runParameter,id).toJobParameters();
}
});
logger.info("------job instance created-------");
return job;
}
@Bean
public Step demoJobStep(@Autowired JobRepository batchJobRepository) {
DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
attribute.setTimeout(2000);
taskletStep step = new taskletStep("demoJobStep");
step.settasklet(generatetasklet());
step.setJobRepository(batchJobRepository);
transactionManager.setAllowCustomIsolationLevels(true);
step.setTransactionManager(transactionManager);
step.setTransactionAttribute(attribute);
return step;
}
@Bean
public DemoCronJobtasklet generatetasklet(){
return new DemoCronJobtasklet();
}
}
DemoCronJobtasklet 类:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.repeat.RepeatStatus;
import org.springframework.stereotype.Component;
@Component
public class DemoCronJobtasklet implements tasklet {
private static Logger logger= LoggerFactory.getLogger(DemoCronJobtasklet.class);
@Override
public RepeatStatus execute(StepContribution stepContribution,ChunkContext chunkContext) throws Exception {
logger.info("hello demo job");
return RepeatStatus.FINISHED;
}
}
批量应用项目 pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.batch.application</groupId>
<artifactId>batch-application</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>batch-application</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-task</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.batch.common.config</groupId>
<artifactId>batch-common-config</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-dependencies</artifactId>
<version>2.2.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>repackage</id>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
批量通用库类:
CronJobConfig 类:
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.target.AbstractLazyCreationTargetSource;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
import org.springframework.batch.core.configuration.support.MapJobRegistry;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.explore.support.JobExplorerfactorybean;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.launch.support.SimpleJobOperator;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.JobRepositoryfactorybean;
import org.springframework.batch.support.transaction.ResourcelesstransactionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.batch.BatchProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;
import javax.sql.DataSource;
import java.util.concurrent.atomic.atomicreference;
@EnableConfigurationProperties(BatchProperties.class)
@Configuration
public class CronJobConfig {
Logger logger = LoggerFactory.getLogger(this.getClass());
private boolean initialized = false;
@Bean
public JobOperator jobOperator(final JobLauncher jobLauncher,final JobExplorer jobExplorer,final JobRepository jobRepository,final JobRegistry jobRegistry) {
SimpleJobOperator simpleJobOperator = new SimpleJobOperator();
simpleJobOperator.setJobExplorer(jobExplorer);
simpleJobOperator.setJobLauncher(jobLauncher);
simpleJobOperator.setJobRepository(jobRepository);
simpleJobOperator.setJobRegistry(jobRegistry);
return simpleJobOperator;
}
@Bean
public JobExplorerfactorybean jobExplorer(@Qualifier("h2DataSource") final DataSource dataSource) {
JobExplorerfactorybean jobExplorerfactorybean = new JobExplorerfactorybean();
jobExplorerfactorybean.setDataSource(dataSource);
jobExplorerfactorybean.setTablePrefix("BATCH_");
return jobExplorerfactorybean;
}
@Bean
public MapJobRegistry jobRegistry() {
return new MapJobRegistry();
}
@Bean
public JobRegistryBeanPostProcessor jobRegisterBeanPostProcess(final JobRegistry jobRegistry) {
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry);
return jobRegistryBeanPostProcessor;
}
@Bean
public JobLauncher jobLauncher(JobRepository jobRepository) throws Exception {
SimpleJobLauncher launcher = new SimpleJobLauncher();
launcher.setJobRepository(jobRepository);
launcher.afterPropertiesSet();
return launcher;
}
@Bean
public JobRepository jobRepository(@Qualifier("h2DataSource") DataSource dataSource,@Qualifier("transactionManager") JtaTransactionManager transactionManager) throws Exception {
JobRepositoryfactorybean jobRepo = new JobRepositoryfactorybean();
jobRepo.setDataSource(dataSource);
jobRepo.setTransactionManager(transactionManager);
transactionManager.setAllowCustomIsolationLevels(true);
jobRepo.setTablePrefix("BATCH_");
return jobRepo.getJobRepository();
}
protected void initialize() throws Exception {
if (!this.initialized) {
this.initialized = true;
}
}
private class ReferenceTargetSource<T> extends AbstractLazyCreationTargetSource {
private atomicreference<T> reference;
public ReferenceTargetSource(atomicreference<T> reference) {
this.reference = reference;
}
protected Object createObject() throws Exception {
CronJobConfig.this.initialize();
return this.reference.get();
}
}
private class PassthruAdvice implements MethodInterceptor {
private PassthruAdvice() {
}
public Object invoke(MethodInvocation invocation) throws Throwable {
return invocation.proceed();
}
}
}
DbConfig 类:
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.jta.JtaTransactionManager;
@Configuration
@EnableJpaRepositories(
transactionManagerRef = "transactionManager",basePackages = {"com.batch.common.config.batchcommonconfig"}
)
public class DbConfig {
public DbConfig() {
}
@ConfigurationProperties(
prefix = "spring.datasource"
)
@Bean
@Primary
@DependsOn({"transactionManager"})
public DataSource h2DataSource() {
return DataSourceBuilder.create().url("jdbc:h2:mem:testdb").username("sa").password("").driverClassName("org.h2.Driver").build();
}
private Properties jpaHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect","org.hibernate.dialect.H2Dialect");
properties.put("hibernate.show_sql",false);
return properties;
}
@Bean(
name = {"transactionManager"}
)
public JtaTransactionManager transactionManager() {
return new JtaTransactionManager();
}
}
TaskJobConfig 类:
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.task.configuration.DefaultTaskConfigurer;
import org.springframework.cloud.task.configuration.TaskConfigurer;
import org.springframework.cloud.task.repository.TaskExplorer;
import org.springframework.cloud.task.repository.TaskNameResolver;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.cloud.task.repository.support.SimpleTaskNameResolver;
import org.springframework.cloud.task.repository.support.TaskRepositoryInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.CollectionUtils;
import javax.annotation.postconstruct;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.Collection;
@Configuration
@EnableTransactionManagement
@EnableConfigurationProperties({CustomTaskProperties.class})
public class TaskJobConfig {
protected static final Log logger = LogFactory.getLog(TaskJobConfig.class);
@Autowired(
required = false
)
private Collection<DataSource> dataSources;
@Autowired
private ConfigurableApplicationContext context;
@Autowired(
required = false
)
private ApplicationArguments applicationArguments;
@Bean
@Primary
public CustomTaskProperties taskProperties(){
return new CustomTaskProperties();
}
private boolean initialized = false;
private TaskRepository taskRepository;
private TaskExplorer taskExplorer;
public TaskJobConfig() {
/***
* Do nothing
* */
}
@Bean
public TaskRepository taskRepository() {
return this.taskRepository;
}
@Bean
public TaskExplorer taskExplorer() {
return this.taskExplorer;
}
@Bean
public TaskNameResolver taskNameResolver() {
return new SimpleTaskNameResolver();
}
@Bean
public TaskRepositoryInitializer taskRepositoryInitializer() {
this.taskProperties().setTablePrefix("TASK_");
this.taskProperties().setinitializeEnabled(true);
TaskRepositoryInitializer taskRepositoryInitializer = new TaskRepositoryInitializer(this.taskProperties());
DataSource initializerDataSource = this.getDefaultConfigurer().getTaskDataSource();
if (initializerDataSource != null) {
taskRepositoryInitializer.setDataSource(initializerDataSource);
}
return taskRepositoryInitializer;
}
@postconstruct
protected void initialize() {
if (!this.initialized) {
TaskConfigurer taskConfigurer = this.getDefaultConfigurer();
logger.debug(String.format("Using %s TaskConfigurer",taskConfigurer.getClass().getName()));
this.taskRepository = taskConfigurer.getTaskRepository();
this.taskExplorer = taskConfigurer.getTaskExplorer();
this.initialized = true;
}
}
private TaskConfigurer getDefaultConfigurer() {
this.taskProperties().setTablePrefix("TASK_");
this.taskProperties().setinitializeEnabled(true);
this.verifyEnvironment();
int configurers = this.context.getBeanNamesForType(TaskConfigurer.class).length;
if (configurers >= 1) {
if (configurers == 1) {
return (TaskConfigurer)this.context.getBean(TaskConfigurer.class);
} else {
throw new IllegalStateException("Expected one TaskConfigurer but found " + configurers);
}
} else {
DefaultTaskConfigurer taskConfigurer;
if (!CollectionUtils.isEmpty(this.dataSources) && this.dataSources.size() == 1) {
taskConfigurer = new DefaultTaskConfigurer((DataSource)this.dataSources.iterator().next(),this.taskProperties().getTablePrefix(),this.context);
} else {
taskConfigurer = new DefaultTaskConfigurer(this.taskProperties().getTablePrefix());
}
this.context.getbeanfactory().registerSingleton("taskConfigurer",taskConfigurer);
return taskConfigurer;
}
}
private void verifyEnvironment() {
int configurers = this.context.getBeanNamesForType(TaskConfigurer.class).length;
long dataSourceCount = Arrays.stream(this.context.getBeanNamesForType(DataSource.class)).filter((name) -> {
return !ScopedProxyUtils.isScopedTarget(name);
}).count();
if (configurers == 0 && dataSourceCount > 1L) {
throw new IllegalStateException("To use the default TaskConfigurer the context must contain no more than one DataSource,found " + dataSourceCount);
}
}
}
CustomTaskConfigurer 类:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.task.configuration.DefaultTaskConfigurer;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
@Component
public class CustomTaskConfigurer extends DefaultTaskConfigurer {
@Autowired
public CustomTaskConfigurer(@Qualifier("h2DataSource") DataSource dataSource) {
super(dataSource);
}
}
CustomTaskProperties 类:
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.task.configuration.TaskProperties;
@ConfigurationProperties(prefix = "spring.cloud.task")
public class CustomTaskProperties extends TaskProperties {
private static final int DEFAULT_CHECK_INTERVAL = 500;
private static final Log logger = LogFactory.getLog(TaskProperties.class);
private String externalExecutionId;
private Long executionid;
private Long parentExecutionId;
private String tablePrefix = "TASK_";
private Boolean closecontextEnabled = false;
private boolean singleInstanceEnabled = false;
private int singleInstanceLockTtl = 2147483647;
private int singleInstanceLockCheckInterval = 500;
private Boolean initializeEnabled;
public CustomTaskProperties() {
}
public String getExternalExecutionId() {
return this.externalExecutionId;
}
public void setExternalExecutionId(String externalExecutionId) {
this.externalExecutionId = externalExecutionId;
}
public Long getExecutionid() {
return this.executionid;
}
public void setExecutionid(Long executionid) {
this.executionid = executionid;
}
public Boolean getClosecontextEnabled() {
return this.closecontextEnabled;
}
public void setClosecontextEnabled(Boolean closecontextEnabled) {
this.closecontextEnabled = closecontextEnabled;
}
public String getTablePrefix() {
return this.tablePrefix;
}
public void setTablePrefix(String tablePrefix) {
this.tablePrefix = tablePrefix;
}
public Long getParentExecutionId() {
return this.parentExecutionId;
}
public void setParentExecutionId(Long parentExecutionId) {
this.parentExecutionId = parentExecutionId;
}
public boolean getSingleInstanceEnabled() {
return this.singleInstanceEnabled;
}
public void setSingleInstanceEnabled(boolean singleInstanceEnabled) {
this.singleInstanceEnabled = singleInstanceEnabled;
}
public int getSingleInstanceLockTtl() {
return this.singleInstanceLockTtl;
}
public void setSingleInstanceLockTtl(int singleInstanceLockTtl) {
this.singleInstanceLockTtl = singleInstanceLockTtl;
}
public int getSingleInstanceLockCheckInterval() {
return this.singleInstanceLockCheckInterval;
}
public void setSingleInstanceLockCheckInterval(int singleInstanceLockCheckInterval) {
this.singleInstanceLockCheckInterval = singleInstanceLockCheckInterval;
}
public Boolean isInitializeEnabled() {
return this.initializeEnabled;
}
public void setinitializeEnabled(Boolean initializeEnabled) {
this.initializeEnabled = initializeEnabled;
}
}
batch-common-configuration pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.batch.common.config</groupId>
<artifactId>batch-common-config</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>batch-common-config</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-task</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-dependencies</artifactId>
<version>2.2.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
错误:
2021-02-23 14:05:57.056 ERROR 28492 --- [ restartedMain] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION Failed TO START
***************************
Description:
Field transactionManager in com.batch.application.batchapplication.DemoCronJobConfiguration required a bean of type 'org.springframework.transaction.jta.JtaTransactionManager' that Could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.springframework.transaction.jta.JtaTransactionManager' in your configuration.
Process finished with exit code 0
当我将这两个项目作为一个项目编写时,它可以正常工作,没有任何错误。它无法创建属于我在外部添加的批处理通用配置 jar 的 bean。我怎样才能克服这个问题?我在等你的建议。从现在开始谢谢你。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。