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 * &lt;bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
084 *     abstract="true"&gt;
085 *   &lt;property name="transactionManager" ref="transactionManager"/&gt;
086 *   &lt;property name="transactionAttributes"&gt;
087 *     &lt;props&gt;
088 *       &lt;prop key="insert*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;
089 *       &lt;prop key="update*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;
090 *       &lt;prop key="*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;
091 *     &lt;/props&gt;
092 *   &lt;/property&gt;
093 * &lt;/bean&gt;
094 *
095 * &lt;bean id="myProxy" parent="baseTransactionProxy"&gt;
096 *   &lt;property name="target" ref="myTarget"/&gt;
097 * &lt;/bean&gt;
098 *
099 * &lt;bean id="yourProxy" parent="baseTransactionProxy"&gt;
100 *   &lt;property name="target" ref="yourTarget"/&gt;
101 * &lt;/bean&gt;</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}