001/* 002 * Copyright 2002-2018 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.framework; 018 019import java.io.Serializable; 020import java.lang.reflect.Method; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.List; 024 025import org.aopalliance.intercept.Interceptor; 026import org.aopalliance.intercept.MethodInterceptor; 027 028import org.springframework.aop.Advisor; 029import org.springframework.aop.IntroductionAdvisor; 030import org.springframework.aop.IntroductionAwareMethodMatcher; 031import org.springframework.aop.MethodMatcher; 032import org.springframework.aop.PointcutAdvisor; 033import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry; 034import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry; 035import org.springframework.lang.Nullable; 036 037/** 038 * A simple but definitive way of working out an advice chain for a Method, 039 * given an {@link Advised} object. Always rebuilds each advice chain; 040 * caching can be provided by subclasses. 041 * 042 * @author Juergen Hoeller 043 * @author Rod Johnson 044 * @author Adrian Colyer 045 * @since 2.0.3 046 */ 047@SuppressWarnings("serial") 048public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable { 049 050 @Override 051 public List<Object> getInterceptorsAndDynamicInterceptionAdvice( 052 Advised config, Method method, @Nullable Class<?> targetClass) { 053 054 // This is somewhat tricky... We have to process introductions first, 055 // but we need to preserve order in the ultimate list. 056 AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); 057 Advisor[] advisors = config.getAdvisors(); 058 List<Object> interceptorList = new ArrayList<>(advisors.length); 059 Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); 060 Boolean hasIntroductions = null; 061 062 for (Advisor advisor : advisors) { 063 if (advisor instanceof PointcutAdvisor) { 064 // Add it conditionally. 065 PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; 066 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { 067 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); 068 boolean match; 069 if (mm instanceof IntroductionAwareMethodMatcher) { 070 if (hasIntroductions == null) { 071 hasIntroductions = hasMatchingIntroductions(advisors, actualClass); 072 } 073 match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions); 074 } 075 else { 076 match = mm.matches(method, actualClass); 077 } 078 if (match) { 079 MethodInterceptor[] interceptors = registry.getInterceptors(advisor); 080 if (mm.isRuntime()) { 081 // Creating a new object instance in the getInterceptors() method 082 // isn't a problem as we normally cache created chains. 083 for (MethodInterceptor interceptor : interceptors) { 084 interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); 085 } 086 } 087 else { 088 interceptorList.addAll(Arrays.asList(interceptors)); 089 } 090 } 091 } 092 } 093 else if (advisor instanceof IntroductionAdvisor) { 094 IntroductionAdvisor ia = (IntroductionAdvisor) advisor; 095 if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { 096 Interceptor[] interceptors = registry.getInterceptors(advisor); 097 interceptorList.addAll(Arrays.asList(interceptors)); 098 } 099 } 100 else { 101 Interceptor[] interceptors = registry.getInterceptors(advisor); 102 interceptorList.addAll(Arrays.asList(interceptors)); 103 } 104 } 105 106 return interceptorList; 107 } 108 109 /** 110 * Determine whether the Advisors contain matching introductions. 111 */ 112 private static boolean hasMatchingIntroductions(Advisor[] advisors, Class<?> actualClass) { 113 for (Advisor advisor : advisors) { 114 if (advisor instanceof IntroductionAdvisor) { 115 IntroductionAdvisor ia = (IntroductionAdvisor) advisor; 116 if (ia.getClassFilter().matches(actualClass)) { 117 return true; 118 } 119 } 120 } 121 return false; 122 } 123 124}