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