001/* 002 * Copyright 2002-2012 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 org.aopalliance.intercept.MethodInterceptor; 020import org.aopalliance.intercept.MethodInvocation; 021 022import org.springframework.aop.Advisor; 023import org.springframework.aop.ProxyMethodInvocation; 024import org.springframework.aop.support.DefaultIntroductionAdvisor; 025import org.springframework.aop.support.DefaultPointcutAdvisor; 026import org.springframework.aop.support.DelegatingIntroductionInterceptor; 027import org.springframework.beans.factory.NamedBean; 028 029/** 030 * Convenient methods for creating advisors that may be used when autoproxying beans 031 * created with the Spring IoC container, binding the bean name to the current 032 * invocation. May support a {@code bean()} pointcut designator with AspectJ. 033 * 034 * <p>Typically used in Spring auto-proxying, where the bean name is known 035 * at proxy creation time. 036 * 037 * @author Rod Johnson 038 * @author Juergen Hoeller 039 * @since 2.0 040 * @see org.springframework.beans.factory.NamedBean 041 */ 042public abstract class ExposeBeanNameAdvisors { 043 044 /** 045 * Binding for the bean name of the bean which is currently being invoked 046 * in the ReflectiveMethodInvocation userAttributes Map. 047 */ 048 private static final String BEAN_NAME_ATTRIBUTE = ExposeBeanNameAdvisors.class.getName() + ".BEAN_NAME"; 049 050 051 /** 052 * Find the bean name for the current invocation. Assumes that an ExposeBeanNameAdvisor 053 * has been included in the interceptor chain, and that the invocation is exposed 054 * with ExposeInvocationInterceptor. 055 * @return the bean name (never {@code null}) 056 * @throws IllegalStateException if the bean name has not been exposed 057 */ 058 public static String getBeanName() throws IllegalStateException { 059 return getBeanName(ExposeInvocationInterceptor.currentInvocation()); 060 } 061 062 /** 063 * Find the bean name for the given invocation. Assumes that an ExposeBeanNameAdvisor 064 * has been included in the interceptor chain. 065 * @param mi MethodInvocation that should contain the bean name as an attribute 066 * @return the bean name (never {@code null}) 067 * @throws IllegalStateException if the bean name has not been exposed 068 */ 069 public static String getBeanName(MethodInvocation mi) throws IllegalStateException { 070 if (!(mi instanceof ProxyMethodInvocation)) { 071 throw new IllegalArgumentException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); 072 } 073 ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; 074 String beanName = (String) pmi.getUserAttribute(BEAN_NAME_ATTRIBUTE); 075 if (beanName == null) { 076 throw new IllegalStateException("Cannot get bean name; not set on MethodInvocation: " + mi); 077 } 078 return beanName; 079 } 080 081 /** 082 * Create a new advisor that will expose the given bean name, 083 * with no introduction 084 * @param beanName bean name to expose 085 */ 086 public static Advisor createAdvisorWithoutIntroduction(String beanName) { 087 return new DefaultPointcutAdvisor(new ExposeBeanNameInterceptor(beanName)); 088 } 089 090 /** 091 * Create a new advisor that will expose the given bean name, introducing 092 * the NamedBean interface to make the bean name accessible without forcing 093 * the target object to be aware of this Spring IoC concept. 094 * @param beanName the bean name to expose 095 */ 096 public static Advisor createAdvisorIntroducingNamedBean(String beanName) { 097 return new DefaultIntroductionAdvisor(new ExposeBeanNameIntroduction(beanName)); 098 } 099 100 101 /** 102 * Interceptor that exposes the specified bean name as invocation attribute. 103 */ 104 private static class ExposeBeanNameInterceptor implements MethodInterceptor { 105 106 private final String beanName; 107 108 public ExposeBeanNameInterceptor(String beanName) { 109 this.beanName = beanName; 110 } 111 112 @Override 113 public Object invoke(MethodInvocation mi) throws Throwable { 114 if (!(mi instanceof ProxyMethodInvocation)) { 115 throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); 116 } 117 ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; 118 pmi.setUserAttribute(BEAN_NAME_ATTRIBUTE, this.beanName); 119 return mi.proceed(); 120 } 121 } 122 123 124 /** 125 * Introduction that exposes the specified bean name as invocation attribute. 126 */ 127 @SuppressWarnings("serial") 128 private static class ExposeBeanNameIntroduction extends DelegatingIntroductionInterceptor implements NamedBean { 129 130 private final String beanName; 131 132 public ExposeBeanNameIntroduction(String beanName) { 133 this.beanName = beanName; 134 } 135 136 @Override 137 public Object invoke(MethodInvocation mi) throws Throwable { 138 if (!(mi instanceof ProxyMethodInvocation)) { 139 throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); 140 } 141 ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; 142 pmi.setUserAttribute(BEAN_NAME_ATTRIBUTE, this.beanName); 143 return super.invoke(mi); 144 } 145 146 @Override 147 public String getBeanName() { 148 return this.beanName; 149 } 150 } 151 152}