AbstractAdvisingBeanPostProcessor uses target class check for existing proxy but checks against actual exposed object otherwise (catching introductions)

Issue: SPR-11725
This commit is contained in:
Juergen Hoeller
2014-04-29 15:44:55 +02:00
parent 26a9c4bc01
commit a0658c5832
2 changed files with 246 additions and 25 deletions

View File

@@ -18,19 +18,22 @@ package org.springframework.scheduling.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.concurrent.Future;
import org.junit.Before;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.tests.Assume;
import org.springframework.tests.TestGroup;
import static org.junit.Assert.*;
@@ -46,10 +49,6 @@ public class AsyncExecutionTests {
private static int listenerConstructed = 0;
@Before
public void setUp() {
Assume.group(TestGroup.PERFORMANCE);
}
@Test
public void asyncMethods() throws Exception {
@@ -135,6 +134,46 @@ public class AsyncExecutionTests {
assertEquals("20", future.get());
}
@Test
public void asyncClassWithPostProcessor() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncClassBean.class));
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
context.refresh();
AsyncClassBean asyncTest = context.getBean("asyncTest", AsyncClassBean.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void asyncClassWithInterface() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncClassBeanWithInterface.class));
context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class));
context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class));
context.refresh();
RegularInterface asyncTest = context.getBean("asyncTest", RegularInterface.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void asyncClassWithInterfaceAndPostProcessor() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncClassBeanWithInterface.class));
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
context.refresh();
RegularInterface asyncTest = context.getBean("asyncTest", RegularInterface.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void asyncInterface() throws Exception {
originalThreadName = Thread.currentThread().getName();
@@ -149,6 +188,46 @@ public class AsyncExecutionTests {
assertEquals("20", future.get());
}
@Test
public void asyncInterfaceWithPostProcessor() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncInterfaceBean.class));
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
context.refresh();
AsyncInterface asyncTest = context.getBean("asyncTest", AsyncInterface.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void dynamicAsyncInterface() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(DynamicAsyncInterfaceBean.class));
context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class));
context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class));
context.refresh();
AsyncInterface asyncTest = context.getBean("asyncTest", AsyncInterface.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void dynamicAsyncInterfaceWithPostProcessor() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(DynamicAsyncInterfaceBean.class));
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
context.refresh();
AsyncInterface asyncTest = context.getBean("asyncTest", AsyncInterface.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void asyncMethodsInInterface() throws Exception {
originalThreadName = Thread.currentThread().getName();
@@ -164,6 +243,33 @@ public class AsyncExecutionTests {
assertEquals("20", future.get());
}
@Test
public void asyncMethodsInInterfaceWithPostProcessor() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncMethodsInterfaceBean.class));
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
context.refresh();
AsyncMethodsInterface asyncTest = context.getBean("asyncTest", AsyncMethodsInterface.class);
asyncTest.doNothing(5);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void dynamicAsyncMethodsInInterfaceWithPostProcessor() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(DynamicAsyncMethodsInterfaceBean.class));
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
context.refresh();
AsyncMethodsInterface asyncTest = context.getBean("asyncTest", AsyncMethodsInterface.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void asyncMethodListener() throws Exception {
originalThreadName = Thread.currentThread().getName();
@@ -304,6 +410,28 @@ public class AsyncExecutionTests {
}
public interface RegularInterface {
void doSomething(int i);
Future<String> returnSomething(int i);
}
@Async
public static class AsyncClassBeanWithInterface implements RegularInterface {
public void doSomething(int i) {
assertTrue(!Thread.currentThread().getName().equals(originalThreadName));
}
public Future<String> returnSomething(int i) {
assertTrue(!Thread.currentThread().getName().equals(originalThreadName));
return new AsyncResult<String>(Integer.toString(i));
}
}
@Async
public interface AsyncInterface {
@@ -328,6 +456,44 @@ public class AsyncExecutionTests {
}
public static class DynamicAsyncInterfaceBean implements FactoryBean<AsyncInterface> {
private final AsyncInterface proxy;
public DynamicAsyncInterfaceBean() {
ProxyFactory pf = new ProxyFactory(new HashMap<>());
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
assertTrue(!Thread.currentThread().getName().equals(originalThreadName));
if (Future.class.equals(invocation.getMethod().getReturnType())) {
return new AsyncResult<String>(invocation.getArguments()[0].toString());
}
return null;
}
});
advisor.addInterface(AsyncInterface.class);
pf.addAdvisor(advisor);
this.proxy = (AsyncInterface) pf.getProxy();
}
@Override
public AsyncInterface getObject() {
return this.proxy;
}
@Override
public Class<?> getObjectType() {
return this.proxy.getClass();
}
@Override
public boolean isSingleton() {
return true;
}
}
public interface AsyncMethodsInterface {
void doNothing(int i);
@@ -360,6 +526,44 @@ public class AsyncExecutionTests {
}
public static class DynamicAsyncMethodsInterfaceBean implements FactoryBean<AsyncMethodsInterface> {
private final AsyncMethodsInterface proxy;
public DynamicAsyncMethodsInterfaceBean() {
ProxyFactory pf = new ProxyFactory(new HashMap<>());
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
assertTrue(!Thread.currentThread().getName().equals(originalThreadName));
if (Future.class.equals(invocation.getMethod().getReturnType())) {
return new AsyncResult<String>(invocation.getArguments()[0].toString());
}
return null;
}
});
advisor.addInterface(AsyncMethodsInterface.class);
pf.addAdvisor(advisor);
this.proxy = (AsyncMethodsInterface) pf.getProxy();
}
@Override
public AsyncMethodsInterface getObject() {
return this.proxy;
}
@Override
public Class<?> getObjectType() {
return this.proxy.getClass();
}
@Override
public boolean isSingleton() {
return true;
}
}
public static class AsyncMethodListener implements ApplicationListener<ApplicationEvent> {
@Override