1. /*
  2. * Copyright 2002-2004 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.transaction.interceptor;
  17. import java.util.Properties;
  18. import org.springframework.aop.Advisor;
  19. import org.springframework.aop.Pointcut;
  20. import org.springframework.aop.TargetSource;
  21. import org.springframework.aop.framework.AopConfigException;
  22. import org.springframework.aop.framework.ProxyConfig;
  23. import org.springframework.aop.framework.ProxyFactory;
  24. import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
  25. import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
  26. import org.springframework.aop.support.AopUtils;
  27. import org.springframework.aop.support.DefaultPointcutAdvisor;
  28. import org.springframework.aop.target.SingletonTargetSource;
  29. import org.springframework.beans.factory.FactoryBean;
  30. import org.springframework.beans.factory.InitializingBean;
  31. import org.springframework.transaction.PlatformTransactionManager;
  32. /**
  33. * Proxy factory bean for simplified declarative transaction handling.
  34. * Alternative to the standard AOP ProxyFactoryBean with a TransactionInterceptor.
  35. *
  36. * <p>This class is intended to cover the <i>typical</i> case of declarative
  37. * transaction demarcation: namely, wrapping a (singleton) target object with a
  38. * transactional proxy, proxying all the interfaces that the target implements.
  39. *
  40. * <p>In contrast to TransactionInterceptor, the transaction attributes are
  41. * specified as properties, with method names as keys and transaction attribute
  42. * descriptors as values. Method names are always applied to the target class.
  43. *
  44. * <p>Internally, a TransactionInterceptor instance is used, but the user of this
  45. * class does not have to care. Optionally, a MethodPointcut can be specified
  46. * to cause conditional invocation of the underlying TransactionInterceptor.
  47. *
  48. * <p>The preInterceptors and postInterceptors properties can be set to add
  49. * additional interceptors to the mix, like PerformanceMonitorInterceptor or
  50. * HibernateInterceptor/JdoInterceptor.
  51. *
  52. * @author Juergen Hoeller
  53. * @author Dmitriy Kopylenko
  54. * @author Rod Johnson
  55. * @since 21.08.2003
  56. * @see org.springframework.aop.framework.ProxyFactoryBean
  57. * @see TransactionInterceptor
  58. * @see #setTransactionAttributes
  59. * @version $Id: TransactionProxyFactoryBean.java,v 1.29 2004/05/23 20:13:33 jhoeller Exp $
  60. */
  61. public class TransactionProxyFactoryBean extends ProxyConfig implements FactoryBean, InitializingBean {
  62. private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
  63. private Object target;
  64. private Class[] proxyInterfaces;
  65. private Pointcut pointcut;
  66. private Object[] preInterceptors;
  67. private Object[] postInterceptors;
  68. /** Default is global AdvisorAdapterRegistry */
  69. private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
  70. private Object proxy;
  71. /**
  72. * Set the transaction manager. This will perform actual
  73. * transaction management: This class is just a way of invoking it.
  74. * @see TransactionInterceptor#setTransactionManager
  75. */
  76. public void setTransactionManager(PlatformTransactionManager transactionManager) {
  77. this.transactionInterceptor.setTransactionManager( transactionManager);
  78. }
  79. /**
  80. * Set the target object, i.e. the bean to be wrapped with a transactional proxy.
  81. * <p>The target may be any object, in which case a SingletonTargetSource will
  82. * be created. If it is a TargetSource, no wrapper TargetSource is created:
  83. * This enables the use of a pooling or prototype TargetSource etc.
  84. * @see org.springframework.aop.TargetSource
  85. * @see org.springframework.aop.target.SingletonTargetSource
  86. */
  87. public void setTarget(Object target) {
  88. this.target = target;
  89. }
  90. /**
  91. * Specify the set of interfaces being proxied.
  92. * <p>If left null (the default), the AOP infrastructure works
  93. * out which interfaces need proxying by analyzing the target,
  94. * proxying all the interfaces that the target object implements.
  95. */
  96. public void setProxyInterfaces(String[] interfaceNames) throws ClassNotFoundException {
  97. this.proxyInterfaces = AopUtils.toInterfaceArray(interfaceNames);
  98. }
  99. /**
  100. * Set properties with method names as keys and transaction attribute
  101. * descriptors (parsed via TransactionAttributeEditor) as values:
  102. * e.g. key = "myMethod", value = "PROPAGATION_REQUIRED,readOnly".
  103. * <p>Note: Method names are always applied to the target class,
  104. * no matter if defined in an interface or the class itself.
  105. * <p>Internally, a NameMatchTransactionAttributeSource will be
  106. * created from the given properties.
  107. * @see #setTransactionAttributeSource
  108. * @see TransactionInterceptor#setTransactionAttributes
  109. * @see TransactionAttributeEditor
  110. * @see NameMatchTransactionAttributeSource
  111. */
  112. public void setTransactionAttributes(Properties transactionAttributes) {
  113. this.transactionInterceptor.setTransactionAttributes(transactionAttributes);
  114. }
  115. /**
  116. * Set the transaction attribute source which is used to find transaction
  117. * attributes. If specifying a String property value, a PropertyEditor
  118. * will create a MethodMapTransactionAttributeSource from the value.
  119. * @see #setTransactionAttributes
  120. * @see TransactionInterceptor#setTransactionAttributeSource
  121. * @see TransactionAttributeSourceEditor
  122. * @see MethodMapTransactionAttributeSource
  123. * @see NameMatchTransactionAttributeSource
  124. */
  125. public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
  126. this.transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource);
  127. }
  128. /**
  129. * Set a pointcut, i.e a bean that can cause conditional invocation
  130. * of the TransactionInterceptor depending on method and attributes passed.
  131. * Note: Additional interceptors are always invoked.
  132. * @see #setPreInterceptors
  133. * @see #setPostInterceptors
  134. */
  135. public void setPointcut(Pointcut pointcut) {
  136. this.pointcut = pointcut;
  137. }
  138. /**
  139. * Set additional interceptors (or advisors) to be applied before the
  140. * implicit transaction interceptor, e.g. PerformanceMonitorInterceptor.
  141. * @see org.springframework.aop.interceptor.PerformanceMonitorInterceptor
  142. */
  143. public void setPreInterceptors(Object[] preInterceptors) {
  144. this.preInterceptors = preInterceptors;
  145. }
  146. /**
  147. * Set additional interceptors (or advisors) to be applied after the
  148. * implicit transaction interceptor, e.g. HibernateInterceptors for
  149. * eagerly binding Sessions to the current thread when using JTA.
  150. * <p>Note that this is just necessary if you rely on those interceptors in general:
  151. * HibernateTemplate and JdoTemplate work nicely with JtaTransactionManager through
  152. * implicit on-demand thread binding.
  153. * @see org.springframework.orm.hibernate.HibernateInterceptor
  154. * @see org.springframework.orm.jdo.JdoInterceptor
  155. */
  156. public void setPostInterceptors(Object[] preInterceptors) {
  157. this.postInterceptors = preInterceptors;
  158. }
  159. /**
  160. * Specify the AdvisorAdapterRegistry to use.
  161. * Default is the global AdvisorAdapterRegistry.
  162. * @see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry
  163. */
  164. public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
  165. this.advisorAdapterRegistry = advisorAdapterRegistry;
  166. }
  167. public void afterPropertiesSet() throws AopConfigException {
  168. this.transactionInterceptor.afterPropertiesSet();
  169. if (this.target == null) {
  170. throw new IllegalArgumentException("'target' is required");
  171. }
  172. ProxyFactory proxyFactory = new ProxyFactory();
  173. if (this.preInterceptors != null) {
  174. for (int i = 0; i < this.preInterceptors.length; i++) {
  175. proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.preInterceptors[i]));
  176. }
  177. }
  178. if (this.pointcut != null) {
  179. Advisor advice = new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
  180. proxyFactory.addAdvisor(advice);
  181. }
  182. else {
  183. // rely on default pointcut
  184. proxyFactory.addAdvisor(new TransactionAttributeSourceAdvisor(this.transactionInterceptor));
  185. // could just do the following, but it's usually less efficient because of AOP advice chain caching
  186. // proxyFactory.addInterceptor(transactionInterceptor);
  187. }
  188. if (this.postInterceptors != null) {
  189. for (int i = 0; i < this.postInterceptors.length; i++) {
  190. proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.postInterceptors[i]));
  191. }
  192. }
  193. proxyFactory.copyFrom(this);
  194. proxyFactory.setTargetSource(createTargetSource(this.target));
  195. if (this.proxyInterfaces != null) {
  196. proxyFactory.setInterfaces(this.proxyInterfaces);
  197. }
  198. else if (!getProxyTargetClass()) {
  199. if (this.target instanceof TargetSource) {
  200. throw new AopConfigException("Either 'proxyInterfaces' or 'proxyTargetClass' is required " +
  201. "when using a TargetSource as 'target");
  202. }
  203. // rely on AOP infrastructure to tell us what interfaces to proxy
  204. proxyFactory.setInterfaces(AopUtils.getAllInterfaces(this.target));
  205. }
  206. this.proxy = proxyFactory.getProxy();
  207. }
  208. /**
  209. * Set the target or TargetSource.
  210. * @param target target. If this is an implementation of TargetSource it is
  211. * used as our TargetSource; otherwise it is wrapped in a SingletonTargetSource.
  212. * @return a TargetSource for this object
  213. */
  214. protected TargetSource createTargetSource(Object target) {
  215. if (target instanceof TargetSource) {
  216. return (TargetSource) target;
  217. }
  218. else {
  219. return new SingletonTargetSource(target);
  220. }
  221. }
  222. public Object getObject() {
  223. return this.proxy;
  224. }
  225. public Class getObjectType() {
  226. if (this.proxy != null) {
  227. return this.proxy.getClass();
  228. }
  229. else if (this.target != null && this.target instanceof TargetSource) {
  230. return this.target.getClass();
  231. }
  232. else {
  233. return null;
  234. }
  235. }
  236. public boolean isSingleton() {
  237. return true;
  238. }
  239. }