AspectJAwareAdvisorAutoProxyCreator.java 5.7 KB
Newer Older
1
/*
J
Juergen Hoeller 已提交
2
 * Copyright 2002-2008 the original author or authors.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.aspectj.autoproxy;

import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;

import org.aopalliance.aop.Advice;
import org.aspectj.util.PartialOrder;
import org.aspectj.util.PartialOrder.PartialComparable;

import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AbstractAspectJAdvice;
import org.springframework.aop.aspectj.AspectJPointcutAdvisor;
import org.springframework.aop.aspectj.AspectJProxyUtils;
import org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.core.Ordered;
import org.springframework.util.ClassUtils;

/**
 * {@link org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator}
 * subclass that exposes AspectJ's invocation context and understands AspectJ's rules
 * for advice precedence when multiple pieces of advice come from the same aspect.
 *
 * @author Adrian Colyer
 * @author Juergen Hoeller
 * @author Ramnivas Laddad
 * @since 2.0
 */
public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {

	private static final Comparator DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator();


	/**
	 * 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
	 * 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>
	 * </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.
	 */
66
	@Override
J
Juergen Hoeller 已提交
67 68
	@SuppressWarnings("unchecked")
	protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
69
		// build list for sorting
J
Juergen Hoeller 已提交
70 71 72 73 74
		List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors =
				new LinkedList<PartiallyComparableAdvisorHolder>();
		for (Advisor element : advisors) {
			partiallyComparableAdvisors.add(
					new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));
75 76 77
		}		
		
		// sort it
J
Juergen Hoeller 已提交
78 79
		List<PartiallyComparableAdvisorHolder> sorted =
				(List<PartiallyComparableAdvisorHolder>) PartialOrder.sort(partiallyComparableAdvisors);
80
		if (sorted == null) {
J
Juergen Hoeller 已提交
81
			// TODO: work harder to give a better error message here.
82 83 84 85
			throw new IllegalArgumentException("Advice precedence circularity error");
		}
		
		// extract results again
J
Juergen Hoeller 已提交
86 87
		List<Advisor> result = new LinkedList<Advisor>();
		for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
88 89 90 91 92 93 94 95 96 97 98
			result.add(pcAdvisor.getAdvisor());
		}
		
		return result;
	}

	/**
	 * Adds an {@link ExposeInvocationInterceptor} to the beginning of the advice chain.
	 * These additional advices are needed when using AspectJ expression pointcuts
	 * and when using AspectJ-style advice.
	 */
99
	@Override
J
Juergen Hoeller 已提交
100
	protected void extendAdvisors(List<Advisor> candidateAdvisors) {
101 102 103
		AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
	}

104
	@Override
105 106
	protected boolean shouldSkip(Class beanClass, String beanName) {
		// TODO: Consider optimization by caching the list of the aspect names
J
Juergen Hoeller 已提交
107 108
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		for (Advisor advisor : candidateAdvisors) {
109
			if (advisor instanceof AspectJPointcutAdvisor) {
J
Juergen Hoeller 已提交
110
				if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
111 112 113 114 115 116 117
					return true;
				}
			}
		}
		return super.shouldSkip(beanClass, beanName);
	}

J
Juergen Hoeller 已提交
118

119 120 121 122 123 124 125
	/**
	 * Implements AspectJ PartialComparable interface for defining partial orderings.
	 */
	private static class PartiallyComparableAdvisorHolder implements PartialComparable {

		private final Advisor advisor;

J
Juergen Hoeller 已提交
126
		private final Comparator<Advisor> comparator;
127

J
Juergen Hoeller 已提交
128
		public PartiallyComparableAdvisorHolder(Advisor advisor, Comparator<Advisor> comparator) {
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
			this.advisor = advisor;
			this.comparator = comparator;
		}

		public int compareTo(Object obj) {
			Advisor otherAdvisor = ((PartiallyComparableAdvisorHolder) obj).advisor;
			return this.comparator.compare(this.advisor, otherAdvisor);
		}

		public int fallbackCompareTo(Object obj) {
			return 0;
		}

		public Advisor getAdvisor() {
			return this.advisor;
		}

146
		@Override
147
		public String toString() {
148
			StringBuilder sb = new StringBuilder();
149 150 151 152
			Advice advice = this.advisor.getAdvice();
			sb.append(ClassUtils.getShortName(advice.getClass()));
			sb.append(": ");
			if (this.advisor instanceof Ordered) {
J
Juergen Hoeller 已提交
153
				sb.append("order ").append(((Ordered) this.advisor).getOrder()).append(", ");
154 155 156 157 158 159 160 161 162 163 164 165
			}
			if (advice instanceof AbstractAspectJAdvice) {
				AbstractAspectJAdvice ajAdvice = (AbstractAspectJAdvice) advice;
				sb.append(ajAdvice.getAspectName());
				sb.append(", declaration order ");
				sb.append(ajAdvice.getDeclarationOrder());
			}
			return sb.toString();
		}
	}

}