DefaultAdvisorChainFactory never passes null into ClassFilter, enabling async advisor to work without target class as well
Issue: SPR-11910
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -32,10 +32,10 @@ public interface AdvisorChainFactory {
|
|||||||
* for the given advisor chain configuration.
|
* for the given advisor chain configuration.
|
||||||
* @param config the AOP configuration in the form of an Advised object
|
* @param config the AOP configuration in the form of an Advised object
|
||||||
* @param method the proxied method
|
* @param method the proxied method
|
||||||
* @param targetClass the target class
|
* @param targetClass the target class (may be {@code null} to indicate a proxy without
|
||||||
|
* target object, in which case the method's declaring class is the next best option)
|
||||||
* @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
|
* @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
|
||||||
*/
|
*/
|
||||||
List<Object> getInterceptorsAndDynamicInterceptionAdvice(
|
List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, Class<?> targetClass);
|
||||||
Advised config, Method method, Class<?> targetClass);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2012 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -50,19 +50,21 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
|
|||||||
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
|
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
|
||||||
Advised config, Method method, Class<?> targetClass) {
|
Advised config, Method method, Class<?> targetClass) {
|
||||||
|
|
||||||
// This is somewhat tricky... we have to process introductions first,
|
// This is somewhat tricky... We have to process introductions first,
|
||||||
// but we need to preserve order in the ultimate list.
|
// but we need to preserve order in the ultimate list.
|
||||||
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
|
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
|
||||||
boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
|
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
|
||||||
|
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
|
||||||
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
|
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
|
||||||
|
|
||||||
for (Advisor advisor : config.getAdvisors()) {
|
for (Advisor advisor : config.getAdvisors()) {
|
||||||
if (advisor instanceof PointcutAdvisor) {
|
if (advisor instanceof PointcutAdvisor) {
|
||||||
// Add it conditionally.
|
// Add it conditionally.
|
||||||
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
|
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
|
||||||
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
|
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
|
||||||
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
|
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
|
||||||
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
|
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
|
||||||
if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
|
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
|
||||||
if (mm.isRuntime()) {
|
if (mm.isRuntime()) {
|
||||||
// Creating a new object instance in the getInterceptors() method
|
// Creating a new object instance in the getInterceptors() method
|
||||||
// isn't a problem as we normally cache created chains.
|
// isn't a problem as we normally cache created chains.
|
||||||
@@ -78,7 +80,7 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
|
|||||||
}
|
}
|
||||||
else if (advisor instanceof IntroductionAdvisor) {
|
else if (advisor instanceof IntroductionAdvisor) {
|
||||||
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
|
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
|
||||||
if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {
|
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
|
||||||
Interceptor[] interceptors = registry.getInterceptors(advisor);
|
Interceptor[] interceptors = registry.getInterceptors(advisor);
|
||||||
interceptorList.addAll(Arrays.asList(interceptors));
|
interceptorList.addAll(Arrays.asList(interceptors));
|
||||||
}
|
}
|
||||||
@@ -88,18 +90,19 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
|
|||||||
interceptorList.addAll(Arrays.asList(interceptors));
|
interceptorList.addAll(Arrays.asList(interceptors));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return interceptorList;
|
return interceptorList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether the Advisors contain matching introductions.
|
* Determine whether the Advisors contain matching introductions.
|
||||||
*/
|
*/
|
||||||
private static boolean hasMatchingIntroductions(Advised config, Class<?> targetClass) {
|
private static boolean hasMatchingIntroductions(Advised config, Class<?> actualClass) {
|
||||||
for (int i = 0; i < config.getAdvisors().length; i++) {
|
for (int i = 0; i < config.getAdvisors().length; i++) {
|
||||||
Advisor advisor = config.getAdvisors()[i];
|
Advisor advisor = config.getAdvisors()[i];
|
||||||
if (advisor instanceof IntroductionAdvisor) {
|
if (advisor instanceof IntroductionAdvisor) {
|
||||||
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
|
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
|
||||||
if (ia.getClassFilter().matches(targetClass)) {
|
if (ia.getClassFilter().matches(actualClass)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,12 +27,15 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.remoting.support.RemoteInvocation;
|
||||||
|
import org.springframework.remoting.support.RemoteInvocationResult;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
*/
|
*/
|
||||||
public class HttpInvokerFactoryBeanIntegrationTests {
|
public class HttpInvokerFactoryBeanIntegrationTests {
|
||||||
@@ -42,6 +45,8 @@ public class HttpInvokerFactoryBeanIntegrationTests {
|
|||||||
ApplicationContext context = new AnnotationConfigApplicationContext(InvokerAutowiringConfig.class);
|
ApplicationContext context = new AnnotationConfigApplicationContext(InvokerAutowiringConfig.class);
|
||||||
MyBean myBean = context.getBean("myBean", MyBean.class);
|
MyBean myBean = context.getBean("myBean", MyBean.class);
|
||||||
assertSame(context.getBean("myService"), myBean.myService);
|
assertSame(context.getBean("myService"), myBean.myService);
|
||||||
|
myBean.myService.handle();
|
||||||
|
myBean.myService.handleAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -51,10 +56,17 @@ public class HttpInvokerFactoryBeanIntegrationTests {
|
|||||||
context.refresh();
|
context.refresh();
|
||||||
MyBean myBean = context.getBean("myBean", MyBean.class);
|
MyBean myBean = context.getBean("myBean", MyBean.class);
|
||||||
assertSame(context.getBean("myService"), myBean.myService);
|
assertSame(context.getBean("myService"), myBean.myService);
|
||||||
|
myBean.myService.handle();
|
||||||
|
myBean.myService.handleAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public interface MyService {
|
public interface MyService {
|
||||||
|
|
||||||
|
public void handle();
|
||||||
|
|
||||||
|
@Async
|
||||||
|
public void handleAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -62,7 +74,7 @@ public class HttpInvokerFactoryBeanIntegrationTests {
|
|||||||
public static class MyBean {
|
public static class MyBean {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MyService myService;
|
public MyService myService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -71,11 +83,23 @@ public class HttpInvokerFactoryBeanIntegrationTests {
|
|||||||
@Lazy
|
@Lazy
|
||||||
public static class InvokerAutowiringConfig {
|
public static class InvokerAutowiringConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AsyncAnnotationBeanPostProcessor aabpp() {
|
||||||
|
return new AsyncAnnotationBeanPostProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public HttpInvokerProxyFactoryBean myService() {
|
public HttpInvokerProxyFactoryBean myService() {
|
||||||
HttpInvokerProxyFactoryBean factory = new HttpInvokerProxyFactoryBean();
|
HttpInvokerProxyFactoryBean factory = new HttpInvokerProxyFactoryBean();
|
||||||
factory.setServiceUrl("/svc/dummy");
|
factory.setServiceUrl("/svc/dummy");
|
||||||
factory.setServiceInterface(MyService.class);
|
factory.setServiceInterface(MyService.class);
|
||||||
|
Thread thread = Thread.currentThread();
|
||||||
|
factory.setHttpInvokerRequestExecutor(new HttpInvokerRequestExecutor() {
|
||||||
|
@Override
|
||||||
|
public RemoteInvocationResult executeRequest(HttpInvokerClientConfiguration config, RemoteInvocation invocation) {
|
||||||
|
return new RemoteInvocationResult(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user