2015-06-01 289 views
0

當覆蓋特定的自動配置時,我對彈簧引導的行爲有些困惑。覆蓋彈簧引導自動配置

我喜歡部分覆蓋BatchAutoConfiguration,但我想,我的問題不是特定於BatchAutoConfiguration。其實我只是想「覆蓋」這個類的兩種方法: public BatchDatabaseInitializer batchDatabaseInitializer()public ExitCodeGenerator jobExecutionExitCodeGenerator()

因此,我寫了如下代碼: package ch.test.autoconfig.autocon fig;

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(); 
    } 
} 

正如在代碼中提到,我使用的是完全相同的annotions的類和方法,它們是在BatchAutoConfiguration.class definend。 唯一的例外是加入@AutoConfigureBefore(BatchAutoConfiguration.class)。因爲這應該優先於BatchAutoConfiguration,所以我認爲這樣會「覆蓋」原始內容。

爲了測試,我使用了下面的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); 
    } 
} 

我希望,我的兩個被覆蓋的方法被調用,但是由於缺少「JobLauncher」實例,因爲自動配置報告指出,我的JavabatchAutoConfiguration類有一個 「否定匹配」。正如該報告還指出的,原始BatchAutoConfiguration類對同一個ConditionalOnBean檢查有正匹配。

如果我在類上評論@ConditionalOnBean(JobLauncher.class)並在batchDatabaseInitializer-方法上評論@ConditionalOnBean(DataSource.class),則所有內容均按預期工作。

有沒有人對此行爲有解釋?

感謝 漢斯約裏

+0

您正在使它變得複雜......只需添加2個「BatchDatabaseInitializer」和「ExitCodeGenerator」類型的Bean即可。 Spring Batch自動配置將自動檢測這些配置,並使用這些默認配置。你不需要所有的條件和配置等。 –

回答

3

你使它方式複雜。你唯一需要做的就是創建一個配置,它定義了你想要使用的2個特定的bean。

@Configuration 
public class MyBatchConfiguration { 

    @Bean 
    public ExitCodeGenerator myExitCodeGenerator() { 
     return new MyExitCodeGenerator(); 
    } 

    @Bean 
    public BatchDatabaseInitializer myBatchDatabaseInitializer() { 
     return new MyBatchDatabaseInitializer(); 
    } 

} 

這就是你需要的。