001/* 002 * Copyright 2002-2014 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.interceptor; 018 019import java.io.Serializable; 020 021import org.aopalliance.intercept.MethodInterceptor; 022import org.aopalliance.intercept.MethodInvocation; 023 024import org.springframework.aop.Advisor; 025import org.springframework.aop.support.DefaultPointcutAdvisor; 026import org.springframework.core.NamedThreadLocal; 027import org.springframework.core.PriorityOrdered; 028 029/** 030 * Interceptor that exposes the current {@link org.aopalliance.intercept.MethodInvocation} 031 * as a thread-local object. We occasionally need to do this; for example, when a pointcut 032 * (e.g. an AspectJ expression pointcut) needs to know the full invocation context. 033 * 034 * <p>Don't use this interceptor unless this is really necessary. Target objects should 035 * not normally know about Spring AOP, as this creates a dependency on Spring API. 036 * Target objects should be plain POJOs as far as possible. 037 * 038 * <p>If used, this interceptor will normally be the first in the interceptor chain. 039 * 040 * @author Rod Johnson 041 * @author Juergen Hoeller 042 */ 043@SuppressWarnings("serial") 044public class ExposeInvocationInterceptor implements MethodInterceptor, PriorityOrdered, Serializable { 045 046 /** Singleton instance of this class */ 047 public static final ExposeInvocationInterceptor INSTANCE = new ExposeInvocationInterceptor(); 048 049 /** 050 * Singleton advisor for this class. Use in preference to INSTANCE when using 051 * Spring AOP, as it prevents the need to create a new Advisor to wrap the instance. 052 */ 053 public static final Advisor ADVISOR = new DefaultPointcutAdvisor(INSTANCE) { 054 @Override 055 public String toString() { 056 return ExposeInvocationInterceptor.class.getName() +".ADVISOR"; 057 } 058 }; 059 060 private static final ThreadLocal<MethodInvocation> invocation = 061 new NamedThreadLocal<MethodInvocation>("Current AOP method invocation"); 062 063 064 /** 065 * Return the AOP Alliance MethodInvocation object associated with the current invocation. 066 * @return the invocation object associated with the current invocation 067 * @throws IllegalStateException if there is no AOP invocation in progress, 068 * or if the ExposeInvocationInterceptor was not added to this interceptor chain 069 */ 070 public static MethodInvocation currentInvocation() throws IllegalStateException { 071 MethodInvocation mi = invocation.get(); 072 if (mi == null) 073 throw new IllegalStateException( 074 "No MethodInvocation found: Check that an AOP invocation is in progress, and that the " + 075 "ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that " + 076 "advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!"); 077 return mi; 078 } 079 080 081 /** 082 * Ensures that only the canonical instance can be created. 083 */ 084 private ExposeInvocationInterceptor() { 085 } 086 087 @Override 088 public Object invoke(MethodInvocation mi) throws Throwable { 089 MethodInvocation oldInvocation = invocation.get(); 090 invocation.set(mi); 091 try { 092 return mi.proceed(); 093 } 094 finally { 095 invocation.set(oldInvocation); 096 } 097 } 098 099 @Override 100 public int getOrder() { 101 return PriorityOrdered.HIGHEST_PRECEDENCE + 1; 102 } 103 104 /** 105 * Required to support serialization. Replaces with canonical instance 106 * on deserialization, protecting Singleton pattern. 107 * <p>Alternative to overriding the {@code equals} method. 108 */ 109 private Object readResolve() { 110 return INSTANCE; 111 } 112 113}