/* * Copyright 2002-2006 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.transaction.interceptor; import java.util.Properties; import org.springframework.aop.Pointcut; import org.springframework.aop.framework.AbstractSingletonProxyFactoryBean; import org.springframework.aop.support.DefaultPointcutAdvisor; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.transaction.PlatformTransactionManager; /** * Proxy factory bean for simplified declarative transaction handling. * This is a convenient alternative to a standard AOP * {@link org.springframework.aop.framework.ProxyFactoryBean} * with a separate {@link TransactionInterceptor} definition. * * <p>This class is intended to cover the <i>typical</i> case of declarative * transaction demarcation: namely, wrapping a singleton target object with a * transactional proxy, proxying all the interfaces that the target implements. * * <p>There are three main properties that need to be specified: * <ul> * <li>"transactionManager": the {@link PlatformTransactionManager} implementation to use * (for example, a {@link org.springframework.transaction.jta.JtaTransactionManager} instance) * <li>"target": the target object that a transactional proxy should be created for * <li>"transactionAttributes": the transaction attributes (for example, propagation * behavior and "readOnly" flag) per target method name (or method name pattern) * </ul> * * <p>If the "transactionManager" property is not set explicitly and this {@link FactoryBean} * is running in a {@link ListableBeanFactory}, a single matching bean of type * {@link PlatformTransactionManager} will be fetched from the {@link BeanFactory}. * * <p>In contrast to {@link TransactionInterceptor}, the transaction attributes are * specified as properties, with method names as keys and transaction attribute * descriptors as values. Method names are always applied to the target class. * * <p>Internally, a {@link TransactionInterceptor} instance is used, but the user of this * class does not have to care. Optionally, a method pointcut can be specified * to cause conditional invocation of the underlying {@link TransactionInterceptor}. * * <p>The "preInterceptors" and "postInterceptors" properties can be set to add * additional interceptors to the mix, like * {@link org.springframework.aop.interceptor.PerformanceMonitorInterceptor} or * {@link org.springframework.orm.hibernate3.HibernateInterceptor} / * {@link org.springframework.orm.jdo.JdoInterceptor}. * * <p><b>HINT:</b> This class is often used with parent / child bean definitions. * Typically, you will define the transaction manager and default transaction * attributes (for method name patterns) in an abstract parent bean definition, * deriving concrete child bean definitions for specific target objects. * This reduces the per-bean definition effort to a minimum. * * <pre code="class"> * <bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" * abstract="true"> * <property name="transactionManager" ref="transactionManager"/> * <property name="transactionAttributes"> * <props> * <prop key="insert*">PROPAGATION_REQUIRED</prop> * <prop key="update*">PROPAGATION_REQUIRED</prop> * <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> * </props> * </property> * </bean> * * <bean id="myProxy" parent="baseTransactionProxy"> * <property name="target" ref="myTarget"/> * </bean> * * <bean id="yourProxy" parent="baseTransactionProxy"> * <property name="target" ref="yourTarget"/> * </bean></pre> * * @author Juergen Hoeller * @author Dmitriy Kopylenko * @author Rod Johnson * @since 21.08.2003 * @see #setTransactionManager * @see #setTarget * @see #setTransactionAttributes * @see TransactionInterceptor * @see org.springframework.aop.framework.ProxyFactoryBean */ public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean implements FactoryBean, BeanFactoryAware { private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor(); private Pointcut pointcut; /** * Set the transaction manager. This will perform actual * transaction management: This class is just a way of invoking it. * @see TransactionInterceptor#setTransactionManager */ public void setTransactionManager(PlatformTransactionManager transactionManager) { this.transactionInterceptor.setTransactionManager(transactionManager); } /** * Set properties with method names as keys and transaction attribute * descriptors (parsed via TransactionAttributeEditor) as values: * e.g. key = "myMethod", value = "PROPAGATION_REQUIRED,readOnly". * <p>Note: Method names are always applied to the target class, * no matter if defined in an interface or the class itself. * <p>Internally, a NameMatchTransactionAttributeSource will be * created from the given properties. * @see #setTransactionAttributeSource * @see TransactionInterceptor#setTransactionAttributes * @see TransactionAttributeEditor * @see NameMatchTransactionAttributeSource */ public void setTransactionAttributes(Properties transactionAttributes) { this.transactionInterceptor.setTransactionAttributes(transactionAttributes); } /** * Set the transaction attribute source which is used to find transaction * attributes. If specifying a String property value, a PropertyEditor * will create a MethodMapTransactionAttributeSource from the value. * @see #setTransactionAttributes * @see TransactionInterceptor#setTransactionAttributeSource * @see TransactionAttributeSourceEditor * @see MethodMapTransactionAttributeSource * @see NameMatchTransactionAttributeSource * @see AttributesTransactionAttributeSource * @see org.springframework.transaction.annotation.AnnotationTransactionAttributeSource */ public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) { this.transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource); } /** * Set a pointcut, i.e a bean that can cause conditional invocation * of the TransactionInterceptor depending on method and attributes passed. * Note: Additional interceptors are always invoked. * @see #setPreInterceptors * @see #setPostInterceptors */ public void setPointcut(Pointcut pointcut) { this.pointcut = pointcut; } /** * This callback is optional: If running in a BeanFactory and no transaction * manager has been set explicitly, a single matching bean of type * PlatformTransactionManager will be fetched from the BeanFactory. * @see org.springframework.beans.factory.BeanFactoryUtils#beanOfTypeIncludingAncestors * @see org.springframework.transaction.PlatformTransactionManager */ public void setBeanFactory(BeanFactory beanFactory) { if (this.transactionInterceptor.getTransactionManager() == null && beanFactory instanceof ListableBeanFactory) { ListableBeanFactory lbf = (ListableBeanFactory) beanFactory; PlatformTransactionManager ptm = (PlatformTransactionManager) BeanFactoryUtils.beanOfTypeIncludingAncestors(lbf, PlatformTransactionManager.class); this.transactionInterceptor.setTransactionManager(ptm); } } /** * Creates an advisor for this FactoryBean's TransactionInterceptor. */ protected Object createMainInterceptor() { this.transactionInterceptor.afterPropertiesSet(); if (this.pointcut != null) { return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor); } else { // Rely on default pointcut. return new TransactionAttributeSourceAdvisor(this.transactionInterceptor); } } }