001/* 002 * Copyright 2002-2016 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.config; 018 019import java.util.List; 020 021import org.w3c.dom.Node; 022 023import org.springframework.aop.framework.ProxyFactoryBean; 024import org.springframework.beans.factory.config.BeanDefinition; 025import org.springframework.beans.factory.config.BeanDefinitionHolder; 026import org.springframework.beans.factory.support.AbstractBeanDefinition; 027import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; 028import org.springframework.beans.factory.support.BeanDefinitionRegistry; 029import org.springframework.beans.factory.support.ManagedList; 030import org.springframework.beans.factory.support.RootBeanDefinition; 031import org.springframework.beans.factory.xml.BeanDefinitionDecorator; 032import org.springframework.beans.factory.xml.ParserContext; 033import org.springframework.util.ClassUtils; 034import org.springframework.util.StringUtils; 035 036/** 037 * Base implementation for 038 * {@link org.springframework.beans.factory.xml.BeanDefinitionDecorator BeanDefinitionDecorators} 039 * wishing to add an {@link org.aopalliance.intercept.MethodInterceptor interceptor} 040 * to the resulting bean. 041 * 042 * <p>This base class controls the creation of the {@link ProxyFactoryBean} bean definition 043 * and wraps the original as an inner-bean definition for the {@code target} property 044 * of {@link ProxyFactoryBean}. 045 * 046 * <p>Chaining is correctly handled, ensuring that only one {@link ProxyFactoryBean} definition 047 * is created. If a previous {@link org.springframework.beans.factory.xml.BeanDefinitionDecorator} 048 * already created the {@link org.springframework.aop.framework.ProxyFactoryBean} then the 049 * interceptor is simply added to the existing definition. 050 * 051 * <p>Subclasses have only to create the {@code BeanDefinition} to the interceptor that 052 * they wish to add. 053 * 054 * @author Rob Harrop 055 * @author Juergen Hoeller 056 * @since 2.0 057 * @see org.aopalliance.intercept.MethodInterceptor 058 */ 059public abstract class AbstractInterceptorDrivenBeanDefinitionDecorator implements BeanDefinitionDecorator { 060 061 @Override 062 public final BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definitionHolder, ParserContext parserContext) { 063 BeanDefinitionRegistry registry = parserContext.getRegistry(); 064 065 // get the root bean name - will be the name of the generated proxy factory bean 066 String existingBeanName = definitionHolder.getBeanName(); 067 BeanDefinition targetDefinition = definitionHolder.getBeanDefinition(); 068 BeanDefinitionHolder targetHolder = new BeanDefinitionHolder(targetDefinition, existingBeanName + ".TARGET"); 069 070 // delegate to subclass for interceptor definition 071 BeanDefinition interceptorDefinition = createInterceptorDefinition(node); 072 073 // generate name and register the interceptor 074 String interceptorName = existingBeanName + '.' + getInterceptorNameSuffix(interceptorDefinition); 075 BeanDefinitionReaderUtils.registerBeanDefinition( 076 new BeanDefinitionHolder(interceptorDefinition, interceptorName), registry); 077 078 BeanDefinitionHolder result = definitionHolder; 079 080 if (!isProxyFactoryBeanDefinition(targetDefinition)) { 081 // create the proxy definition 082 RootBeanDefinition proxyDefinition = new RootBeanDefinition(); 083 // create proxy factory bean definition 084 proxyDefinition.setBeanClass(ProxyFactoryBean.class); 085 proxyDefinition.setScope(targetDefinition.getScope()); 086 proxyDefinition.setLazyInit(targetDefinition.isLazyInit()); 087 // set the target 088 proxyDefinition.setDecoratedDefinition(targetHolder); 089 proxyDefinition.getPropertyValues().add("target", targetHolder); 090 // create the interceptor names list 091 proxyDefinition.getPropertyValues().add("interceptorNames", new ManagedList<String>()); 092 // copy autowire settings from original bean definition. 093 proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate()); 094 proxyDefinition.setPrimary(targetDefinition.isPrimary()); 095 if (targetDefinition instanceof AbstractBeanDefinition) { 096 proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition); 097 } 098 // wrap it in a BeanDefinitionHolder with bean name 099 result = new BeanDefinitionHolder(proxyDefinition, existingBeanName); 100 } 101 102 addInterceptorNameToList(interceptorName, result.getBeanDefinition()); 103 return result; 104 } 105 106 @SuppressWarnings("unchecked") 107 private void addInterceptorNameToList(String interceptorName, BeanDefinition beanDefinition) { 108 List<String> list = (List<String>) 109 beanDefinition.getPropertyValues().getPropertyValue("interceptorNames").getValue(); 110 list.add(interceptorName); 111 } 112 113 private boolean isProxyFactoryBeanDefinition(BeanDefinition existingDefinition) { 114 return ProxyFactoryBean.class.getName().equals(existingDefinition.getBeanClassName()); 115 } 116 117 protected String getInterceptorNameSuffix(BeanDefinition interceptorDefinition) { 118 return StringUtils.uncapitalize(ClassUtils.getShortName(interceptorDefinition.getBeanClassName())); 119 } 120 121 /** 122 * Subclasses should implement this method to return the {@code BeanDefinition} 123 * for the interceptor they wish to apply to the bean being decorated. 124 */ 125 protected abstract BeanDefinition createInterceptorDefinition(Node node); 126 127}