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