All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.aop.framework.ReflectiveMethodInvocation Maven / Gradle / Ivy

There is a newer version: 5.3.34
Show newest version
/*
 * Copyright 2002-2007 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.
 * 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.framework;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import org.springframework.aop.ProxyMethodInvocation;
import org.springframework.aop.support.AopUtils;

/**
 * Spring's implementation of the AOP Alliance
 * {@link org.aopalliance.intercept.MethodInvocation} interface,
 * implementing the extended
 * {@link org.springframework.aop.ProxyMethodInvocation} interface.
 *
 * 

Invokes the target object using reflection. Subclasses can override the * {@link #invokeJoinpoint()} method to change this behavior, so this is also * a useful base class for more specialized MethodInvocation implementations. * *

It is possible to clone an invocation, to invoke {@link #proceed()} * repeatedly (once per clone), using the {@link #invocableClone()} method. * It is also possible to attach custom attributes to the invocation, * using the {@link #setUserAttribute} / {@link #getUserAttribute} methods. * * @author Rod Johnson * @author Juergen Hoeller * @see #invokeJoinpoint * @see #proceed * @see #invocableClone * @see #setUserAttribute * @see #getUserAttribute */ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable { protected final Object proxy; protected final Object target; protected final Method method; protected Object[] arguments; private final Class targetClass; /** * Lazily initialized map of user-specific attributes for this invocation. */ private Map userAttributes; /** * List of MethodInterceptor and InterceptorAndDynamicMethodMatcher * that need dynamic checks. */ protected final List interceptorsAndDynamicMethodMatchers; /** * Index from 0 of the current interceptor we're invoking. * -1 until we invoke: then the current interceptor. */ private int currentInterceptorIndex = -1; /** * Construct a new ReflectiveMethodInvocation with the given arguments. * @param proxy the proxy object that the invocation was made on * @param target the target object to invoke * @param method the method to invoke * @param arguments the arguments to invoke the method with * @param targetClass the target class, for MethodMatcher invocations * @param interceptorsAndDynamicMethodMatchers interceptors that should be applied, * along with any InterceptorAndDynamicMethodMatchers that need evaluation at runtime. * MethodMatchers included in this struct must already have been found to have matched * as far as was possibly statically. Passing an array might be about 10% faster, * but would complicate the code. And it would work only for static pointcuts. */ public ReflectiveMethodInvocation( Object proxy, Object target, Method method, Object[] arguments, Class targetClass, List interceptorsAndDynamicMethodMatchers) { this.proxy = proxy; this.target = target; this.targetClass = targetClass; this.method = method; this.arguments = arguments; this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers; } public final Object getProxy() { return this.proxy; } public final Object getThis() { return this.target; } public final AccessibleObject getStaticPart() { return this.method; } /** * Return the method invoked on the proxied interface. * May or may not correspond with a method invoked on an underlying * implementation of that interface. */ public final Method getMethod() { return this.method; } public final Object[] getArguments() { return (this.arguments != null ? this.arguments : new Object[0]); } public Object proceed() throws Throwable { // We start with an index of -1 and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // Evaluate dynamic method matcher here: static part will already have // been evaluated and found to match. InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. return proceed(); } } else { // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } } /** * Invoke the joinpoint using reflection. * Subclasses can override this to use custom invocation. * @return the return value of the joinpoint * @throws Throwable if invoking the joinpoint resulted in an exception */ protected Object invokeJoinpoint() throws Throwable { return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments); } /** * This implementation returns a shallow copy of this invocation object, * including an independent copy of the original arguments array. *

We want a shallow copy in this case: We want to use the same interceptor * chain and other object references, but we want an independent value for the * current interceptor index. * @see java.lang.Object#clone() */ public MethodInvocation invocableClone() { Object[] cloneArguments = null; if (this.arguments != null) { // Build an independent copy of the arguments array. cloneArguments = new Object[this.arguments.length]; System.arraycopy(this.arguments, 0, cloneArguments, 0, this.arguments.length); } return invocableClone(cloneArguments); } /** * This implementation returns a shallow copy of this invocation object, * using the given arguments array for the clone. *

We want a shallow copy in this case: We want to use the same interceptor * chain and other object references, but we want an independent value for the * current interceptor index. * @see java.lang.Object#clone() */ public MethodInvocation invocableClone(Object[] arguments) { try { ReflectiveMethodInvocation clone = (ReflectiveMethodInvocation) clone(); clone.arguments = arguments; return clone; } catch (CloneNotSupportedException ex) { throw new IllegalStateException( "Should be able to clone object of type [" + getClass() + "]: " + ex); } } public void setUserAttribute(String key, Object value) { if (value != null) { if (this.userAttributes == null) { this.userAttributes = new HashMap(); } this.userAttributes.put(key, value); } else { if (this.userAttributes != null) { this.userAttributes.remove(key); } } } public Object getUserAttribute(String key) { return (this.userAttributes != null ? this.userAttributes.get(key) : null); } /** * Return user attributes associated with this invocation. * This method provides an invocation-bound alternative to a ThreadLocal. *

This map is initialized lazily and is not used in the AOP framework itself. * @return any user attributes associated with this invocation * (never null) */ public Map getUserAttributes() { if (this.userAttributes == null) { this.userAttributes = new HashMap(); } return this.userAttributes; } public String toString() { // Don't do toString on target, it may be proxied. StringBuffer sb = new StringBuffer("ReflectiveMethodInvocation: "); sb.append(this.method).append("; "); if (this.target == null) { sb.append("target is null"); } else { sb.append("target is of class [").append(this.target.getClass().getName()).append(']'); } return sb.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy