001/* 002 * Copyright 2002-2013 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.aop.aspectj.autoproxy; 018 019import java.util.ArrayList; 020import java.util.Comparator; 021import java.util.List; 022 023import org.aopalliance.aop.Advice; 024import org.aspectj.util.PartialOrder; 025import org.aspectj.util.PartialOrder.PartialComparable; 026 027import org.springframework.aop.Advisor; 028import org.springframework.aop.aspectj.AbstractAspectJAdvice; 029import org.springframework.aop.aspectj.AspectJPointcutAdvisor; 030import org.springframework.aop.aspectj.AspectJProxyUtils; 031import org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator; 032import org.springframework.aop.interceptor.ExposeInvocationInterceptor; 033import org.springframework.core.Ordered; 034import org.springframework.util.ClassUtils; 035 036/** 037 * {@link org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator} 038 * subclass that exposes AspectJ's invocation context and understands AspectJ's rules 039 * for advice precedence when multiple pieces of advice come from the same aspect. 040 * 041 * @author Adrian Colyer 042 * @author Juergen Hoeller 043 * @author Ramnivas Laddad 044 * @since 2.0 045 */ 046@SuppressWarnings("serial") 047public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator { 048 049 private static final Comparator<Advisor> DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator(); 050 051 052 /** 053 * Sort the rest by AspectJ precedence. If two pieces of advice have 054 * come from the same aspect they will have the same order. 055 * Advice from the same aspect is then further ordered according to the 056 * following rules: 057 * <ul> 058 * <li>if either of the pair is after advice, then the advice declared 059 * last gets highest precedence (runs last)</li> 060 * <li>otherwise the advice declared first gets highest precedence (runs first)</li> 061 * </ul> 062 * <p><b>Important:</b> Advisors are sorted in precedence order, from highest 063 * precedence to lowest. "On the way in" to a join point, the highest precedence 064 * advisor should run first. "On the way out" of a join point, the highest precedence 065 * advisor should run last. 066 */ 067 @Override 068 @SuppressWarnings("unchecked") 069 protected List<Advisor> sortAdvisors(List<Advisor> advisors) { 070 List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = 071 new ArrayList<PartiallyComparableAdvisorHolder>(advisors.size()); 072 for (Advisor element : advisors) { 073 partiallyComparableAdvisors.add( 074 new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR)); 075 } 076 List<PartiallyComparableAdvisorHolder> sorted = 077 PartialOrder.sort(partiallyComparableAdvisors); 078 if (sorted != null) { 079 List<Advisor> result = new ArrayList<Advisor>(advisors.size()); 080 for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) { 081 result.add(pcAdvisor.getAdvisor()); 082 } 083 return result; 084 } 085 else { 086 return super.sortAdvisors(advisors); 087 } 088 } 089 090 /** 091 * Adds an {@link ExposeInvocationInterceptor} to the beginning of the advice chain. 092 * These additional advices are needed when using AspectJ expression pointcuts 093 * and when using AspectJ-style advice. 094 */ 095 @Override 096 protected void extendAdvisors(List<Advisor> candidateAdvisors) { 097 AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors); 098 } 099 100 @Override 101 protected boolean shouldSkip(Class<?> beanClass, String beanName) { 102 // TODO: Consider optimization by caching the list of the aspect names 103 List<Advisor> candidateAdvisors = findCandidateAdvisors(); 104 for (Advisor advisor : candidateAdvisors) { 105 if (advisor instanceof AspectJPointcutAdvisor) { 106 if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) { 107 return true; 108 } 109 } 110 } 111 return super.shouldSkip(beanClass, beanName); 112 } 113 114 115 /** 116 * Implements AspectJ PartialComparable interface for defining partial orderings. 117 */ 118 private static class PartiallyComparableAdvisorHolder implements PartialComparable { 119 120 private final Advisor advisor; 121 122 private final Comparator<Advisor> comparator; 123 124 public PartiallyComparableAdvisorHolder(Advisor advisor, Comparator<Advisor> comparator) { 125 this.advisor = advisor; 126 this.comparator = comparator; 127 } 128 129 @Override 130 public int compareTo(Object obj) { 131 Advisor otherAdvisor = ((PartiallyComparableAdvisorHolder) obj).advisor; 132 return this.comparator.compare(this.advisor, otherAdvisor); 133 } 134 135 @Override 136 public int fallbackCompareTo(Object obj) { 137 return 0; 138 } 139 140 public Advisor getAdvisor() { 141 return this.advisor; 142 } 143 144 @Override 145 public String toString() { 146 StringBuilder sb = new StringBuilder(); 147 Advice advice = this.advisor.getAdvice(); 148 sb.append(ClassUtils.getShortName(advice.getClass())); 149 sb.append(": "); 150 if (this.advisor instanceof Ordered) { 151 sb.append("order ").append(((Ordered) this.advisor).getOrder()).append(", "); 152 } 153 if (advice instanceof AbstractAspectJAdvice) { 154 AbstractAspectJAdvice ajAdvice = (AbstractAspectJAdvice) advice; 155 sb.append(ajAdvice.getAspectName()); 156 sb.append(", declaration order "); 157 sb.append(ajAdvice.getDeclarationOrder()); 158 } 159 return sb.toString(); 160 } 161 } 162 163}