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