问题
I downloaded the spring batch admin application in the github repo and I imported it in eclipse. it works perfectly.
Then, I asked myself how to import an external config file into the application that I can use in my job definition class.
I tried this :
VM Arguments
-Dspring.config.location=C:/path/to/config/file/application.properties
Job configuration
src/main/java
org.springframework.batch.admin.sample.job
-------------------------------------------
@Configuration
public class JobConfiguration {
//I try to import this properties from an external config file.
@Value("${folder.input.files}")
private String pathToFiles;
@Autowired
public JobBuilderFactory jobBuilderFactory;
@Autowired
public StepBuilderFactory stepBuilderFactory;
@Bean
@JobScope
public ExampleItemReader itemReader() {
return new ExampleItemReader();
}
@Bean
@StepScope
public ExampleItemWriter itemWriter(@Value("#{jobParameters[fail]}") Boolean fail) {
ExampleItemWriter itemWriter = new ExampleItemWriter();
itemWriter.setFail(fail);
return itemWriter;
}
@Bean
public Step step1() {
return stepBuilderFactory.get("step1")
.<String, Object>chunk(5)
.reader(itemReader())
.writer(itemWriter(null))
.build();
}
@Bean
public Job javaJob() {
return jobBuilderFactory.get("javaJob")
.start(step1())
.build();
}
}
XML configuration
src/main/resources
launch-context.xml
-----------------------
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<description><![CDATA[
A convenient aggregating config file for running the jobs in this project
from the command line instead of from the web application. E.g.
$ MAVEN_OPTS="-Dbatch.jdbc.url=jdbc:hsqldb:hsql://localhost:9005/samples -Dbatch.data.source.init=false" \
mvn exec:java -Dexec.classpathScope=runtime \
-Dexec.mainClass=org.springframework.batch.core.launch.support.CommandLineJobRunner \
-Dexec.args="classpath:launch-context.xml job1 fail=false run.id=1"
]]>
</description>
<import resource="classpath*:/META-INF/spring/batch/bootstrap/**/*.xml" />
<import resource="classpath*:/META-INF/spring/batch/override/**/*.xml" />
<bean id="jobLauncherTaskExecutor" class="org.springframework.core.task.SyncTaskExecutor"/>
<!-- Try to add my external config file -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:file:///${spring.config.location}</value>
</list>
</property>
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreResourceNotFound" value="true" />
<property name="ignoreUnresolvablePlaceholders" value="false" />
<property name="order" value="1" />
</bean>
</beans>
Stack trace when I launch the app with tomcat 7
18:54:38,528 ERROR localhost-startStop-1 context.ContextLoader:331 - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jobConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.lang.String org.springframework.batch.admin.sample.job.JobConfiguration.pathToFiles; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'folder.input.files' in string value "${folder.input.files}"
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1204)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:762)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.batch.core.configuration.support.GenericApplicationContextFactory$ResourceAnnotationApplicationContext.<init>(GenericApplicationContextFactory.java:209)
at org.springframework.batch.core.configuration.support.GenericApplicationContextFactory.createApplicationContext(GenericApplicationContextFactory.java:70)
at org.springframework.batch.core.configuration.support.AbstractApplicationContextFactory.createApplicationContext(AbstractApplicationContextFactory.java:172)
at org.springframework.batch.core.configuration.support.DefaultJobLoader.doLoad(DefaultJobLoader.java:154)
at org.springframework.batch.core.configuration.support.DefaultJobLoader.load(DefaultJobLoader.java:147)
at org.springframework.batch.core.configuration.support.AutomaticJobRegistrar.start(AutomaticJobRegistrar.java:173)
at org.springframework.batch.core.configuration.support.AutomaticJobRegistrar.onApplicationEvent(AutomaticJobRegistrar.java:139)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:151)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:128)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:331)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:773)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:483)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.lang.String org.springframework.batch.admin.sample.job.JobConfiguration.pathToFiles; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'folder.input.files' in string value "${folder.input.files}"
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:555)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 34 more
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'folder.input.files' in string value "${folder.input.files}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.beans.factory.config.PropertyPlaceholderConfigurer$PlaceholderResolvingStringValueResolver.resolveStringValue(PropertyPlaceholderConfigurer.java:259)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:800)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:962)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:949)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:527)
... 36 more
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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-batch-admin-sample</artifactId>
<description>A sample web application (WAR project) for Spring Batch Admin console.</description>
<parent>
<artifactId>spring-batch-admin-parent</artifactId>
<groupId>org.springframework.batch</groupId>
<version>2.0.0.BUILD-SNAPSHOT</version>
<relativePath>../spring-batch-admin-parent</relativePath>
</parent>
<packaging>war</packaging>
<name>Web Sample</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-infrastructure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-admin-manager</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-admin-resources</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<contextPath>/spring-batch-admin-sample</contextPath>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Maven Milestone Repository</name>
<url>http://s3.amazonaws.com/maven.springframework.org/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
I tried this post and much more but without success.
I use exactly the same files and the same configuration than the spring batch admin github project.
Can someone tell me how to add the external configuration file to spring batch admin?
回答1:
Spring batch admin searches configurations in specific paths.This page explains from which paths it loads resources:
<import resource="classpath*:/META-INF/spring/batch/bootstrap/**/*.xml"/>
<import resource="classpath*:/META-INF/spring/batch/override/**/*.xml"/>
Note that the "override" location has no files in it in Spring Batch Admin distribution. This is a placeholder for users to add their own content.
We managed to load external properties files placing xml configuration file under src/main/resources/META-INF/spring/batch/override/manager/env-context.xml
which looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Use this to set additional properties on beans at run time -->
<bean id="placeholderProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/org/springframework/batch/admin/bootstrap/batch.properties</value>
<value>classpath:batch-default.properties</value>
<value>classpath:batch-${ENVIRONMENT:hsql}.properties</value>
<value>classpath:batch-${ENVIRONMENT:mysql}.properties</value>
<!-- here we load properties from external config folder -->
<value>file:${spring.file.location}</value>
</list>
</property>
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreResourceNotFound" value="false" />
<property name="ignoreUnresolvablePlaceholders" value="false" />
<property name="order" value="1" />
</bean>
</beans>
回答2:
Under main folder of spring-batch-admin template, there are three folders - java, resources and webapp. Under resources there are some property files and META-INF folder. within META-INF there are two folders - batch and servlet.
Here If I want to add new property file "batch.properties" under resources and want to refer the property values from configuration (xml) files from "META-INF/batch/*.xml" in addition to the properties from spring-batch-admin-manager-1.0.0.M1.jar, 1. where to add below entries
Where to keep "env-context.xml". Under which folders, coz in "src/main/resources/META-INF" i can see only one folder batch.
I tried to create "spring/batch/override/manager/env-context.xml" under "src/main/resources/META-INF" but not able to read the property file entries.
If you provide your working application folder structure will help me a lot.
回答3:
You can put your env-context.xml file on spring/batch/servlet/override/env-context.xml folder.
来源:https://stackoverflow.com/questions/30465345/load-external-config-file-in-spring-batch-admin