moving unit tests from .testsuite -> .aop
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.interceptor;
|
||||
|
||||
/**
|
||||
* Bean that changes state on a business invocation, so that
|
||||
* we can check whether it's been invoked
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
public class SideEffectBean {
|
||||
|
||||
private int count;
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return this.count;
|
||||
}
|
||||
|
||||
public void doWork() {
|
||||
++count;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.target;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.ITestBean;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
/**
|
||||
* @author Rob Harrop
|
||||
* @author Chris Beams
|
||||
* @since 2.0
|
||||
*/
|
||||
public class CommonsPoolTargetSourceProxyTests {
|
||||
|
||||
@Test
|
||||
public void testProxy() throws Exception {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
|
||||
reader.loadBeanDefinitions(new ClassPathResource("commonsPoolProxyTests.xml", getClass()));
|
||||
beanFactory.preInstantiateSingletons();
|
||||
ITestBean bean = (ITestBean)beanFactory.getBean("testBean");
|
||||
assertTrue(AopUtils.isAopProxy(bean));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.target;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.interceptor.SerializableNopInterceptor;
|
||||
import org.springframework.aop.interceptor.SideEffectBean;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.beans.Person;
|
||||
import org.springframework.beans.SerializablePerson;
|
||||
import org.springframework.beans.factory.xml.XmlBeanFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.SerializationTestUtils;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class HotSwappableTargetSourceTests {
|
||||
|
||||
/** Initial count value set in bean factory XML */
|
||||
private static final int INITIAL_COUNT = 10;
|
||||
|
||||
private XmlBeanFactory beanFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.beanFactory = new XmlBeanFactory(new ClassPathResource("hotSwapTests.xml", getClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* We must simulate container shutdown, which should clear threads.
|
||||
*/
|
||||
@After
|
||||
public void tearDown() {
|
||||
// Will call pool.close()
|
||||
this.beanFactory.destroySingletons();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check it works like a normal invoker
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testBasicFunctionality() {
|
||||
SideEffectBean proxied = (SideEffectBean) beanFactory.getBean("swappable");
|
||||
assertEquals(INITIAL_COUNT, proxied.getCount() );
|
||||
proxied.doWork();
|
||||
assertEquals(INITIAL_COUNT + 1, proxied.getCount() );
|
||||
|
||||
proxied = (SideEffectBean) beanFactory.getBean("swappable");
|
||||
proxied.doWork();
|
||||
assertEquals(INITIAL_COUNT + 2, proxied.getCount() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidSwaps() {
|
||||
SideEffectBean target1 = (SideEffectBean) beanFactory.getBean("target1");
|
||||
SideEffectBean target2 = (SideEffectBean) beanFactory.getBean("target2");
|
||||
|
||||
SideEffectBean proxied = (SideEffectBean) beanFactory.getBean("swappable");
|
||||
assertEquals(target1.getCount(), proxied.getCount() );
|
||||
proxied.doWork();
|
||||
assertEquals(INITIAL_COUNT + 1, proxied.getCount() );
|
||||
|
||||
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
|
||||
Object old = swapper.swap(target2);
|
||||
assertEquals("Correct old target was returned", target1, old);
|
||||
|
||||
// TODO should be able to make this assertion: need to fix target handling
|
||||
// in AdvisedSupport
|
||||
//assertEquals(target2, ((Advised) proxied).getTarget());
|
||||
|
||||
assertEquals(20, proxied.getCount());
|
||||
proxied.doWork();
|
||||
assertEquals(21, target2.getCount());
|
||||
|
||||
// Swap it back
|
||||
swapper.swap(target1);
|
||||
assertEquals(target1.getCount(), proxied.getCount());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param invalid
|
||||
* @return the message
|
||||
*/
|
||||
private IllegalArgumentException testRejectsSwapToInvalidValue(Object invalid) {
|
||||
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
|
||||
IllegalArgumentException aopex = null;
|
||||
try {
|
||||
swapper.swap(invalid);
|
||||
fail("Shouldn't be able to swap to invalid value [" + invalid + "]");
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// Ok
|
||||
aopex = ex;
|
||||
}
|
||||
|
||||
// It shouldn't be corrupted, it should still work
|
||||
testBasicFunctionality();
|
||||
return aopex;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRejectsSwapToNull() {
|
||||
IllegalArgumentException ex = testRejectsSwapToInvalidValue(null);
|
||||
assertTrue(ex.getMessage().indexOf("null") != -1);
|
||||
}
|
||||
|
||||
// TODO test reject swap to wrong interface or class?
|
||||
// how to decide what's valid?
|
||||
|
||||
|
||||
@Test
|
||||
public void testSerialization() throws Exception {
|
||||
SerializablePerson sp1 = new SerializablePerson();
|
||||
sp1.setName("Tony");
|
||||
SerializablePerson sp2 = new SerializablePerson();
|
||||
sp1.setName("Gordon");
|
||||
|
||||
HotSwappableTargetSource hts = new HotSwappableTargetSource(sp1);
|
||||
ProxyFactory pf = new ProxyFactory();
|
||||
pf.addInterface(Person.class);
|
||||
pf.setTargetSource(hts);
|
||||
pf.addAdvisor(new DefaultPointcutAdvisor(new SerializableNopInterceptor()));
|
||||
Person p = (Person) pf.getProxy();
|
||||
|
||||
assertEquals(sp1.getName(), p.getName());
|
||||
hts.swap(sp2);
|
||||
assertEquals(sp2.getName(), p.getName());
|
||||
|
||||
p = (Person) SerializationTestUtils.serializeAndDeserialize(p);
|
||||
// We need to get a reference to the client-side targetsource
|
||||
hts = (HotSwappableTargetSource) ((Advised) p).getTargetSource();
|
||||
assertEquals(sp2.getName(), p.getName());
|
||||
hts.swap(sp1);
|
||||
assertEquals(sp1.getName(), p.getName());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.target;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
|
||||
/**
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class LazyCreationTargetSourceTests {
|
||||
|
||||
@Test
|
||||
public void testCreateLazy() {
|
||||
TargetSource targetSource = new AbstractLazyCreationTargetSource() {
|
||||
protected Object createObject() {
|
||||
return new InitCountingBean();
|
||||
}
|
||||
public Class<?> getTargetClass() {
|
||||
return InitCountingBean.class;
|
||||
}
|
||||
};
|
||||
|
||||
InitCountingBean proxy = (InitCountingBean) ProxyFactory.getProxy(targetSource);
|
||||
assertEquals("Init count should be 0", 0, InitCountingBean.initCount);
|
||||
assertEquals("Target class incorrect", InitCountingBean.class, targetSource.getTargetClass());
|
||||
assertEquals("Init count should still be 0 after getTargetClass()", 0, InitCountingBean.initCount);
|
||||
|
||||
proxy.doSomething();
|
||||
assertEquals("Init count should now be 1", 1, InitCountingBean.initCount);
|
||||
|
||||
proxy.doSomething();
|
||||
assertEquals("Init count should still be 1", 1, InitCountingBean.initCount);
|
||||
}
|
||||
|
||||
|
||||
private static class InitCountingBean {
|
||||
|
||||
public static int initCount;
|
||||
|
||||
public InitCountingBean() {
|
||||
if (InitCountingBean.class.equals(getClass())) {
|
||||
// only increment when creating the actual target - not the proxy
|
||||
initCount++;
|
||||
}
|
||||
}
|
||||
|
||||
public void doSomething() {
|
||||
//no-op
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.target;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.ITestBean;
|
||||
import org.springframework.beans.factory.xml.XmlBeanFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Chris Beams
|
||||
* @since 07.01.2005
|
||||
*/
|
||||
public class LazyInitTargetSourceTests {
|
||||
|
||||
@Test
|
||||
public void testLazyInitSingletonTargetSource() {
|
||||
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("lazyInitSingletonTests.xml", getClass()));
|
||||
bf.preInstantiateSingletons();
|
||||
|
||||
ITestBean tb = (ITestBean) bf.getBean("proxy");
|
||||
assertFalse(bf.containsSingleton("target"));
|
||||
assertEquals(10, tb.getAge());
|
||||
assertTrue(bf.containsSingleton("target"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomLazyInitSingletonTargetSource() {
|
||||
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("customLazyInitTarget.xml", getClass()));
|
||||
bf.preInstantiateSingletons();
|
||||
|
||||
ITestBean tb = (ITestBean) bf.getBean("proxy");
|
||||
assertFalse(bf.containsSingleton("target"));
|
||||
assertEquals("Rob Harrop", tb.getName());
|
||||
assertTrue(bf.containsSingleton("target"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyInitFactoryBeanTargetSource() {
|
||||
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("lazyInitFactoryBean.xml", getClass()));
|
||||
bf.preInstantiateSingletons();
|
||||
|
||||
Set<?> set1 = (Set<?>) bf.getBean("proxy1");
|
||||
assertFalse(bf.containsSingleton("target1"));
|
||||
assertTrue(set1.contains("10"));
|
||||
assertTrue(bf.containsSingleton("target1"));
|
||||
|
||||
Set<?> set2 = (Set<?>) bf.getBean("proxy2");
|
||||
assertFalse(bf.containsSingleton("target2"));
|
||||
assertTrue(set2.contains("20"));
|
||||
assertTrue(bf.containsSingleton("target2"));
|
||||
}
|
||||
|
||||
|
||||
public static class CustomLazyInitTargetSource extends LazyInitTargetSource {
|
||||
|
||||
protected void postProcessTargetObject(Object targetObject) {
|
||||
((ITestBean) targetObject).setName("Rob Harrop");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.target;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.SerializablePerson;
|
||||
import org.springframework.beans.TestBean;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.util.SerializationTestUtils;
|
||||
|
||||
/**
|
||||
* Unit tests relating to the abstract AbstractPrototypeBasedTargetSource
|
||||
* and not subclasses.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class PrototypeBasedTargetSourceTests {
|
||||
|
||||
@Test
|
||||
public void testSerializability() throws Exception {
|
||||
MutablePropertyValues tsPvs = new MutablePropertyValues();
|
||||
tsPvs.addPropertyValue("targetBeanName", "person");
|
||||
RootBeanDefinition tsBd = new RootBeanDefinition(TestTargetSource.class, tsPvs);
|
||||
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
RootBeanDefinition bd = new RootBeanDefinition(SerializablePerson.class, pvs);
|
||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.registerBeanDefinition("ts", tsBd);
|
||||
bf.registerBeanDefinition("person", bd);
|
||||
|
||||
TestTargetSource cpts = (TestTargetSource) bf.getBean("ts");
|
||||
TargetSource serialized = (TargetSource) SerializationTestUtils.serializeAndDeserialize(cpts);
|
||||
assertTrue("Changed to SingletonTargetSource on deserialization",
|
||||
serialized instanceof SingletonTargetSource);
|
||||
SingletonTargetSource sts = (SingletonTargetSource) serialized;
|
||||
assertNotNull(sts.getTarget());
|
||||
}
|
||||
|
||||
|
||||
private static class TestTargetSource extends AbstractPrototypeBasedTargetSource {
|
||||
|
||||
/**
|
||||
* Nonserializable test field to check that subclass
|
||||
* state can't prevent serialization from working
|
||||
*/
|
||||
private TestBean thisFieldIsNotSerializable = new TestBean();
|
||||
|
||||
public Object getTarget() throws Exception {
|
||||
return newPrototypeInstance();
|
||||
}
|
||||
|
||||
public void releaseTarget(Object target) throws Exception {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.target;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.aop.interceptor.SideEffectBean;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.xml.XmlBeanFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class PrototypeTargetSourceTests {
|
||||
|
||||
/** Initial count value set in bean factory XML */
|
||||
private static final int INITIAL_COUNT = 10;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.beanFactory = new XmlBeanFactory(new ClassPathResource("prototypeTests.xml", getClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that multiple invocations of the prototype bean will result
|
||||
* in no change to visible state, as a new instance is used.
|
||||
* With the singleton, there will be change.
|
||||
*/
|
||||
@Test
|
||||
public void testPrototypeAndSingletonBehaveDifferently() {
|
||||
SideEffectBean singleton = (SideEffectBean) beanFactory.getBean("singleton");
|
||||
assertEquals(INITIAL_COUNT, singleton.getCount() );
|
||||
singleton.doWork();
|
||||
assertEquals(INITIAL_COUNT + 1, singleton.getCount() );
|
||||
|
||||
SideEffectBean prototype = (SideEffectBean) beanFactory.getBean("prototype");
|
||||
assertEquals(INITIAL_COUNT, prototype.getCount() );
|
||||
prototype.doWork();
|
||||
assertEquals(INITIAL_COUNT, prototype.getCount() );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.target;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.aop.interceptor.SideEffectBean;
|
||||
import org.springframework.beans.ITestBean;
|
||||
import org.springframework.beans.factory.xml.XmlBeanFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class ThreadLocalTargetSourceTests {
|
||||
|
||||
/** Initial count value set in bean factory XML */
|
||||
private static final int INITIAL_COUNT = 10;
|
||||
|
||||
private XmlBeanFactory beanFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.beanFactory = new XmlBeanFactory(new ClassPathResource("threadLocalTests.xml", getClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* We must simulate container shutdown, which should clear threads.
|
||||
*/
|
||||
protected void tearDown() {
|
||||
this.beanFactory.destroySingletons();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check we can use two different ThreadLocalTargetSources
|
||||
* managing objects of different types without them interfering
|
||||
* with one another.
|
||||
*/
|
||||
@Test
|
||||
public void testUseDifferentManagedInstancesInSameThread() {
|
||||
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
|
||||
assertEquals(INITIAL_COUNT, apartment.getCount() );
|
||||
apartment.doWork();
|
||||
assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
|
||||
|
||||
ITestBean test = (ITestBean) beanFactory.getBean("threadLocal2");
|
||||
assertEquals("Rod", test.getName());
|
||||
assertEquals("Kerry", test.getSpouse().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReuseInSameThread() {
|
||||
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
|
||||
assertEquals(INITIAL_COUNT, apartment.getCount() );
|
||||
apartment.doWork();
|
||||
assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
|
||||
|
||||
apartment = (SideEffectBean) beanFactory.getBean("apartment");
|
||||
assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Relies on introduction.
|
||||
*/
|
||||
@Test
|
||||
public void testCanGetStatsViaMixin() {
|
||||
ThreadLocalTargetSourceStats stats = (ThreadLocalTargetSourceStats) beanFactory.getBean("apartment");
|
||||
// +1 because creating target for stats call counts
|
||||
assertEquals(1, stats.getInvocationCount());
|
||||
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
|
||||
apartment.doWork();
|
||||
// +1 again
|
||||
assertEquals(3, stats.getInvocationCount());
|
||||
// + 1 for states call!
|
||||
assertEquals(3, stats.getHitCount());
|
||||
apartment.doWork();
|
||||
assertEquals(6, stats.getInvocationCount());
|
||||
assertEquals(6, stats.getHitCount());
|
||||
// Only one thread so only one object can have been bound
|
||||
assertEquals(1, stats.getObjectCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewThreadHasOwnInstance() throws InterruptedException {
|
||||
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
|
||||
assertEquals(INITIAL_COUNT, apartment.getCount() );
|
||||
apartment.doWork();
|
||||
apartment.doWork();
|
||||
apartment.doWork();
|
||||
assertEquals(INITIAL_COUNT + 3, apartment.getCount() );
|
||||
|
||||
class Runner implements Runnable {
|
||||
public SideEffectBean mine;
|
||||
public void run() {
|
||||
this.mine = (SideEffectBean) beanFactory.getBean("apartment");
|
||||
assertEquals(INITIAL_COUNT, mine.getCount() );
|
||||
mine.doWork();
|
||||
assertEquals(INITIAL_COUNT + 1, mine.getCount() );
|
||||
}
|
||||
}
|
||||
Runner r = new Runner();
|
||||
Thread t = new Thread(r);
|
||||
t.start();
|
||||
t.join();
|
||||
|
||||
assertNotNull(r);
|
||||
|
||||
// Check it didn't affect the other thread's copy
|
||||
assertEquals(INITIAL_COUNT + 3, apartment.getCount() );
|
||||
|
||||
// When we use other thread's copy in this thread
|
||||
// it should behave like ours
|
||||
assertEquals(INITIAL_COUNT + 3, r.mine.getCount() );
|
||||
|
||||
// Bound to two threads
|
||||
assertEquals(2, ((ThreadLocalTargetSourceStats) apartment).getObjectCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for SPR-1442. Destroyed target should re-associated with thread and not throw NPE
|
||||
*/
|
||||
@Test
|
||||
public void testReuseDestroyedTarget() {
|
||||
ThreadLocalTargetSource source = (ThreadLocalTargetSource)this.beanFactory.getBean("threadLocalTs");
|
||||
|
||||
// try first time
|
||||
source.getTarget();
|
||||
source.destroy();
|
||||
|
||||
// try second time
|
||||
try {
|
||||
source.getTarget();
|
||||
} catch(NullPointerException ex) {
|
||||
fail("Should not throw NPE");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="testBeanTarget" class="org.springframework.beans.TestBean" scope="prototype"/>
|
||||
|
||||
<bean id="targetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
|
||||
<property name="targetBeanName" value="testBeanTarget"/>
|
||||
</bean>
|
||||
|
||||
<bean id="testBean" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="targetSource" ref="targetSource"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="prototypeTest" class="org.springframework.aop.interceptor.SideEffectBean" scope="prototype">
|
||||
<property name="count"><value>10</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
|
||||
<property name="targetBeanName"><value>prototypeTest</value></property>
|
||||
<property name="maxSize"><value>25</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="poolConfigAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
|
||||
<property name="targetObject"><ref local="poolTargetSource" /></property>
|
||||
<property name="targetMethod"><value>getPoolingConfigMixin</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="nop" class="org.springframework.aop.interceptor.NopInterceptor"/>
|
||||
|
||||
<!--
|
||||
This will create a bean for each thread ("apartment")
|
||||
-->
|
||||
<bean id="pooled" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="targetSource"><ref local="poolTargetSource"/></property>
|
||||
<property name="interceptorNames"><value>nop</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="pooledNoInterceptors" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="targetSource"><ref local="poolTargetSource"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="pooledWithMixin" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="targetSource"><ref local="poolTargetSource"/></property>
|
||||
<property name="interceptorNames"><value>poolConfigAdvisor</value></property>
|
||||
<!-- Necessary as have a mixin and want to avoid losing the class,
|
||||
because there's no target interface -->
|
||||
<property name="proxyTargetClass"><value>true</value></property>
|
||||
</bean>
|
||||
|
||||
<!-- Serialization tests using serializable target and advice -->
|
||||
<bean id="serializableNop" class="org.springframework.aop.interceptor.SerializableNopInterceptor" />
|
||||
|
||||
<bean id="prototypePerson" class="org.springframework.beans.SerializablePerson" scope="prototype"/>
|
||||
|
||||
<bean id="personPoolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
|
||||
<property name="targetBeanName"><value>prototypePerson</value></property>
|
||||
<property name="maxSize"><value>10</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="pooledPerson" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="targetSource"><ref local="personPoolTargetSource"/></property>
|
||||
<property name="interceptorNames"><value>serializableNop</value></property>
|
||||
|
||||
</bean>
|
||||
|
||||
<bean id="maxSizePooledPerson" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="targetSource">
|
||||
<bean class="org.springframework.aop.target.CommonsPoolTargetSource">
|
||||
<property name="targetBeanName" value="prototypePerson"/>
|
||||
<property name="maxSize" value="10"/>
|
||||
<property name="maxWait" value="1"/>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="interceptorNames"><value>serializableNop</value></property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="target" class="org.springframework.beans.TestBean" lazy-init="true">
|
||||
<property name="age"><value>10</value></property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
This will create a proxy that lazily fetches its target bean (with name "target").
|
||||
-->
|
||||
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="targetSource">
|
||||
<bean class="org.springframework.aop.target.LazyInitTargetSourceTests$CustomLazyInitTargetSource">
|
||||
<property name="targetBeanName"><idref local="target"/></property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.target.dynamic;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Rob Harrop
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class RefreshableTargetSourceTests {
|
||||
|
||||
/**
|
||||
* Test what happens when checking for refresh but not refreshing object.
|
||||
*/
|
||||
@Test
|
||||
public void testRefreshCheckWithNonRefresh() throws Exception {
|
||||
CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource();
|
||||
ts.setRefreshCheckDelay(0);
|
||||
|
||||
Object a = ts.getTarget();
|
||||
Thread.sleep(1);
|
||||
Object b = ts.getTarget();
|
||||
|
||||
assertEquals("Should be one call to freshTarget to get initial target", 1, ts.getCallCount());
|
||||
assertSame("Returned objects should be the same - no refresh should occur", a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test what happens when checking for refresh and refresh occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testRefreshCheckWithRefresh() throws Exception {
|
||||
CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(true);
|
||||
ts.setRefreshCheckDelay(0);
|
||||
|
||||
Object a = ts.getTarget();
|
||||
Thread.sleep(100);
|
||||
Object b = ts.getTarget();
|
||||
|
||||
assertEquals("Should have called freshTarget twice", 2, ts.getCallCount());
|
||||
assertNotSame("Should be different objects", a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test what happens when no refresh occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testWithNoRefreshCheck() throws Exception {
|
||||
CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(true);
|
||||
ts.setRefreshCheckDelay(-1);
|
||||
|
||||
Object a = ts.getTarget();
|
||||
Object b = ts.getTarget();
|
||||
|
||||
assertEquals("Refresh target should only be called once", 1, ts.getCallCount());
|
||||
assertSame("Objects should be the same - refresh check delay not elapsed", a, b);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshOverTime() throws Exception {
|
||||
CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(true);
|
||||
ts.setRefreshCheckDelay(100);
|
||||
|
||||
Object a = ts.getTarget();
|
||||
Object b = ts.getTarget();
|
||||
assertEquals("Objects should be same", a, b);
|
||||
|
||||
Thread.sleep(50);
|
||||
|
||||
Object c = ts.getTarget();
|
||||
assertEquals("A and C should be same", a, c);
|
||||
|
||||
Thread.sleep(60);
|
||||
|
||||
Object d = ts.getTarget();
|
||||
assertNotNull("D should not be null", d);
|
||||
assertFalse("A and D should not be equal", a.equals(d));
|
||||
|
||||
Object e = ts.getTarget();
|
||||
assertEquals("D and E should be equal", d, e);
|
||||
|
||||
Thread.sleep(110);
|
||||
|
||||
Object f = ts.getTarget();
|
||||
assertFalse("E and F should be different", e.equals(f));
|
||||
}
|
||||
|
||||
|
||||
private static class CountingRefreshableTargetSource extends AbstractRefreshableTargetSource {
|
||||
|
||||
private int callCount;
|
||||
|
||||
private boolean requiresRefresh;
|
||||
|
||||
public CountingRefreshableTargetSource() {
|
||||
}
|
||||
|
||||
public CountingRefreshableTargetSource(boolean requiresRefresh) {
|
||||
this.requiresRefresh = requiresRefresh;
|
||||
}
|
||||
|
||||
protected Object freshTarget() {
|
||||
this.callCount++;
|
||||
return new Object();
|
||||
}
|
||||
|
||||
public int getCallCount() {
|
||||
return this.callCount;
|
||||
}
|
||||
|
||||
protected boolean requiresRefresh() {
|
||||
return this.requiresRefresh;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<!-- Simple target -->
|
||||
<bean id="target1" class="org.springframework.aop.interceptor.SideEffectBean">
|
||||
<property name="count"><value>10</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="target2" class="org.springframework.aop.interceptor.SideEffectBean" scope="singleton">
|
||||
<property name="count"><value>20</value></property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
Hot swappable target source. Note the use of Type 3 IoC.
|
||||
-->
|
||||
<bean id="swapper" class="org.springframework.aop.target.HotSwappableTargetSource">
|
||||
<constructor-arg><ref local="target1"/></constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="swappable" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="targetSource"><ref local="swapper"/></property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="target1" class="org.springframework.beans.factory.config.SetFactoryBean" lazy-init="true">
|
||||
<property name="sourceSet">
|
||||
<set>
|
||||
<value>10</value>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
This will create a proxy that lazily fetches its target bean (with name "target").
|
||||
-->
|
||||
<bean id="proxy1" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="proxyInterfaces" value="java.util.Set"/>
|
||||
<property name="targetSource">
|
||||
<bean class="org.springframework.aop.target.LazyInitTargetSource">
|
||||
<property name="targetBeanName" value="target1"/>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="target2" class="org.springframework.beans.factory.config.SetFactoryBean" lazy-init="true">
|
||||
<property name="sourceSet">
|
||||
<set>
|
||||
<value>20</value>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
This will create a proxy that lazily fetches its target bean (with name "target").
|
||||
-->
|
||||
<bean id="proxy2" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="autodetectInterfaces" value="true"/>
|
||||
<property name="targetSource">
|
||||
<bean class="org.springframework.aop.target.LazyInitTargetSource">
|
||||
<property name="targetBeanName" value="target2"/>
|
||||
<property name="targetClass" value="java.util.Set"/>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="target" class="org.springframework.beans.TestBean" lazy-init="true">
|
||||
<property name="age"><value>10</value></property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
This will create a proxy that lazily fetches its target bean (with name "target").
|
||||
-->
|
||||
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="targetSource">
|
||||
<bean class="org.springframework.aop.target.LazyInitTargetSource">
|
||||
<property name="targetBeanName"><idref local="target"/></property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<!-- Simple target -->
|
||||
<bean id="test" class="org.springframework.aop.interceptor.SideEffectBean">
|
||||
<property name="count"><value>10</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="prototypeTest" class="org.springframework.aop.interceptor.SideEffectBean" scope="prototype">
|
||||
<property name="count"><value>10</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource">
|
||||
<property name="targetBeanName"><value>prototypeTest</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.NopInterceptor" />
|
||||
|
||||
<bean id="singleton" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="interceptorNames"><value>debugInterceptor,test</value></property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
This will create a bean that creates a new target on each invocation.
|
||||
-->
|
||||
<bean id="prototype" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="targetSource"><ref local="prototypeTargetSource"/></property>
|
||||
<property name="interceptorNames"><value>debugInterceptor</value></property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="prototypeTest" class="org.springframework.aop.interceptor.SideEffectBean" scope="prototype">
|
||||
<property name="count"><value>10</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="threadLocalTs" class="org.springframework.aop.target.ThreadLocalTargetSource">
|
||||
<property name="targetBeanName"><value>prototypeTest</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.NopInterceptor" />
|
||||
|
||||
<!--
|
||||
We want to invoke the getStatsMixin method on our ThreadLocal invoker
|
||||
-->
|
||||
<bean id="statsAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
|
||||
<property name="targetObject"><ref local="threadLocalTs" /></property>
|
||||
<property name="targetMethod"><value>getStatsMixin</value></property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
This will create a bean for each thread ("apartment")
|
||||
-->
|
||||
<bean id="apartment" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="interceptorNames"><value>debugInterceptor,statsAdvisor</value></property>
|
||||
<property name="targetSource"><ref local="threadLocalTs"/></property>
|
||||
<!-- Necessary as have a mixin and want to avoid losing the class,
|
||||
because there's no target interface -->
|
||||
<property name="proxyTargetClass"><value>true</value></property>
|
||||
</bean>
|
||||
|
||||
<!-- ================ Definitions for second ThreadLocalTargetSource ====== -->
|
||||
|
||||
<bean id="test" class="org.springframework.beans.TestBean" scope="prototype">
|
||||
<property name="name"><value>Rod</value></property>
|
||||
<property name="spouse"><ref local="wife"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="wife" class="org.springframework.beans.TestBean">
|
||||
<property name="name"><value>Kerry</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="threadLocalTs2" class="org.springframework.aop.target.ThreadLocalTargetSource">
|
||||
<property name="targetBeanName"><value>test</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="threadLocal2" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="targetSource"><ref local="threadLocalTs2"/></property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
Reference in New Issue
Block a user