Merge branch '5.2.x'
This commit is contained in:
commit
0bfcabebf3
|
|
@ -59,15 +59,15 @@ class AspectJAutoProxyAdviceOrderIntegrationTests {
|
|||
class AfterAdviceFirstTests {
|
||||
|
||||
@Test
|
||||
void afterAdviceIsNotInvokedLast(@Autowired Echo echo, @Autowired AfterAdviceFirstAspect aspect) throws Exception {
|
||||
void afterAdviceIsInvokedLast(@Autowired Echo echo, @Autowired AfterAdviceFirstAspect aspect) throws Exception {
|
||||
assertThat(aspect.invocations).isEmpty();
|
||||
assertThat(echo.echo(42)).isEqualTo(42);
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after", "after returning");
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "after returning", "after", "around - end");
|
||||
|
||||
aspect.invocations.clear();
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(
|
||||
() -> echo.echo(new Exception()));
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after", "after throwing");
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "after throwing", "after", "around - end");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ class AspectJAutoProxyAdviceOrderIntegrationTests {
|
|||
* in its source code.
|
||||
*
|
||||
* <p>On Java versions prior to JDK 7, we would have expected the {@code @After}
|
||||
* advice method to be invoked after {@code @AfterThrowing} and
|
||||
* advice method to be invoked before {@code @AfterThrowing} and
|
||||
* {@code @AfterReturning} advice methods due to the AspectJ precedence
|
||||
* rules implemented in
|
||||
* {@link org.springframework.aop.aspectj.autoproxy.AspectJPrecedenceComparator}.
|
||||
|
|
@ -89,15 +89,15 @@ class AspectJAutoProxyAdviceOrderIntegrationTests {
|
|||
class AfterAdviceLastTests {
|
||||
|
||||
@Test
|
||||
void afterAdviceIsNotInvokedLast(@Autowired Echo echo, @Autowired AfterAdviceLastAspect aspect) throws Exception {
|
||||
void afterAdviceIsInvokedLast(@Autowired Echo echo, @Autowired AfterAdviceLastAspect aspect) throws Exception {
|
||||
assertThat(aspect.invocations).isEmpty();
|
||||
assertThat(echo.echo(42)).isEqualTo(42);
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after", "after returning");
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "after returning", "after", "around - end");
|
||||
|
||||
aspect.invocations.clear();
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(
|
||||
() -> echo.echo(new Exception()));
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after", "after throwing");
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "after throwing", "after", "around - end");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,14 +56,15 @@ import org.springframework.util.comparator.InstanceComparator;
|
|||
|
||||
/**
|
||||
* Factory that can create Spring AOP Advisors given AspectJ classes from
|
||||
* classes honoring the AspectJ 5 annotation syntax, using reflection to
|
||||
* invoke the corresponding advice methods.
|
||||
* classes honoring AspectJ's annotation syntax, using reflection to invoke the
|
||||
* corresponding advice methods.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Adrian Colyer
|
||||
* @author Juergen Hoeller
|
||||
* @author Ramnivas Laddad
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
|
@ -72,6 +73,11 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
|||
private static final Comparator<Method> METHOD_COMPARATOR;
|
||||
|
||||
static {
|
||||
// Note: although @After is ordered before @AfterReturning and @AfterThrowing,
|
||||
// an @After advice method will actually be invoked after @AfterReturning and
|
||||
// @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
|
||||
// invokes proceed() in a `try` block and only invokes the @After advice method
|
||||
// in a corresponding `finally` block.
|
||||
Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
|
||||
new InstanceComparator<>(
|
||||
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
|
||||
|
|
@ -122,7 +128,15 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
|||
|
||||
List<Advisor> advisors = new ArrayList<>();
|
||||
for (Method method : getAdvisorMethods(aspectClass)) {
|
||||
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
|
||||
// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
|
||||
// to getAdvisor(...) to represent the "current position" in the declared methods list.
|
||||
// However, since Java 7 the "current position" is not valid since the JDK no longer
|
||||
// returns declared methods in the order in which they are declared in the source code.
|
||||
// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
|
||||
// discovered via reflection in order to support reliable advice ordering across JVM launches.
|
||||
// Specifically, a value of 0 aligns with the default value used in
|
||||
// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
|
||||
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
|
||||
if (advisor != null) {
|
||||
advisors.add(advisor);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 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,27 +50,27 @@ public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProx
|
|||
|
||||
|
||||
/**
|
||||
* Sort the rest by AspectJ precedence. If two pieces of advice have
|
||||
* come from the same aspect they will have the same order.
|
||||
* Advice from the same aspect is then further ordered according to the
|
||||
* Sort the supplied {@link Advisor} instances according to AspectJ precedence.
|
||||
* <p>If two pieces of advice come from the same aspect, they will have the same
|
||||
* order. Advice from the same aspect is then further ordered according to the
|
||||
* following rules:
|
||||
* <ul>
|
||||
* <li>if either of the pair is after advice, then the advice declared
|
||||
* last gets highest precedence (runs last)</li>
|
||||
* <li>otherwise the advice declared first gets highest precedence (runs first)</li>
|
||||
* <li>If either of the pair is <em>after</em> advice, then the advice declared
|
||||
* last gets highest precedence (i.e., runs last).</li>
|
||||
* <li>Otherwise the advice declared first gets highest precedence (i.e., runs
|
||||
* first).</li>
|
||||
* </ul>
|
||||
* <p><b>Important:</b> Advisors are sorted in precedence order, from highest
|
||||
* precedence to lowest. "On the way in" to a join point, the highest precedence
|
||||
* advisor should run first. "On the way out" of a join point, the highest precedence
|
||||
* advisor should run last.
|
||||
* advisor should run first. "On the way out" of a join point, the highest
|
||||
* precedence advisor should run last.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
|
||||
List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
|
||||
for (Advisor element : advisors) {
|
||||
for (Advisor advisor : advisors) {
|
||||
partiallyComparableAdvisors.add(
|
||||
new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));
|
||||
new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR));
|
||||
}
|
||||
List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
|
||||
if (sorted != null) {
|
||||
|
|
@ -86,8 +86,8 @@ public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProx
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds an {@link ExposeInvocationInterceptor} to the beginning of the advice chain.
|
||||
* These additional advices are needed when using AspectJ expression pointcuts
|
||||
* Add an {@link ExposeInvocationInterceptor} to the beginning of the advice chain.
|
||||
* <p>This additional advice is needed when using AspectJ pointcut expressions
|
||||
* and when using AspectJ-style advice.
|
||||
*/
|
||||
@Override
|
||||
|
|
@ -110,7 +110,7 @@ public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProx
|
|||
|
||||
|
||||
/**
|
||||
* Implements AspectJ PartialComparable interface for defining partial orderings.
|
||||
* Implements AspectJ's {@link PartialComparable} interface for defining partial orderings.
|
||||
*/
|
||||
private static class PartiallyComparableAdvisorHolder implements PartialComparable {
|
||||
|
||||
|
|
@ -140,17 +140,19 @@ public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProx
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Advice advice = this.advisor.getAdvice();
|
||||
sb.append(ClassUtils.getShortName(advice.getClass()));
|
||||
sb.append(": ");
|
||||
StringBuilder sb = new StringBuilder(ClassUtils.getShortName(advice.getClass()));
|
||||
boolean appended = false;
|
||||
if (this.advisor instanceof Ordered) {
|
||||
sb.append("order ").append(((Ordered) this.advisor).getOrder()).append(", ");
|
||||
sb.append(": order = ").append(((Ordered) this.advisor).getOrder());
|
||||
appended = true;
|
||||
}
|
||||
if (advice instanceof AbstractAspectJAdvice) {
|
||||
sb.append(!appended ? ": " : ", ");
|
||||
AbstractAspectJAdvice ajAdvice = (AbstractAspectJAdvice) advice;
|
||||
sb.append("aspect name = ");
|
||||
sb.append(ajAdvice.getAspectName());
|
||||
sb.append(", declaration order ");
|
||||
sb.append(", declaration order = ");
|
||||
sb.append(ajAdvice.getDeclarationOrder());
|
||||
}
|
||||
return sb.toString();
|
||||
|
|
|
|||
|
|
@ -27,20 +27,22 @@ import org.springframework.util.Assert;
|
|||
/**
|
||||
* Orders AspectJ advice/advisors by precedence (<i>not</i> invocation order).
|
||||
*
|
||||
* <p>Given two pieces of advice, {@code a} and {@code b}:
|
||||
* <p>Given two pieces of advice, {@code A} and {@code B}:
|
||||
* <ul>
|
||||
* <li>if {@code a} and {@code b} are defined in different aspects, then the advice
|
||||
* in the aspect with the lowest order value has the highest precedence</li>
|
||||
* <li>if {@code a} and {@code b} are defined in the same aspect, then if one of
|
||||
* {@code a} or {@code b} is a form of after advice, then the advice declared last
|
||||
* in the aspect has the highest precedence. If neither {@code a} nor {@code b} is
|
||||
* a form of after advice, then the advice declared first in the aspect has the
|
||||
* highest precedence.</li>
|
||||
* <li>If {@code A} and {@code B} are defined in different aspects, then the advice
|
||||
* in the aspect with the lowest order value has the highest precedence.</li>
|
||||
* <li>If {@code A} and {@code B} are defined in the same aspect, if one of
|
||||
* {@code A} or {@code B} is a form of <em>after</em> advice, then the advice declared
|
||||
* last in the aspect has the highest precedence. If neither {@code A} nor {@code B}
|
||||
* is a form of <em>after</em> advice, then the advice declared first in the aspect
|
||||
* has the highest precedence.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Important: Note that unlike a normal comparator a return of 0 means
|
||||
* we don't care about the ordering, not that the two elements must be sorted
|
||||
* identically. Used with AspectJ PartialOrder class.
|
||||
* <p>Important: This comparator is used with AspectJ's
|
||||
* {@link org.aspectj.util.PartialOrder PartialOrder} sorting utility. Thus, unlike
|
||||
* a normal {@link Comparator}, a return value of {@code 0} from this comparator
|
||||
* means we don't care about the ordering, not that the two elements must be sorted
|
||||
* identically.
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @author Juergen Hoeller
|
||||
|
|
@ -59,16 +61,16 @@ class AspectJPrecedenceComparator implements Comparator<Advisor> {
|
|||
|
||||
|
||||
/**
|
||||
* Create a default AspectJPrecedenceComparator.
|
||||
* Create a default {@code AspectJPrecedenceComparator}.
|
||||
*/
|
||||
public AspectJPrecedenceComparator() {
|
||||
this.advisorComparator = AnnotationAwareOrderComparator.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a AspectJPrecedenceComparator, using the given Comparator
|
||||
* Create an {@code AspectJPrecedenceComparator}, using the given {@link Comparator}
|
||||
* for comparing {@link org.springframework.aop.Advisor} instances.
|
||||
* @param advisorComparator the Comparator to use for Advisors
|
||||
* @param advisorComparator the {@code Comparator} to use for advisors
|
||||
*/
|
||||
public AspectJPrecedenceComparator(Comparator<? super Advisor> advisorComparator) {
|
||||
Assert.notNull(advisorComparator, "Advisor comparator must not be null");
|
||||
|
|
@ -125,20 +127,20 @@ class AspectJPrecedenceComparator implements Comparator<Advisor> {
|
|||
getAspectName(advisor1).equals(getAspectName(advisor2)));
|
||||
}
|
||||
|
||||
private boolean hasAspectName(Advisor anAdvisor) {
|
||||
return (anAdvisor instanceof AspectJPrecedenceInformation ||
|
||||
anAdvisor.getAdvice() instanceof AspectJPrecedenceInformation);
|
||||
private boolean hasAspectName(Advisor advisor) {
|
||||
return (advisor instanceof AspectJPrecedenceInformation ||
|
||||
advisor.getAdvice() instanceof AspectJPrecedenceInformation);
|
||||
}
|
||||
|
||||
// pre-condition is that hasAspectName returned true
|
||||
private String getAspectName(Advisor anAdvisor) {
|
||||
AspectJPrecedenceInformation pi = AspectJAopUtils.getAspectJPrecedenceInformationFor(anAdvisor);
|
||||
Assert.state(pi != null, "Unresolvable precedence information");
|
||||
return pi.getAspectName();
|
||||
private String getAspectName(Advisor advisor) {
|
||||
AspectJPrecedenceInformation precedenceInfo = AspectJAopUtils.getAspectJPrecedenceInformationFor(advisor);
|
||||
Assert.state(precedenceInfo != null, () -> "Unresolvable AspectJPrecedenceInformation for " + advisor);
|
||||
return precedenceInfo.getAspectName();
|
||||
}
|
||||
|
||||
private int getAspectDeclarationOrder(Advisor anAdvisor) {
|
||||
AspectJPrecedenceInformation precedenceInfo = AspectJAopUtils.getAspectJPrecedenceInformationFor(anAdvisor);
|
||||
private int getAspectDeclarationOrder(Advisor advisor) {
|
||||
AspectJPrecedenceInformation precedenceInfo = AspectJAopUtils.getAspectJPrecedenceInformationFor(advisor);
|
||||
return (precedenceInfo != null ? precedenceInfo.getDeclarationOrder() : 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 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.
|
||||
|
|
@ -36,11 +36,13 @@ import org.springframework.util.Assert;
|
|||
* also override the inherited {@link #shouldSkip} method to exclude certain
|
||||
* objects from auto-proxying.
|
||||
*
|
||||
* <p>Advisors or advices requiring ordering should implement the
|
||||
* <p>Advisors or advices requiring ordering should be annotated with
|
||||
* {@link org.springframework.core.annotation.Order @Order} or implement the
|
||||
* {@link org.springframework.core.Ordered} interface. This class sorts
|
||||
* Advisors by Ordered order value. Advisors that don't implement the
|
||||
* Ordered interface will be considered as unordered; they will appear
|
||||
* at the end of the advisor chain in undefined order.
|
||||
* advisors using the {@link AnnotationAwareOrderComparator}. Advisors that are
|
||||
* not annotated with {@code @Order} or don't implement the {@code Ordered}
|
||||
* interface will be considered as unordered; they will appear at the end of the
|
||||
* advisor chain in an undefined order.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
|
|
|
|||
Loading…
Reference in New Issue