RESOLVED BATCH-939: Make step scope work with aop-scoped-proxy

This commit is contained in:
dsyer
2008-11-24 08:24:51 +00:00
parent 925e7d1e16
commit fb9b662160
17 changed files with 319 additions and 84 deletions

View File

@@ -22,6 +22,32 @@
<config>src/test/resources/org/springframework/batch/core/configuration/xml/OneStepJobParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/TwoStepJobParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/annotation/batch-component-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/scope/util/AsyncPlaceholderTargetSourceTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/scope/AsyncStepScopeIntegrationTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/annotation/batch-component-context-scoped.xml</config>
<config>src/test/resources/org/springframework/batch/core/annotation/batch-component-context-with-resolver-nonscanned.xml</config>
<config>src/test/resources/org/springframework/batch/core/annotation/batch-component-context-with-resolver.xml</config>
<config>src/test/resources/org/springframework/batch/core/annotation/component-scan-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/DecisionJobParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/JobExecutionListenerParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/JobRepositoryParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/partition/launch-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/scope/util/MultipleContextPlaceholderTargetSourceTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/NextAttributeFailureJobParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/NextAttributeJobParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/scope/util/PlaceholderTargetSourceTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/RepositoryJobParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/scope/util/SimplePlaceholderTargetSourceTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/SplitJobParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/scope/StepScopeDestructionCallbackIntegrationTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/scope/StepScopeIntegrationTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/scope/StepScopeNestedIntegrationTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/scope/StepScopePlaceholderIntegrationTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/scope/StepScopeStartupIntegrationTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/StepWithBasicProcessTaskJobParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/StepWithFaultTolerantProcessTaskJobParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/StepWithSimpleTaskJobParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/StopJobParserTests-context.xml</config>
</configs>
<configSets>
<configSet>

View File

@@ -164,7 +164,7 @@ public class StepContext extends SynchronizedAttributeAccessor {
}
else {
throw new UnexpectedJobExecutionException("Could not close step context, rethrowing first of "
+ errors.size() + " execptions.", error);
+ errors.size() + " exceptions.", error);
}
}

View File

@@ -285,6 +285,7 @@ public class StepScope implements Scope, BeanFactoryPostProcessor, Ordered {
return createScopedProxy(holder.getBeanName(), definition, registry, proxyTargetClass);
}
}
value = super.resolveValue(value);
return value;
}
}

View File

@@ -47,7 +47,7 @@ public class PlaceholderProxyFactoryBean extends ProxyConfig implements FactoryB
*/
public PlaceholderProxyFactoryBean(ContextFactory contextFactory) {
this.contextFactory = contextFactory;
setProxyTargetClass(true);
// setProxyTargetClass(false);
}
/**

View File

@@ -17,7 +17,6 @@ package org.springframework.batch.core.scope.util;
import org.springframework.aop.TargetSource;
import org.springframework.aop.target.SimpleBeanTargetSource;
import org.springframework.batch.core.scope.StepScope;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
@@ -25,7 +24,6 @@ import org.springframework.beans.TypeConverter;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinitionVisitor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
@@ -60,8 +58,6 @@ public class PlaceholderTargetSource extends SimpleBeanTargetSource implements I
private ContextFactory contextFactory;
private StepScope scope = new StepScope();
/**
* Public setter for the context factory. Used to construct the context root
* whenever placeholders are replaced in a bean definition.
@@ -95,6 +91,8 @@ public class PlaceholderTargetSource extends SimpleBeanTargetSource implements I
final TypeConverter typeConverter = listableBeanFactory.getTypeConverter();
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(listableBeanFactory);
beanFactory.copyConfigurationFrom(listableBeanFactory);
beanFactory.setTypeConverter(new TypeConverter() {
@SuppressWarnings("unchecked")
public Object convertIfNecessary(Object value, Class requiredType, MethodParameter methodParam)
@@ -155,17 +153,6 @@ public class PlaceholderTargetSource extends SimpleBeanTargetSource implements I
};
String beanScope = beanDefinition.getScope();
/*
* The scope for the bean really ought to be "step" if we get this
* far, but we'll be cautious anyway and avoid a potential issue
* with trying to replace the default scopes (which is not allowed)
*/
if (!beanScope.equals(ConfigurableListableBeanFactory.SCOPE_PROTOTYPE)
&& !beanScope.equals(ConfigurableListableBeanFactory.SCOPE_SINGLETON)) {
// Need this otherwise there will be no step scope available.
beanFactory.registerScope(beanScope, scope);
}
beanFactory.registerBeanDefinition(beanName, beanDefinition);
// Make the replacements before the target is hydrated
visitor.visitBeanDefinition(beanDefinition);
@@ -173,7 +160,7 @@ public class PlaceholderTargetSource extends SimpleBeanTargetSource implements I
}
finally {
beanFactory.destroySingletons();
beanFactory.removeBeanDefinition(beanName);
beanFactory = null;
// Anything else we can do to clean it up?
}

View File

@@ -0,0 +1,72 @@
package org.springframework.batch.core.scope;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class StepScopeDestructionCallbackIntegrationTests {
@Autowired
@Qualifier("proxied")
private Step proxied;
@Autowired
@Qualifier("nested")
private Step nested;
@Autowired
@Qualifier("foo")
private Collaborator foo;
@Before
@After
public void resetMessage() throws Exception {
TestDisposableCollaborator.message = "none";
TestAdvice.names.clear();
}
@Test
public void testDisposableScopedProxy() throws Exception {
assertNotNull(proxied);
proxied.execute(new StepExecution("step", new JobExecution(0L), 1L));
assertEquals("destroyed", TestDisposableCollaborator.message);
}
@Test
public void testDisposableInnerScopedProxy() throws Exception {
assertNotNull(nested);
nested.execute(new StepExecution("step", new JobExecution(0L), 1L));
assertEquals("destroyed", TestDisposableCollaborator.message);
}
@Test
public void testProxiedScopedProxy() throws Exception {
assertNotNull(nested);
nested.execute(new StepExecution("step", new JobExecution(0L), 1L));
assertEquals(2, TestAdvice.names.size());
assertEquals("bar", TestAdvice.names.get(0));
assertEquals("destroyed", TestDisposableCollaborator.message);
}
@Test
public void testProxiedNormalBean() throws Exception {
assertNotNull(nested);
String name = foo.getName();
assertEquals(1, TestAdvice.names.size());
assertEquals(name, TestAdvice.names.get(0));
}
}

View File

@@ -0,0 +1,33 @@
package org.springframework.batch.core.scope;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.Step;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class StepScopeNestedIntegrationTests {
@Autowired
@Qualifier("proxied")
private Step proxied;
@Autowired
@Qualifier("parent")
private Collaborator parent;
@Test
public void testNestedScopedProxy() throws Exception {
assertNotNull(proxied);
assertEquals("foo", parent.getName());
}
}

View File

@@ -0,0 +1,20 @@
package org.springframework.batch.core.scope;
import java.util.ArrayList;
import java.util.List;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class TestAdvice {
public static List<String> names = new ArrayList<String>();
@AfterReturning(pointcut="execution(String org.springframework.batch.core.scope.Collaborator+.getName(..))", returning="name")
public void registerCollaborator(String name) {
names.add(name);
}
}

View File

@@ -17,9 +17,6 @@ public class TestCollaborator implements Collaborator, Serializable {
this.parent = parent;
}
/* (non-Javadoc)
* @see org.springframework.batch.core.scope.Collaborator#getName()
*/
public String getName() {
return name;
}

View File

@@ -0,0 +1,14 @@
package org.springframework.batch.core.scope;
import org.springframework.beans.factory.DisposableBean;
public class TestDisposableCollaborator extends TestCollaborator implements DisposableBean {
public static volatile String message = "none";
public void destroy() throws Exception {
message = "destroyed";
}
}

View File

