Skip to content

Commit 1cd0135

Browse files
committed
Restore original DefaultAdvisorChainFactory MethodMatcher invocation
Includes test for @async pointcut against AOP proxy without target.
1 parent 0c5c310 commit 1cd0135

File tree

9 files changed

+57
-37
lines changed

9 files changed

+57
-37
lines changed

spring-aop/src/main/java/org/springframework/aop/MethodMatcher.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -50,10 +50,11 @@
5050
public interface MethodMatcher {
5151

5252
/**
53-
* Perform static checking whether the given method matches. If this
54-
* returns {@code false} or if the {@link #isRuntime()} method
55-
* returns {@code false}, no runtime check (i.e. no.
56-
* {@link #matches(java.lang.reflect.Method, Class, Object[])} call) will be made.
53+
* Perform static checking whether the given method matches.
54+
* <p>If this returns {@code false} or if the {@link #isRuntime()}
55+
* method returns {@code false}, no runtime check (i.e. no
56+
* {@link #matches(java.lang.reflect.Method, Class, Object[])} call)
57+
* will be made.
5758
* @param method the candidate method
5859
* @param targetClass the target class (may be {@code null}, in which case
5960
* the candidate class must be taken to be the method's declaring class)

spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,12 @@ public TargetSource getTargetSource() {
152152
* @see #setTargetSource
153153
* @see #setTarget
154154
*/
155-
public void setTargetClass(Class<?> targetClass) {
155+
public void setTargetClass(@Nullable Class<?> targetClass) {
156156
this.targetSource = EmptyTargetSource.forClass(targetClass);
157157
}
158158

159159
@Override
160+
@Nullable
160161
public Class<?> getTargetClass() {
161162
return this.targetSource.getTargetClass();
162163
}

spring-aop/src/main/java/org/springframework/aop/framework/DefaultAdvisorChainFactory.java

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@
2727

2828
import org.springframework.aop.Advisor;
2929
import org.springframework.aop.IntroductionAdvisor;
30-
import org.springframework.aop.IntroductionAwareMethodMatcher;
3130
import org.springframework.aop.MethodMatcher;
3231
import org.springframework.aop.PointcutAdvisor;
3332
import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
3433
import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
34+
import org.springframework.aop.support.MethodMatchers;
3535
import org.springframework.lang.Nullable;
3636

3737
/**
@@ -53,29 +53,18 @@ public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
5353

5454
// This is somewhat tricky... We have to process introductions first,
5555
// but we need to preserve order in the ultimate list.
56-
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
57-
Advisor[] advisors = config.getAdvisors();
58-
List<Object> interceptorList = new ArrayList<>(advisors.length);
56+
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
5957
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
60-
Boolean hasIntroductions = null;
58+
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
59+
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
6160

62-
for (Advisor advisor : advisors) {
61+
for (Advisor advisor : config.getAdvisors()) {
6362
if (advisor instanceof PointcutAdvisor) {
6463
// Add it conditionally.
6564
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
6665
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
6766
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
68-
boolean match;
69-
if (mm instanceof IntroductionAwareMethodMatcher) {
70-
if (hasIntroductions == null) {
71-
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
72-
}
73-
match = ((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions);
74-
}
75-
else {
76-
match = mm.matches(method, targetClass);
77-
}
78-
if (match) {
67+
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
7968
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
8069
if (mm.isRuntime()) {
8170
// Creating a new object instance in the getInterceptors() method
@@ -109,8 +98,8 @@ else if (advisor instanceof IntroductionAdvisor) {
10998
/**
11099
* Determine whether the Advisors contain matching introductions.
111100
*/
112-
private static boolean hasMatchingIntroductions(Advisor[] advisors, Class<?> actualClass) {
113-
for (Advisor advisor : advisors) {
101+
private static boolean hasMatchingIntroductions(Advised config, Class<?> actualClass) {
102+
for (Advisor advisor : config.getAdvisors()) {
114103
if (advisor instanceof IntroductionAdvisor) {
115104
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
116105
if (ia.getClassFilter().matches(actualClass)) {

spring-aop/src/main/java/org/springframework/aop/support/AbstractRegexpMethodPointcut.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -131,8 +131,9 @@ public String[] getExcludedPatterns() {
131131
*/
132132
@Override
133133
public boolean matches(Method method, @Nullable Class<?> targetClass) {
134-
return ((targetClass != null && matchesPattern(ClassUtils.getQualifiedMethodName(method, targetClass))) ||
135-
matchesPattern(ClassUtils.getQualifiedMethodName(method)));
134+
return ((targetClass != null && targetClass != method.getDeclaringClass() &&
135+
matchesPattern(ClassUtils.getQualifiedMethodName(method, targetClass))) ||
136+
matchesPattern(ClassUtils.getQualifiedMethodName(method, method.getDeclaringClass())));
136137
}
137138

138139
/**

spring-aop/src/main/java/org/springframework/aop/support/DynamicMethodMatcher.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@
2424
/**
2525
* Convenient abstract superclass for dynamic method matchers,
2626
* which do care about arguments at runtime.
27+
*
28+
* @author Rod Johnson
2729
*/
2830
public abstract class DynamicMethodMatcher implements MethodMatcher {
2931

spring-aop/src/main/java/org/springframework/aop/support/RootClassFilter.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,7 +21,8 @@
2121
import org.springframework.aop.ClassFilter;
2222

2323
/**
24-
* Simple ClassFilter implementation that passes classes (and optionally subclasses)
24+
* Simple ClassFilter implementation that passes classes (and optionally subclasses).
25+
*
2526
* @author Rod Johnson
2627
*/
2728
@SuppressWarnings("serial")
@@ -37,7 +38,7 @@ public RootClassFilter(Class<?> clazz) {
3738

3839
@Override
3940
public boolean matches(Class<?> candidate) {
40-
return clazz.isAssignableFrom(candidate);
41+
return this.clazz.isAssignableFrom(candidate);
4142
}
4243

4344
}

spring-aop/src/main/java/org/springframework/aop/support/StaticMethodMatcher.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@
2424
/**
2525
* Convenient abstract superclass for static method matchers, which don't care
2626
* about arguments at runtime.
27+
*
28+
* @author Rod Johnson
2729
*/
2830
public abstract class StaticMethodMatcher implements MethodMatcher {
2931

spring-context/src/test/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessorTests.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,8 +23,10 @@
2323
import java.util.concurrent.Future;
2424
import java.util.concurrent.TimeUnit;
2525

26+
import org.aopalliance.intercept.MethodInterceptor;
2627
import org.junit.Test;
2728

29+
import org.springframework.aop.framework.ProxyFactory;
2830
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
2931
import org.springframework.aop.support.AopUtils;
3032
import org.springframework.beans.factory.config.BeanDefinition;
@@ -62,6 +64,26 @@ public void proxyCreated() {
6264
public void invokedAsynchronously() {
6365
ConfigurableApplicationContext context = initContext(
6466
new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
67+
68+
ITestBean testBean = context.getBean("target", ITestBean.class);
69+
testBean.test();
70+
Thread mainThread = Thread.currentThread();
71+
testBean.await(3000);
72+
Thread asyncThread = testBean.getThread();
73+
assertNotSame(mainThread, asyncThread);
74+
context.close();
75+
}
76+
77+
@Test
78+
public void invokedAsynchronouslyOnProxyTarget() {
79+
StaticApplicationContext context = new StaticApplicationContext();
80+
context.registerBeanDefinition("postProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
81+
TestBean tb = new TestBean();
82+
ProxyFactory pf = new ProxyFactory(ITestBean.class,
83+
(MethodInterceptor) invocation -> invocation.getMethod().invoke(tb, invocation.getArguments()));
84+
context.registerBean("target", ITestBean.class, () -> (ITestBean) pf.getProxy());
85+
context.refresh();
86+
6587
ITestBean testBean = context.getBean("target", ITestBean.class);
6688
testBean.test();
6789
Thread mainThread = Thread.currentThread();
@@ -79,6 +101,7 @@ public void threadNamePrefix() {
79101
executor.afterPropertiesSet();
80102
processorDefinition.getPropertyValues().add("executor", executor);
81103
ConfigurableApplicationContext context = initContext(processorDefinition);
104+
82105
ITestBean testBean = context.getBean("target", ITestBean.class);
83106
testBean.test();
84107
testBean.await(3000);
@@ -246,8 +269,7 @@ public void exceptionHandlerThrowsUnexpectedException() {
246269

247270
private ConfigurableApplicationContext initContext(BeanDefinition asyncAnnotationBeanPostProcessorDefinition) {
248271
StaticApplicationContext context = new StaticApplicationContext();
249-
BeanDefinition targetDefinition =
250-
new RootBeanDefinition(AsyncAnnotationBeanPostProcessorTests.TestBean.class);
272+
BeanDefinition targetDefinition = new RootBeanDefinition(TestBean.class);
251273
context.registerBeanDefinition("postProcessor", asyncAnnotationBeanPostProcessorDefinition);
252274
context.registerBeanDefinition("target", targetDefinition);
253275
context.refresh();
@@ -259,6 +281,7 @@ private interface ITestBean {
259281

260282
Thread getThread();
261283

284+
@Async
262285
void test();
263286

264287
Future<Object> failWithFuture();

spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionInterceptor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttribu
8888

8989
@Override
9090
@Nullable
91-
public Object invoke(final MethodInvocation invocation) throws Throwable {
91+
public Object invoke(MethodInvocation invocation) throws Throwable {
9292
// Work out the target class: may be {@code null}.
9393
// The TransactionAttributeSource should be passed the target class
9494
// as well as the method, which may be from an interface.

0 commit comments

Comments
 (0)