001/* 002 * Copyright 2002-2015 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.transaction.interceptor; 018 019import java.util.Properties; 020 021import org.springframework.aop.Pointcut; 022import org.springframework.aop.framework.AbstractSingletonProxyFactoryBean; 023import org.springframework.aop.framework.ProxyFactory; 024import org.springframework.aop.support.DefaultPointcutAdvisor; 025import org.springframework.beans.factory.BeanFactory; 026import org.springframework.beans.factory.BeanFactoryAware; 027import org.springframework.beans.factory.FactoryBean; 028import org.springframework.beans.factory.ListableBeanFactory; 029import org.springframework.transaction.PlatformTransactionManager; 030 031/** 032 * Proxy factory bean for simplified declarative transaction handling. 033 * This is a convenient alternative to a standard AOP 034 * {@link org.springframework.aop.framework.ProxyFactoryBean} 035 * with a separate {@link TransactionInterceptor} definition. 036 * 037 * <p><strong>HISTORICAL NOTE:</strong> This class was originally designed to cover the 038 * typical case of declarative transaction demarcation: namely, wrapping a singleton 039 * target object with a transactional proxy, proxying all the interfaces that the target 040 * implements. However, in Spring versions 2.0 and beyond, the functionality provided here 041 * is superseded by the more convenient {@code tx:} XML namespace. See the <a 042 * href="https://bit.ly/qUwvwz">declarative transaction management</a> section of the 043 * Spring reference documentation to understand the modern options for managing 044 * transactions in Spring applications. For these reasons, <strong>users should favor of 045 * the {@code tx:} XML namespace as well as 046 * the @{@link org.springframework.transaction.annotation.Transactional Transactional} 047 * and @{@link org.springframework.transaction.annotation.EnableTransactionManagement 048 * EnableTransactionManagement} annotations.</strong> 049 * 050 * <p>There are three main properties that need to be specified: 051 * <ul> 052 * <li>"transactionManager": the {@link PlatformTransactionManager} implementation to use 053 * (for example, a {@link org.springframework.transaction.jta.JtaTransactionManager} instance) 054 * <li>"target": the target object that a transactional proxy should be created for 055 * <li>"transactionAttributes": the transaction attributes (for example, propagation 056 * behavior and "readOnly" flag) per target method name (or method name pattern) 057 * </ul> 058 * 059 * <p>If the "transactionManager" property is not set explicitly and this {@link FactoryBean} 060 * is running in a {@link ListableBeanFactory}, a single matching bean of type 061 * {@link PlatformTransactionManager} will be fetched from the {@link BeanFactory}. 062 * 063 * <p>In contrast to {@link TransactionInterceptor}, the transaction attributes are 064 * specified as properties, with method names as keys and transaction attribute 065 * descriptors as values. Method names are always applied to the target class. 066 * 067 * <p>Internally, a {@link TransactionInterceptor} instance is used, but the user of this 068 * class does not have to care. Optionally, a method pointcut can be specified 069 * to cause conditional invocation of the underlying {@link TransactionInterceptor}. 070 * 071 * <p>The "preInterceptors" and "postInterceptors" properties can be set to add 072 * additional interceptors to the mix, like 073 * {@link org.springframework.aop.interceptor.PerformanceMonitorInterceptor}. 074 * 075 * <p><b>HINT:</b> This class is often used with parent / child bean definitions. 076 * Typically, you will define the transaction manager and default transaction 077 * attributes (for method name patterns) in an abstract parent bean definition, 078 * deriving concrete child bean definitions for specific target objects. 079 * This reduces the per-bean definition effort to a minimum. 080 * 081 * <pre code="class"> 082 * {@code 083 * <bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" 084 * abstract="true"> 085 * <property name="transactionManager" ref="transactionManager"/> 086 * <property name="transactionAttributes"> 087 * <props> 088 * <prop key="insert*">PROPAGATION_REQUIRED</prop> 089 * <prop key="update*">PROPAGATION_REQUIRED</prop> 090 * <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> 091 * </props> 092 * </property> 093 * </bean> 094 * 095 * <bean id="myProxy" parent="baseTransactionProxy"> 096 * <property name="target" ref="myTarget"/> 097 * </bean> 098 * 099 * <bean id="yourProxy" parent="baseTransactionProxy"> 100 * <property name="target" ref="yourTarget"/> 101 * </bean>}</pre> 102 * 103 * @author Juergen Hoeller 104 * @author Dmitriy Kopylenko 105 * @author Rod Johnson 106 * @author Chris Beams 107 * @since 21.08.2003 108 * @see #setTransactionManager 109 * @see #setTarget 110 * @see #setTransactionAttributes 111 * @see TransactionInterceptor 112 * @see org.springframework.aop.framework.ProxyFactoryBean 113 */ 114@SuppressWarnings("serial") 115public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean 116 implements BeanFactoryAware { 117 118 private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor(); 119 120 private Pointcut pointcut; 121 122 123 /** 124 * Set the default transaction manager. This will perform actual 125 * transaction management: This class is just a way of invoking it. 126 * @see TransactionInterceptor#setTransactionManager 127 */ 128 public void setTransactionManager(PlatformTransactionManager transactionManager) { 129 this.transactionInterceptor.setTransactionManager(transactionManager); 130 } 131 132 /** 133 * Set properties with method names as keys and transaction attribute 134 * descriptors (parsed via TransactionAttributeEditor) as values: 135 * e.g. key = "myMethod", value = "PROPAGATION_REQUIRED,readOnly". 136 * <p>Note: Method names are always applied to the target class, 137 * no matter if defined in an interface or the class itself. 138 * <p>Internally, a NameMatchTransactionAttributeSource will be 139 * created from the given properties. 140 * @see #setTransactionAttributeSource 141 * @see TransactionInterceptor#setTransactionAttributes 142 * @see TransactionAttributeEditor 143 * @see NameMatchTransactionAttributeSource 144 */ 145 public void setTransactionAttributes(Properties transactionAttributes) { 146 this.transactionInterceptor.setTransactionAttributes(transactionAttributes); 147 } 148 149 /** 150 * Set the transaction attribute source which is used to find transaction 151 * attributes. If specifying a String property value, a PropertyEditor 152 * will create a MethodMapTransactionAttributeSource from the value. 153 * @see #setTransactionAttributes 154 * @see TransactionInterceptor#setTransactionAttributeSource 155 * @see TransactionAttributeSourceEditor 156 * @see MethodMapTransactionAttributeSource 157 * @see NameMatchTransactionAttributeSource 158 * @see org.springframework.transaction.annotation.AnnotationTransactionAttributeSource 159 */ 160 public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) { 161 this.transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource); 162 } 163 164 /** 165 * Set a pointcut, i.e a bean that can cause conditional invocation 166 * of the TransactionInterceptor depending on method and attributes passed. 167 * Note: Additional interceptors are always invoked. 168 * @see #setPreInterceptors 169 * @see #setPostInterceptors 170 */ 171 public void setPointcut(Pointcut pointcut) { 172 this.pointcut = pointcut; 173 } 174 175 /** 176 * This callback is optional: If running in a BeanFactory and no transaction 177 * manager has been set explicitly, a single matching bean of type 178 * {@link PlatformTransactionManager} will be fetched from the BeanFactory. 179 * @see org.springframework.beans.factory.BeanFactory#getBean(Class) 180 * @see org.springframework.transaction.PlatformTransactionManager 181 */ 182 @Override 183 public void setBeanFactory(BeanFactory beanFactory) { 184 this.transactionInterceptor.setBeanFactory(beanFactory); 185 } 186 187 188 /** 189 * Creates an advisor for this FactoryBean's TransactionInterceptor. 190 */ 191 @Override 192 protected Object createMainInterceptor() { 193 this.transactionInterceptor.afterPropertiesSet(); 194 if (this.pointcut != null) { 195 return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor); 196 } 197 else { 198 // Rely on default pointcut. 199 return new TransactionAttributeSourceAdvisor(this.transactionInterceptor); 200 } 201 } 202 203 /** 204 * As of 4.2, this method adds {@link TransactionalProxy} to the set of 205 * proxy interfaces in order to avoid re-processing of transaction metadata. 206 */ 207 @Override 208 protected void postProcessProxyFactory(ProxyFactory proxyFactory) { 209 proxyFactory.addInterface(TransactionalProxy.class); 210 } 211 212}