覆盖 spring-boot 自动配置
Overwriting spring-boot autoconfiguration
我对 spring-boot 在覆盖特定自动配置时的行为有点困惑。
我喜欢部分覆盖 BatchAutoConfiguration,但我想,我的问题并不特定于 BatchAutoConfiguration。
其实我只是想"overwrite"这个class的两个方法:
public BatchDatabaseInitializer batchDatabaseInitializer()
和 public ExitCodeGenerator jobExecutionExitCodeGenerator()
.
因此,我编写了以下代码:
包裹 ch.test.autoconfig.autoconfigure;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration;
import org.springframework.boot.autoconfigure.batch.BatchDatabaseInitializer;
import org.springframework.boot.autoconfigure.batch.BatchProperties;
import org.springframework.boot.autoconfigure.batch.JobExecutionExitCodeGenerator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcOperations;
import javax.sql.DataSource;
/**
* I'm using the same annotations as defined in BatchAutoConfiguration...
*/
@Configuration
@ConditionalOnClass({ JobLauncher.class, DataSource.class, JdbcOperations.class })
@AutoConfigureAfter(HibernateJpaAutoConfiguration.class)
@ConditionalOnBean(JobLauncher.class)
@EnableConfigurationProperties(BatchProperties.class)
// ... but I add @AutoConfigureBefore(BatchAutoConfiguration.class) to take precedence over BatchAutoConfiguration
@AutoConfigureBefore(BatchAutoConfiguration.class)
public class JavabatchAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(DataSource.class)
public BatchDatabaseInitializer batchDatabaseInitializer() {
System.out.println("Entering overwritten batchDatabaseInitializer");
return new BatchDatabaseInitializer();
}
@Bean
@ConditionalOnMissingBean
public ExitCodeGenerator jobExecutionExitCodeGenerator() {
System.out.println("Entering overwritten jobExecutionExitCodeGenerator");
return new JobExecutionExitCodeGenerator();
}
}
如代码中所述,我对 class 和方法使用完全相同的注释,因为它们在 BatchAutoConfiguration.class
中定义。
唯一的例外是添加 @AutoConfigureBefore(BatchAutoConfiguration.class)
。因为这应该优先于 BatchAutoConfiguration,我假设,这有点像 "overwrite" 原来的。
为了测试,我使用以下 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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ch.test.autoconfig</groupId>
<artifactId>auto_config_test</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
</dependencies>
</project>
我正在使用这个简单的工作和一个主要方法:
package ch.test.autoconfig;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
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.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
/**
* Created by U802552 on 01.06.2015.
*/
@SpringBootApplication
@EnableBatchProcessing
public class MainJob {
@Autowired
private JobBuilderFactory jobs;
@Autowired
private StepBuilderFactory steps;
@Bean
protected Tasklet tasklet() {
return new Tasklet() {
public RepeatStatus execute(StepContribution contribution,
ChunkContext context) {
return RepeatStatus.FINISHED;
}
};
}
@Bean
public Job job() throws Exception {
return this.jobs.get("job").start(step1()).build();
}
@Bean
protected Step step1() throws Exception {
return this.steps.get("step1").tasklet(tasklet()).build();
}
public static void main(String[] args) throws Exception {
// switch on Auto-Configuration-Report
System.setProperty("debug","true");
SpringApplication.run(MainJob.class, args);
}
}
我希望调用我的两个覆盖方法,但正如自动配置报告所述,我的 JavabatchAutoConfiguration class 有一个
"negative match" 因为缺少 "JobLauncher" 个实例。正如报告还指出的那样,原始 BatchAutoConfiguration class 与相同的 ConditionalOnBean
检查具有肯定的匹配。
如果我在 class 上评论 @ConditionalOnBean(JobLauncher.class)
并在 batchDatabaseInitializer
方法上评论 @ConditionalOnBean(DataSource.class)
,一切都会按预期进行。
有人对此行为有解释吗?
谢谢
汉舍格
您正在变得复杂。您唯一需要做的就是创建一个配置来定义您要使用的 2 个特定 bean。
@Configuration
public class MyBatchConfiguration {
@Bean
public ExitCodeGenerator myExitCodeGenerator() {
return new MyExitCodeGenerator();
}
@Bean
public BatchDatabaseInitializer myBatchDatabaseInitializer() {
return new MyBatchDatabaseInitializer();
}
}
这就是你所需要的。
我认为 Hansjörg 和 M. 是对的。 "methode name" 应该与特定的自动配置使用的相同。
原因:我不确定,如果 ApplicationContext 中存在相同类型是 spring 省略该类型创建的唯一标准。至少限定符必须相同?!
我对 spring-boot 在覆盖特定自动配置时的行为有点困惑。
我喜欢部分覆盖 BatchAutoConfiguration,但我想,我的问题并不特定于 BatchAutoConfiguration。
其实我只是想"overwrite"这个class的两个方法:
public BatchDatabaseInitializer batchDatabaseInitializer()
和 public ExitCodeGenerator jobExecutionExitCodeGenerator()
.
因此,我编写了以下代码: 包裹 ch.test.autoconfig.autoconfigure;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration;
import org.springframework.boot.autoconfigure.batch.BatchDatabaseInitializer;
import org.springframework.boot.autoconfigure.batch.BatchProperties;
import org.springframework.boot.autoconfigure.batch.JobExecutionExitCodeGenerator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcOperations;
import javax.sql.DataSource;
/**
* I'm using the same annotations as defined in BatchAutoConfiguration...
*/
@Configuration
@ConditionalOnClass({ JobLauncher.class, DataSource.class, JdbcOperations.class })
@AutoConfigureAfter(HibernateJpaAutoConfiguration.class)
@ConditionalOnBean(JobLauncher.class)
@EnableConfigurationProperties(BatchProperties.class)
// ... but I add @AutoConfigureBefore(BatchAutoConfiguration.class) to take precedence over BatchAutoConfiguration
@AutoConfigureBefore(BatchAutoConfiguration.class)
public class JavabatchAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(DataSource.class)
public BatchDatabaseInitializer batchDatabaseInitializer() {
System.out.println("Entering overwritten batchDatabaseInitializer");
return new BatchDatabaseInitializer();
}
@Bean
@ConditionalOnMissingBean
public ExitCodeGenerator jobExecutionExitCodeGenerator() {
System.out.println("Entering overwritten jobExecutionExitCodeGenerator");
return new JobExecutionExitCodeGenerator();
}
}
如代码中所述,我对 class 和方法使用完全相同的注释,因为它们在 BatchAutoConfiguration.class
中定义。
唯一的例外是添加 @AutoConfigureBefore(BatchAutoConfiguration.class)
。因为这应该优先于 BatchAutoConfiguration,我假设,这有点像 "overwrite" 原来的。
为了测试,我使用以下 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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ch.test.autoconfig</groupId>
<artifactId>auto_config_test</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
</dependencies>
</project>
我正在使用这个简单的工作和一个主要方法:
package ch.test.autoconfig;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
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.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
/**
* Created by U802552 on 01.06.2015.
*/
@SpringBootApplication
@EnableBatchProcessing
public class MainJob {
@Autowired
private JobBuilderFactory jobs;
@Autowired
private StepBuilderFactory steps;
@Bean
protected Tasklet tasklet() {
return new Tasklet() {
public RepeatStatus execute(StepContribution contribution,
ChunkContext context) {
return RepeatStatus.FINISHED;
}
};
}
@Bean
public Job job() throws Exception {
return this.jobs.get("job").start(step1()).build();
}
@Bean
protected Step step1() throws Exception {
return this.steps.get("step1").tasklet(tasklet()).build();
}
public static void main(String[] args) throws Exception {
// switch on Auto-Configuration-Report
System.setProperty("debug","true");
SpringApplication.run(MainJob.class, args);
}
}
我希望调用我的两个覆盖方法,但正如自动配置报告所述,我的 JavabatchAutoConfiguration class 有一个
"negative match" 因为缺少 "JobLauncher" 个实例。正如报告还指出的那样,原始 BatchAutoConfiguration class 与相同的 ConditionalOnBean
检查具有肯定的匹配。
如果我在 class 上评论 @ConditionalOnBean(JobLauncher.class)
并在 batchDatabaseInitializer
方法上评论 @ConditionalOnBean(DataSource.class)
,一切都会按预期进行。
有人对此行为有解释吗?
谢谢 汉舍格
您正在变得复杂。您唯一需要做的就是创建一个配置来定义您要使用的 2 个特定 bean。
@Configuration
public class MyBatchConfiguration {
@Bean
public ExitCodeGenerator myExitCodeGenerator() {
return new MyExitCodeGenerator();
}
@Bean
public BatchDatabaseInitializer myBatchDatabaseInitializer() {
return new MyBatchDatabaseInitializer();
}
}
这就是你所需要的。
我认为 Hansjörg 和 M. 是对的。 "methode name" 应该与特定的自动配置使用的相同。
原因:我不确定,如果 ApplicationContext 中存在相同类型是 spring 省略该类型创建的唯一标准。至少限定符必须相同?!