REOPENED - issue BATCH-1338: Allow segregation of jobs by type or origin
Added parent configuration copying as a feature in ClassPathXmlApplicationContextFactory.
This commit is contained in:
@@ -17,6 +17,8 @@
|
||||
package org.springframework.batch.core.configuration.support;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -41,6 +43,10 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
|
||||
|
||||
private ResourceXmlApplicationContext context;
|
||||
|
||||
private boolean copyConfiguration = true;
|
||||
|
||||
private boolean copyBeanFactoryPostProcessors = true;
|
||||
|
||||
private final Object lock = new Object();
|
||||
|
||||
/**
|
||||
@@ -54,6 +60,27 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag to indicate that configuration such as bean post processors and
|
||||
* custom editors should be copied from the parent context. Defaults to
|
||||
* true;
|
||||
*
|
||||
* @param copyConfiguration the flag value to set
|
||||
*/
|
||||
public void setCopyConfiguration(boolean copyConfiguration) {
|
||||
this.copyConfiguration = copyConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag to indicate that bean factory post processors (like property
|
||||
* placeholders) should be copied from the parent context. Defaults to true;
|
||||
*
|
||||
* @param copyBeanFactoryPostProcessors the flag value to set
|
||||
*/
|
||||
public void setCopyBeanFactoryPostProcessors(boolean copyBeanFactoryPostProcessors) {
|
||||
this.copyBeanFactoryPostProcessors = copyBeanFactoryPostProcessors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the parent application context.
|
||||
*
|
||||
@@ -92,17 +119,81 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
|
||||
*
|
||||
*/
|
||||
private final class ResourceXmlApplicationContext extends AbstractXmlApplicationContext {
|
||||
|
||||
private final DefaultListableBeanFactory parentBeanFactory;
|
||||
|
||||
/**
|
||||
* @param parent
|
||||
*/
|
||||
private ResourceXmlApplicationContext(ApplicationContext parent) {
|
||||
public ResourceXmlApplicationContext(ConfigurableApplicationContext parent) {
|
||||
super(parent);
|
||||
if (parent != null) {
|
||||
Assert.isTrue(parent.getBeanFactory() instanceof DefaultListableBeanFactory,
|
||||
"The parent application context must have a bean factory of type DefaultListableBeanFactory");
|
||||
parentBeanFactory = (DefaultListableBeanFactory) parent.getBeanFactory();
|
||||
refreshBeanFactory();
|
||||
prepareContext(parent, this);
|
||||
}
|
||||
else {
|
||||
parentBeanFactory = null;
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
|
||||
super.customizeBeanFactory(beanFactory);
|
||||
if (parentBeanFactory != null) {
|
||||
ClassPathXmlApplicationContextFactory.this.prepareBeanFactory(parentBeanFactory, beanFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Resource[] getConfigResources() {
|
||||
return new Resource[] { path };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension point for special subclasses that want to do more complex
|
||||
* things with the context prior to refresh. The default implementation
|
||||
* copies bean factory post processors according to the flag set. The bean
|
||||
* factory for the context will be available if needed through
|
||||
* {@link ConfigurableApplicationContext#getBeanFactory()
|
||||
* context.getBeanFactory()}.
|
||||
*
|
||||
* @param parent the parent for the new application context
|
||||
* @param context the new application context before it is refreshed, but
|
||||
* after bean factory is initialized
|
||||
*
|
||||
* @see ClassPathXmlApplicationContextFactory#setCopyBeanFactoryPostProcessors(boolean)
|
||||
*/
|
||||
protected void prepareContext(ConfigurableApplicationContext parent, ConfigurableApplicationContext context) {
|
||||
if (copyBeanFactoryPostProcessors) {
|
||||
for (String name : parent.getBeanNamesForType(BeanFactoryPostProcessor.class)) {
|
||||
context.addBeanFactoryPostProcessor((BeanFactoryPostProcessor) parent.getBean(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension point for special subclasses that want to do more complex
|
||||
* things with the bean factory prior to refresh. The default implementation
|
||||
* copies all configuration from the parent according to the flag set.
|
||||
*
|
||||
* @param parent the parent bean factory for the new context (will never be
|
||||
* null)
|
||||
* @param beanFactory the new bean factory before bean definitions are
|
||||
* loaded
|
||||
*
|
||||
* @see ClassPathXmlApplicationContextFactory#setCopyConfiguration(boolean)
|
||||
* @see DefaultListableBeanFactory#copyConfigurationFrom(ConfigurableBeanFactory)
|
||||
*/
|
||||
protected void prepareBeanFactory(DefaultListableBeanFactory parent, DefaultListableBeanFactory beanFactory) {
|
||||
if (copyConfiguration && parent != null) {
|
||||
beanFactory.copyConfigurationFrom(parent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,9 +15,13 @@
|
||||
*/
|
||||
package org.springframework.batch.core.configuration.support;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -25,18 +29,60 @@ import org.springframework.util.ClassUtils;
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class ClassPathXmlApplicationContextFactoryTests extends TestCase {
|
||||
public class ClassPathXmlApplicationContextFactoryTests {
|
||||
|
||||
private ClassPathXmlApplicationContextFactory factory = new ClassPathXmlApplicationContextFactory();
|
||||
|
||||
@Test
|
||||
public void testCreateJob() {
|
||||
factory.setPath(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "trivial-context.xml")));
|
||||
assertNotNull(factory.createApplicationContext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetJobName() {
|
||||
factory.setPath(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "trivial-context.xml")));
|
||||
assertEquals("test-job", factory.createApplicationContext().getBeanNamesForType(Job.class)[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParentConfigurationInherited() {
|
||||
factory.setApplicationContext(new ClassPathXmlApplicationContext(ClassUtils.addResourcePathToPackagePath(getClass(), "parent-context.xml")));
|
||||
factory.setPath(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "child-context.xml")));
|
||||
ConfigurableApplicationContext context = factory.createApplicationContext();
|
||||
assertEquals("test-job", context.getBeanNamesForType(Job.class)[0]);
|
||||
assertEquals("bar", ((Job) context.getBean("test-job", Job.class)).getName());
|
||||
assertEquals(4, ((Foo) context.getBean("foo", Foo.class)).values[1], 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeanFactoryPostProcessorsNotCopied() {
|
||||
factory.setApplicationContext(new ClassPathXmlApplicationContext(ClassUtils.addResourcePathToPackagePath(getClass(), "parent-context.xml")));
|
||||
factory.setPath(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "child-context.xml")));
|
||||
factory.setCopyBeanFactoryPostProcessors(false);
|
||||
ConfigurableApplicationContext context = factory.createApplicationContext();
|
||||
assertEquals("test-job", context.getBeanNamesForType(Job.class)[0]);
|
||||
assertEquals("${foo}", ((Job) context.getBean("test-job", Job.class)).getName());
|
||||
assertEquals(4, ((Foo) context.getBean("foo", Foo.class)).values[1], 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeanFactoryConfigurationNotCopied() {
|
||||
factory.setApplicationContext(new ClassPathXmlApplicationContext(ClassUtils.addResourcePathToPackagePath(getClass(), "parent-context.xml")));
|
||||
factory.setPath(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "child-context.xml")));
|
||||
factory.setCopyConfiguration(false);
|
||||
ConfigurableApplicationContext context = factory.createApplicationContext();
|
||||
assertEquals("test-job", context.getBeanNamesForType(Job.class)[0]);
|
||||
assertEquals("bar", ((Job) context.getBean("test-job", Job.class)).getName());
|
||||
// The CustomEditorConfigurer is a BeanFactoryPostProcessor so the editor gets copied anyway!
|
||||
assertEquals(4, ((Foo) context.getBean("foo", Foo.class)).values[1], 0.01);
|
||||
}
|
||||
|
||||
public static class Foo {
|
||||
private double[] values;
|
||||
public void setValues(double[] values) {
|
||||
this.values = values;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx" 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-2.0.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
|
||||
|
||||
<bean id="test-job" class="org.springframework.batch.core.job.JobSupport">
|
||||
<property name="name" value="${foo}" />
|
||||
</bean>
|
||||
|
||||
<bean id="foo" class="org.springframework.batch.core.configuration.support.ClassPathXmlApplicationContextFactoryTests$Foo">
|
||||
<property name="values" value="1,4" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx" 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-2.0.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
|
||||
<property name="properties" value="foo=bar" />
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
|
||||
<property name="customEditors">
|
||||
<map>
|
||||
<entry key="double[]" value="org.springframework.batch.support.IntArrayPropertyEditor"/>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
Reference in New Issue
Block a user