@@ -31,7 +31,8 @@ public class TestStep implements Step {
private void setContextFromCollaborator() {
if (context != null) {
context.setAttribute("collaborator", collaborator.getName());
String name = collaborator.getName();
context.setAttribute("collaborator", name);
}
}

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.springframework.batch.core.annotation"
scope-resolver="org.springframework.batch.core.annotation.BatchComponentScopeMetaDataResolver">
<context:component-scan base-package="org.springframework.batch.core.annotation"
scope-resolver="org.springframework.batch.core.annotation.BatchComponentScopeMetaDataResolver">
</context:component-scan>
<bean id="testComponent" class="org.springframework.batch.core.annotation.TestComponent" />
</beans>
</beans>

View File

@@ -1,14 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.springframework.batch.core.annotation"
scope-resolver="org.springframework.batch.core.annotation.BatchComponentScopeMetaDataResolver"
>
<context:include-filter type="annotation" expression="org.springframework.batch.core.annotation.BatchComponent"/>
<context:component-scan base-package="org.springframework.batch.core.annotation"
scope-resolver="org.springframework.batch.core.annotation.BatchComponentScopeMetaDataResolver">
<context:include-filter type="annotation"
expression="org.springframework.batch.core.annotation.BatchComponent" />
</context:component-scan>
</beans>
</beans>

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.springframework.batch.core.annotation">
<context:include-filter type="annotation" expression="org.springframework.batch.core.annotation.BatchComponent"/>
<context:include-filter type="annotation"
expression="org.springframework.batch.core.annotation.BatchComponent" />
</context:component-scan>
</beans>

View File

@@ -1,49 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.springframework.batch.core.annotation"
scope-resolver="org.springframework.batch.core.annotation.BatchComponentScopeMetaDataResolver"
>
<context:include-filter type="annotation" expression="org.springframework.batch.core.annotation.BatchComponent"/>
</context:component-scan>
<bean id="job-scan" class="org.springframework.batch.core.job.SimpleJob" >
<property name="steps">
<list>
<ref bean="step"/>
</list>
</property>
<property name="jobRepository" ref="jobRepository" />
</bean>
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" >
<property name="transactionManager">
<bean class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
</property>
</bean>
<bean id="step" class="org.springframework.batch.core.step.tasklet.TaskletStep" >
<property name="tasklet">
<bean class="org.springframework.batch.core.configuration.xml.TestTasklet" />
</property>
<property name="jobRepository" ref="jobRepository" />
<property name="transactionManager">
<bean class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
</property>
</bean>
<bean class="org.springframework.batch.core.annotation.StepComponentBeanPostProcessor" >
<constructor-arg ref="step" />
<constructor-arg value="org.springframework.batch.core.annotation" />
</bean>
<bean class="org.springframework.batch.core.launch.support.SimpleJobLauncher" >
<property name="jobRepository" ref="jobRepository" />
<context:component-scan base-package="org.springframework.batch.core.annotation"
scope-resolver="org.springframework.batch.core.annotation.BatchComponentScopeMetaDataResolver">
<context:include-filter type="annotation"
expression="org.springframework.batch.core.annotation.BatchComponent" />
</context:component-scan>
<bean id="job-scan" class="org.springframework.batch.core.job.SimpleJob">
<property name="steps">
<list>
<ref bean="step" />
</list>
</property>
<property name="jobRepository" ref="jobRepository" />
</bean>
</beans>
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
<property name="transactionManager">
<bean
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
</property>
</bean>
<bean id="step" class="org.springframework.batch.core.step.tasklet.TaskletStep">
<property name="tasklet">
<bean class="org.springframework.batch.core.configuration.xml.TestTasklet" />
</property>
<property name="jobRepository" ref="jobRepository" />
<property name="transactionManager">
<bean
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
</property>
</bean>
<bean
class="org.springframework.batch.core.annotation.StepComponentBeanPostProcessor">
<constructor-arg ref="step" />
<constructor-arg value="org.springframework.batch.core.annotation" />
</bean>
<bean class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
</beans>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:annotation-config />
<bean id="proxied" class="org.springframework.batch.core.scope.TestStep">
<property name="collaborator">
<bean
class="org.springframework.batch.core.scope.TestDisposableCollaborator"
scope="step">
<property name="name" value="bar" />
</bean>
</property>
</bean>
<bean id="nested" class="org.springframework.batch.core.scope.TestStep">
<property name="collaborator">
<bean class="org.springframework.batch.core.scope.TestCollaborator"
scope="step">
<property name="name" value="bar" />
<property name="parent">
<bean
class="org.springframework.batch.core.scope.TestDisposableCollaborator">
<property name="name" value="foo" />
</bean>
</property>
</bean>
</property>
</bean>
<bean id="foo"
class="org.springframework.batch.core.scope.TestDisposableCollaborator">
<property name="name" value="foo" />
</bean>
<aop:aspectj-autoproxy />
<bean class="org.springframework.batch.core.scope.TestAdvice" />
<bean class="org.springframework.batch.core.scope.StepScopeManager" />
<bean class="org.springframework.batch.core.scope.StepScope" />
</beans>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:annotation-config />
<bean id="proxied" class="org.springframework.batch.core.scope.TestStep">
<property name="collaborator">
<bean class="org.springframework.batch.core.scope.TestDisposableCollaborator"
scope="step">
<property name="name" value="bar" />
<property name="parent" ref="parent"/>
</bean>
</property>
</bean>
<bean id="parent"
class="org.springframework.batch.core.scope.TestDisposableCollaborator">
<property name="name" value="foo" />
</bean>
<aop:aspectj-autoproxy />
<bean class="org.springframework.batch.core.scope.StepScopeManager" />
<bean class="org.springframework.batch.core.scope.StepScope" />
</beans>