Spring Batch - Resource must not be null

只愿长相守 提交于 2019-12-25 04:13:30

问题


I'm new to Spring Batch and am trying to work with a simple Spring Batch application (http://spring.io/guides/gs/batch-processing/) and am trying to convert it to use Oracle as a storage mechanism.

The problem I'm running into is below;

INFO 22152 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=importUserJob]] failed unexpectedly and fatally with the following parameters: [{run.id=7, -spring.output.ansi.enabled=always}]

java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:803) [spring-boot-1.4.1.RELEASE.jar:1.4.1.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:784) [spring-boot-1.4.1.RELEASE.jar:1.4.1.RELEASE]
at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:771) [spring-boot-1.4.1.RELEASE.jar:1.4.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-1.4.1.RELEASE.jar:1.4.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1186) [spring-boot-1.4.1.RELEASE.jar:1.4.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1175) [spring-boot-1.4.1.RELEASE.jar:1.4.1.RELEASE]
at hello.Application.main(Application.java:10) [classes/:na]
Caused by: java.lang.IllegalArgumentException: Resource must not be null
at org.springframework.util.Assert.notNull(Assert.java:115) ~[spring-core-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.transaction.support.TransactionSynchronizationUtils.unwrapResourceIfNecessary(TransactionSynchronizationUtils.java:62) ~[spring-tx-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.transaction.support.TransactionSynchronizationManager.getResource(TransactionSynchronizationManager.java:137) ~[spring-tx-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doGetTransaction(DataSourceTransactionManager.java:182) ~[spring-jdbc-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:337) ~[spring-tx-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:430) ~[spring-tx-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:276) ~[spring-tx-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at com.sun.proxy.$Proxy42.update(Unknown Source) ~[na:na]
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:357) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_102]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_102]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_102]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_102]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) ~[spring-aop-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) ~[spring-aop-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at com.sun.proxy.$Proxy47.run(Unknown Source) ~[na:na]
at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.execute(JobLauncherCommandLineRunner.java:216) ~[spring-boot-autoconfigure-1.4.1.RELEASE.jar:1.4.1.RELEASE]
at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.executeLocalJobs(JobLauncherCommandLineRunner.java:233) ~[spring-boot-autoconfigure-1.4.1.RELEASE.jar:1.4.1.RELEASE]
at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.launchJobFromProperties(JobLauncherCommandLineRunner.java:125) ~[spring-boot-autoconfigure-1.4.1.RELEASE.jar:1.4.1.RELEASE]
at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.run(JobLauncherCommandLineRunner.java:119) ~[spring-boot-autoconfigure-1.4.1.RELEASE.jar:1.4.1.RELEASE]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800) [spring-boot-1.4.1.RELEASE.jar:1.4.1.RELEASE]

The problem is, I can't figure out what resource is null and how to resolve it.

The code for my batch is below;

@Configuration
@EnableBatchProcessing
public class BatchConfiguration {

@Autowired
public JobBuilderFactory jobBuilderFactory;

@Autowired
public StepBuilderFactory stepBuilderFactory;

@Bean
public JobRepository jobRepository(){       
    JobRepositoryFactoryBean jReposFact = new JobRepositoryFactoryBean();
    jReposFact.setDataSource(dataSource());
    jReposFact.setTransactionManager(new DataSourceTransactionManager());
    jReposFact.setIsolationLevelForCreate("ISOLATION_REPEATABLE_READ");

    JobRepository jRepos = null;

    try{
        jRepos = jReposFact.getObject();
    }catch(Exception e){
        e.printStackTrace();
    }

    return jRepos;
}

@Bean
public DataSource dataSource(){
   return DataSourceBuilder.create()
            .url("jdbc:oracle:thin:@localhost:1521:curamdb")
            .driverClassName("oracle.jdbc.OracleDriver")
            .username("springbatch")
            .password("password")
            .build();          
}

@Bean
public FlatFileItemReader<Person> reader() {
    FlatFileItemReader<Person> reader = new FlatFileItemReader<Person>();
    reader.setResource(new ClassPathResource("sample-data.csv"));
    reader.setLineMapper(new DefaultLineMapper<Person>() {{
        setLineTokenizer(new DelimitedLineTokenizer() {{
            setNames(new String[] { "firstName", "lastName" });
        }});
        setFieldSetMapper(new BeanWrapperFieldSetMapper<Person>() {{
            setTargetType(Person.class);
        }});
    }});
    return reader;
}

@Bean
public PersonItemProcessor processor() {
    return new PersonItemProcessor();
}

@Bean
public JdbcBatchItemWriter<Person> writer() {
    JdbcBatchItemWriter<Person> writer = new JdbcBatchItemWriter<Person>();
    writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Person>());
    writer.setSql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)");
    writer.setDataSource(dataSource());
    return writer;
}

@Bean
public Job importUserJob(JobCompletionNotificationListener listener) {
    return jobBuilderFactory.get("importUserJob")
            .incrementer(new RunIdIncrementer())
            .listener(listener)
            .flow(step1())
            .end()
            .build();
}

@Bean
public Step step1() {
    return stepBuilderFactory.get("step1")
            .<Person, Person> chunk(10)
            .reader(reader())
            .processor(processor())
            .writer(writer())
            .build();
}
}

I have a suspicion is could be to do with my JobRepository definition, and maybe with the TransactionManager but am not familiar enough with Spring Batch to work out what the problem is.

Thanks in advance!

Bic


回答1:


Your dataSource is null, when the job starts. (check the stacktrace for DataSourceTransactionManager.doGetTransaction -> this method calls TransactionSynchronizationManager.getResource with a datasource as parameter).

I just can guess, but the problem could be the order in which the beans are being created

In your configuration class, you also define the datasource. But there is a chance, that the datasource been has not been initialized completely when the whole "launching beans of springbatch" are being created.

As far as I understood, the code works if your remove the dataSource and the jobRepository creation from your configuration class. In this case, springboot will provide a default inmemorydb-datasource and an appropriate jobrepository. I'd suggest, that you remove this two entries from your configuration file and see if the code works (I expect it will) Note: you need to add "@Autowired DataSource dataSource".

Next, write your own configuration class (annotated with '@Configuration') and add only your DataSource definition to it.

@Bean
public DataSource dataSource(){
   return DataSourceBuilder.create()
            .url("jdbc:oracle:thin:@localhost:1521:curamdb")
            .driverClassName("oracle.jdbc.OracleDriver")
            .username("springbatch")
            .password("password")
            .build();          
}

Use the "@Import" statement to add this configuration to your class.

@Configuration
@EnableBatchProcessing
@Import(YourDataSourceConfiguration.class)
public class BatchConfiguration {
   @Autowired
   private  DataSource dataSource;
   ....


来源:https://stackoverflow.com/questions/40380982/spring-batch-resource-must-not-be-null

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!