RESOLVED - issue BATCH-1395: Remove or deprecate old application context creation pattern

Removed it.
This commit is contained in:
dsyer
2009-09-07 17:24:22 +00:00
parent 8143e66768
commit 4da7efee3a
5 changed files with 123 additions and 31 deletions

View File

@@ -54,7 +54,7 @@ public class ApplicationContextJobFactory implements JobFactory {
public Job createJob() {
ConfigurableApplicationContext context = applicationContextFactory.createApplicationContext();
Job job = (Job) context.getBean(jobName, Job.class);
return new ContextClosingJob(job, context);
return new ContextAwareJob(job);
}
/**
@@ -72,19 +72,15 @@ public class ApplicationContextJobFactory implements JobFactory {
* @author Dave Syer
*
*/
private static class ContextClosingJob implements Job {
private static class ContextAwareJob implements Job {
private Job delegate;
private ConfigurableApplicationContext context;
/**
* @param delegate
* @param context
*/
public ContextClosingJob(Job delegate, ConfigurableApplicationContext context) {
public ContextAwareJob(Job delegate) {
super();
this.delegate = delegate;
this.context = context;
}
/**
@@ -92,12 +88,7 @@ public class ApplicationContextJobFactory implements JobFactory {
* @see org.springframework.batch.core.Job#execute(org.springframework.batch.core.JobExecution)
*/
public void execute(JobExecution execution) {
try {
delegate.execute(execution);
}
finally {
context.close();
}
delegate.execute(execution);
}
/**

View File

@@ -25,10 +25,12 @@ import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
/**
* {@link ApplicationContextFactory} implementation that takes a parent context and a path
* to the context to create. Each time the createApplicationContext method is called, a new
* {@link ApplicationContext} will be returned. It should be noted that if a path isn't
* set, the parent will always be returned.
* {@link ApplicationContextFactory} implementation that takes a parent context
* and a path to the context to create. When createApplicationContext method is
* called, the child {@link ApplicationContext} will be returned. The child
* context is not re-created every time it is requested, it is lazily
* initialized and cached. Clients should ensure that it is closed when it is no
* longer needed. If a path is not set, the parent will always be returned.
*
*/
public class ClassPathXmlApplicationContextFactory implements ApplicationContextFactory, ApplicationContextAware {
@@ -37,10 +39,14 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
private Resource path;
private ResourceXmlApplicationContext context;
private final Object lock = new Object();
/**
* Setter for the path to the xml to load to create an
* {@link ApplicationContext}. Use imports to centralise the configuration in
* one file.
* {@link ApplicationContext}. Use imports to centralise the configuration
* in one file.
*
* @param path the resource path to the xml to load for the child context.
*/
@@ -64,10 +70,21 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
* @see ApplicationContextFactory#createApplicationContext()
*/
public ConfigurableApplicationContext createApplicationContext() {
if (path == null) {
return parent;
}
return new ResourceXmlApplicationContext(parent);
if (context == null) {
// Lazy initialization of cached context
synchronized (lock) {
if (context == null) {
context = new ResourceXmlApplicationContext(parent);
}
}
}
return context;
}
/**
@@ -84,7 +101,7 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
}
protected Resource[] getConfigResources() {
return new Resource[] {path};
return new Resource[] { path };
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.batch.core.configuration.support;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.apache.commons.logging.Log;
@@ -28,20 +29,26 @@ import org.springframework.batch.core.configuration.JobFactory;
import org.springframework.batch.core.configuration.ListableJobRegistry;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.Resource;
/**
* Implementation of the {@link ListableJobRegistry} interface that assumes all
* Jobs will be loaded from ClassPathXml resources.
* Jobs will be loaded from class path xml resources. Each resource provided is
* loaded as an application context with the current context as its parent, and
* then all the jobs from the child context are registered under their bean
* names. Care must be taken to avoid duplicate names.
*
* @author Lucas Ward
* @author Dave Syer
* @since 2.0
*/
public class ClassPathXmlJobRegistry implements ListableJobRegistry, ApplicationContextAware, InitializingBean {
public class ClassPathXmlJobRegistry implements ListableJobRegistry, ApplicationContextAware, InitializingBean,
DisposableBean {
private static Log logger = LogFactory.getLog(ClassPathXmlJobRegistry.class);
@@ -51,25 +58,59 @@ public class ClassPathXmlJobRegistry implements ListableJobRegistry, Application
private ListableJobRegistry jobRegistry = new MapJobRegistry();
private Collection<ConfigurableApplicationContext> contexts = new HashSet<ConfigurableApplicationContext>();
/**
* A set of resources to load. Each resource should be a Spring
* configuration file which is loaded into an application context whose
* parent is the current context. In a configuration file the resources can
* be given as a pattern (e.g.
* <code>classpath*:/config/*-job-context.xml</code>).
*
* @param jobPaths
*/
public void setJobPaths(Resource[] jobPaths) {
this.jobPaths = Arrays.asList(jobPaths);
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.context.ApplicationContextAware#setApplicationContext
* (org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
parent = applicationContext;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.batch.core.configuration.JobLocator#getJob(java.lang
* .String)
*/
public Job getJob(String name) throws NoSuchJobException {
return jobRegistry.getJob(name);
}
/**
* Create all the application contexts required and set up job registry
* entries with all the instances of {@link Job} found therein.
*
* @see InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
for (Resource resource : jobPaths) {
ClassPathXmlApplicationContextFactory applicationContextFactory = new ClassPathXmlApplicationContextFactory();
applicationContextFactory.setPath(resource);
applicationContextFactory.setApplicationContext(parent);
ApplicationContext context = applicationContextFactory.createApplicationContext();
if (parent != null) {
applicationContextFactory.setApplicationContext(parent);
}
ConfigurableApplicationContext context = applicationContextFactory.createApplicationContext();
contexts.add(context);
String[] names = context.getBeanNamesForType(Job.class);
for (String name : names) {
@@ -86,6 +127,35 @@ public class ClassPathXmlJobRegistry implements ListableJobRegistry, Application
}
/**
* Close the contexts that were created in {@link #afterPropertiesSet()}.
*
* @see DisposableBean#destroy()
*/
public void destroy() throws Exception {
try {
for (ConfigurableApplicationContext context : contexts) {
String[] names = context.getBeanNamesForType(Job.class);
try {
for (String name : names) {
unregister(name);
}
}
finally {
context.close();
}
}
}
finally {
contexts.clear();
}
}
public Collection<String> getJobNames() {
return jobRegistry.getJobNames();
}

View File

@@ -70,4 +70,18 @@ public class ClassPathXmlJobRegistryTests {
registry.afterPropertiesSet();
assertEquals(2, registry.getJobNames().size());
}
@Test
public void testDestroy() throws Exception {
Resource[] jobPaths = new Resource[] { new ClassPathResource(
"org/springframework/batch/core/launch/support/2jobs.xml") };
registry.setJobPaths(jobPaths);
registry.afterPropertiesSet();
assertEquals(2, registry.getJobNames().size());
registry.destroy();
assertEquals(0, registry.getJobNames().size());
}
}

View File

@@ -88,13 +88,13 @@
</property>
</bean>
<bean id="tradeProcessor" class="org.springframework.batch.sample.domain.trade.internal.TradeProcessor" />
<bean id="tradeProcessor" class="org.springframework.batch.sample.domain.trade.internal.TradeProcessor" scope="step"/>
<bean id="tradeProcessorFailure" class="org.springframework.batch.sample.domain.trade.internal.TradeProcessor">
<bean id="tradeProcessorFailure" class="org.springframework.batch.sample.domain.trade.internal.TradeProcessor" scope="step">
<property name="validationFailure" value="7" />
</bean>
<bean id="tradeWriter" class="org.springframework.batch.sample.domain.trade.internal.TradeWriter">
<bean id="tradeWriter" class="org.springframework.batch.sample.domain.trade.internal.TradeWriter" scope="step">
<property name="dao">
<bean class="org.springframework.batch.sample.domain.trade.internal.JdbcTradeDao">
<property name="dataSource" ref="dataSource" />
@@ -112,12 +112,12 @@
</property>
</bean>
<bean id="itemTrackingWriter" class="org.springframework.batch.sample.domain.trade.internal.ItemTrackingTradeItemWriter">
<bean id="itemTrackingWriter" class="org.springframework.batch.sample.domain.trade.internal.ItemTrackingTradeItemWriter" scope="step">
<property name="writeFailureISIN" value="UK21341EAH47" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="tradeSqlItemReader" class="org.springframework.batch.item.database.JdbcCursorItemReader">
<bean id="tradeSqlItemReader" class="org.springframework.batch.item.database.JdbcCursorItemReader" scope="step">
<property name="dataSource" ref="dataSource" />
<property name="sql" value="SELECT isin, quantity, price, customer, id, version from TRADE" />
<property name="rowMapper">
@@ -125,7 +125,7 @@
</property>
</bean>
<bean id="errorLogTasklet" class="org.springframework.batch.sample.common.ErrorLogTasklet">
<bean id="errorLogTasklet" class="org.springframework.batch.sample.common.ErrorLogTasklet" scope="step">
<property name="dataSource" ref="dataSource" />
</bean>