001/* 002 * Copyright 2002-2020 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 org.springframework.core.NamedThreadLocal; 020import org.springframework.lang.Nullable; 021 022/** 023 * Class containing static methods used to obtain information about the current AOP invocation. 024 * 025 * <p>The {@code currentProxy()} method is usable if the AOP framework is configured to 026 * expose the current proxy (not the default). It returns the AOP proxy in use. Target objects 027 * or advice can use this to make advised calls, in the same way as {@code getEJBObject()} 028 * can be used in EJBs. They can also use it to find advice configuration. 029 * 030 * <p>Spring's AOP framework does not expose proxies by default, as there is a performance cost 031 * in doing so. 032 * 033 * <p>The functionality in this class might be used by a target object that needed access 034 * to resources on the invocation. However, this approach should not be used when there is 035 * a reasonable alternative, as it makes application code dependent on usage under AOP and 036 * the Spring AOP framework in particular. 037 * 038 * @author Rod Johnson 039 * @author Juergen Hoeller 040 * @since 13.03.2003 041 */ 042public final class AopContext { 043 044 /** 045 * ThreadLocal holder for AOP proxy associated with this thread. 046 * Will contain {@code null} unless the "exposeProxy" property on 047 * the controlling proxy configuration has been set to "true". 048 * @see ProxyConfig#setExposeProxy 049 */ 050 private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal<>("Current AOP proxy"); 051 052 053 private AopContext() { 054 } 055 056 057 /** 058 * Try to return the current AOP proxy. This method is usable only if the 059 * calling method has been invoked via AOP, and the AOP framework has been set 060 * to expose proxies. Otherwise, this method will throw an IllegalStateException. 061 * @return the current AOP proxy (never returns {@code null}) 062 * @throws IllegalStateException if the proxy cannot be found, because the 063 * method was invoked outside an AOP invocation context, or because the 064 * AOP framework has not been configured to expose the proxy 065 */ 066 public static Object currentProxy() throws IllegalStateException { 067 Object proxy = currentProxy.get(); 068 if (proxy == null) { 069 throw new IllegalStateException( 070 "Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and " + 071 "ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context."); 072 } 073 return proxy; 074 } 075 076 /** 077 * Make the given proxy available via the {@code currentProxy()} method. 078 * <p>Note that the caller should be careful to keep the old value as appropriate. 079 * @param proxy the proxy to expose (or {@code null} to reset it) 080 * @return the old proxy, which may be {@code null} if none was bound 081 * @see #currentProxy() 082 */ 083 @Nullable 084 static Object setCurrentProxy(@Nullable Object proxy) { 085 Object old = currentProxy.get(); 086 if (proxy != null) { 087 currentProxy.set(proxy); 088 } 089 else { 090 currentProxy.remove(); 091 } 092 return old; 093 } 094 095}