DefaultAdvisorChainFactory never passes null into ClassFilter, enabling async advisor to work without target class as well
Issue: SPR-11910
This commit is contained in:
parent
9796af72db
commit
a9b650fd0f
|
@ -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");
|
||||
* 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.
|
||||
* @param config the AOP configuration in the form of an Advised object
|
||||
* @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)
|
||||
*/
|
||||
List<Object> getInterceptorsAndDynamicInterceptionAdvice(
|
||||
Advised config, Method method, Class<?> targetClass);
|
||||
List<Object> getInterceptorsAndDynamicInterceptionAdvice(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");
|
||||
* 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(
|
||||
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.
|
||||
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();
|
||||
|
||||
for (Advisor advisor : config.getAdvisors()) {
|
||||
if (advisor instanceof PointcutAdvisor) {
|
||||
// Add it conditionally.
|
||||
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);
|
||||
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
|
||||
if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
|
||||
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
|
||||
if (mm.isRuntime()) {
|
||||
// Creating a new object instance in the getInterceptors() method
|
||||
// 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) {
|
||||
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
|
||||
if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {
|
||||
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
|
||||
Interceptor[] interceptors = registry.getInterceptors(advisor);
|
||||
interceptorList.addAll(Arrays.asList(interceptors));
|
||||
}
|
||||
|
@ -88,18 +90,19 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
|
|||
interceptorList.addAll(Arrays.asList(interceptors));
|
||||
}
|
||||
}
|
||||
|
||||
return interceptorList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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++) {
|
||||
Advisor advisor = config.getAdvisors()[i];
|
||||
if (advisor instanceof IntroductionAdvisor) {
|
||||
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
|
||||
if (ia.getClassFilter().matches(targetClass)) {
|
||||
if (ia.getClassFilter().matches(actualClass)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,12 +27,15 @@ import org.springframework.context.annotation.Bean;
|
|||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
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 static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class HttpInvokerFactoryBeanIntegrationTests {
|
||||
|
@ -42,6 +45,8 @@ public class HttpInvokerFactoryBeanIntegrationTests {
|
|||
ApplicationContext context = new AnnotationConfigApplicationContext(InvokerAutowiringConfig.class);
|
||||
MyBean myBean = context.getBean("myBean", MyBean.class);
|
||||
assertSame(context.getBean("myService"), myBean.myService);
|
||||
myBean.myService.handle();
|
||||
myBean.myService.handleAsync();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -51,10 +56,17 @@ public class HttpInvokerFactoryBeanIntegrationTests {
|
|||
context.refresh();
|
||||
MyBean myBean = context.getBean("myBean", MyBean.class);
|
||||
assertSame(context.getBean("myService"), myBean.myService);
|
||||
myBean.myService.handle();
|
||||
myBean.myService.handleAsync();
|
||||
}
|
||||
|
||||
|
||||
public interface MyService {
|
||||
|
||||
public void handle();
|
||||
|
||||
@Async
|
||||
public void handleAsync();
|
||||
}
|
||||
|
||||
|
||||
|
@ -62,7 +74,7 @@ public class HttpInvokerFactoryBeanIntegrationTests {
|
|||
public static class MyBean {
|
||||
|
||||
@Autowired
|
||||
private MyService myService;
|
||||
public MyService myService;
|
||||
}
|
||||
|
||||
|
||||
|
@ -71,11 +83,23 @@ public class HttpInvokerFactoryBeanIntegrationTests {
|
|||
@Lazy
|
||||
public static class InvokerAutowiringConfig {
|
||||
|
||||
@Bean
|
||||
public AsyncAnnotationBeanPostProcessor aabpp() {
|
||||
return new AsyncAnnotationBeanPostProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HttpInvokerProxyFactoryBean myService() {
|
||||
HttpInvokerProxyFactoryBean factory = new HttpInvokerProxyFactoryBean();
|
||||
factory.setServiceUrl("/svc/dummy");
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue