/** * 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 TransactionAttributeEditor * @see NameMatchTransactionAttributeSource */ public void setTransactionAttributes(Properties transactionAttributes) { NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); tas.setProperties(transactionAttributes); this.transactionAttributeSource = tas; }
/** * Parses the given properties into a name/attribute map. * Expects method names as keys and String attributes definitions as values, * parsable into TransactionAttribute instances via TransactionAttributeEditor. * @see #setNameMap * @see TransactionAttributeEditor */ public void setProperties(Properties transactionAttributes) { TransactionAttributeEditor tae = new TransactionAttributeEditor(); Enumeration<?> propNames = transactionAttributes.propertyNames(); while (propNames.hasMoreElements()) { String methodName = (String) propNames.nextElement(); String value = transactionAttributes.getProperty(methodName); tae.setAsText(value); TransactionAttribute attr = (TransactionAttribute) tae.getValue(); addTransactionalMethod(methodName, attr); } }
@Override @Nullable public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { if (!ClassUtils.isUserLevelMethod(method)) { return null; } // Look for direct name match. String methodName = method.getName(); TransactionAttribute attr = this.nameMap.get(methodName); if (attr == null) { // Look for most specific name match. String bestNameMatch = null; for (String mappedName : this.nameMap.keySet()) { if (isMatch(methodName, mappedName) && (bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) { attr = this.nameMap.get(mappedName); bestNameMatch = mappedName; } } } return attr; }
@Test public void nameMatchTransactionAttributeSourceWithEmptyMethodName() throws Exception { NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); Properties attributes = new Properties(); attributes.put("", "PROPAGATION_MANDATORY"); tas.setProperties(attributes); TransactionAttribute ta = tas.getTransactionAttribute(Object.class.getMethod("hashCode"), null); assertNull(ta); }
/** * 配置事务拦截器 * * @param transactionManager : 事务管理器 */ @Bean( CUSTOMIZE_TRANSACTION_INTERCEPTOR_NAME ) public TransactionInterceptor customizeTransactionInterceptor ( PlatformTransactionManager transactionManager ) { NameMatchTransactionAttributeSource transactionAttributeSource = new NameMatchTransactionAttributeSource(); RuleBasedTransactionAttribute readOnly = this.readOnlyTransactionRule(); RuleBasedTransactionAttribute required = this.requiredTransactionRule(); // 默认的只读事务配置 for ( String methodName : DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES ) { transactionAttributeSource.addTransactionalMethod( methodName , readOnly ); } // 默认的传播事务配置 for ( String methodName : DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES ) { transactionAttributeSource.addTransactionalMethod( methodName , required ); } // 定制的只读事务配置 for ( String methodName : customizeReadOnlyMethodRuleTransactionAttributes ) { transactionAttributeSource.addTransactionalMethod( methodName , readOnly ); } // 定制的传播事务配置 for ( String methodName : customizeRequiredMethodRuleTransactionAttributes ) { transactionAttributeSource.addTransactionalMethod( methodName , required ); } return new TransactionInterceptor( transactionManager , transactionAttributeSource ); }
private TransactionInterceptor createTransactionInterceptor(BeanFactory beanFactory, String transactionManagerName, PlatformTransactionManager transactionManager) { TransactionInterceptor ti = new TransactionInterceptor(); if (beanFactory != null) { ti.setBeanFactory(beanFactory); } if (transactionManagerName != null) { ti.setTransactionManagerBeanName(transactionManagerName); } if (transactionManager != null) { ti.setTransactionManager(transactionManager); } ti.setTransactionAttributeSource(new NameMatchTransactionAttributeSource()); ti.afterPropertiesSet(); return ti; }
/** * 配置事务拦截器 * * @param transactionManager : 事务管理器 */ @Bean( CUSTOMIZE_TRANSACTION_INTERCEPTOR_NAME ) public TransactionInterceptor customizeTransactionInterceptor ( PlatformTransactionManager transactionManager ) { NameMatchTransactionAttributeSource transactionAttributeSource = new NameMatchTransactionAttributeSource(); RuleBasedTransactionAttribute readOnly = this.readOnlyTransactionRule(); RuleBasedTransactionAttribute required = this.requiredTransactionRule(); // 默认的只读事务配置 for ( String methodName : DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES ) { transactionAttributeSource.addTransactionalMethod( methodName , readOnly ); } // 默认的传播事务配置 for ( String methodName : DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES ) { transactionAttributeSource.addTransactionalMethod( methodName , required ); } // 定制的只读事务配置 for ( String methodName : customizeReadOnlyMethodRuleTransactionAttributes ) { transactionAttributeSource.addTransactionalMethod( methodName , readOnly ); } // 定制的传播事务配置 for ( String methodName : customizeRequiredMethodRuleTransactionAttributes ) { transactionAttributeSource.addTransactionalMethod( methodName , required ); } return new TransactionInterceptor( transactionManager , transactionAttributeSource ); }
@Test public void nameMatchTransactionAttributeSourceMostSpecificMethodNameIsDefinitelyMatched() throws Exception { NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); Properties attributes = new Properties(); attributes.put("*", "PROPAGATION_REQUIRED"); attributes.put("hashCode", "PROPAGATION_MANDATORY"); tas.setProperties(attributes); TransactionAttribute ta = tas.getTransactionAttribute(Object.class.getMethod("hashCode"), null); assertNotNull(ta); assertEquals(TransactionDefinition.PROPAGATION_MANDATORY, ta.getPropagationBehavior()); }
/** * 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 TransactionAttributeEditor * @see NameMatchTransactionAttributeSource */ public void setTransactionAttributes(Properties transactionAttributes) { NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); tas.setProperties(transactionAttributes); this.transactionAttributeSource = tas; }
/** * 配置事务拦截器 * * @param transactionManager : 事务管理器 * @return */ @Bean( CUSTOMIZE_TRANSACTION_INTERCEPTOR_NAME ) public TransactionInterceptor customizeTransactionInterceptor ( PlatformTransactionManager transactionManager ) { NameMatchTransactionAttributeSource transactionAttributeSource = new NameMatchTransactionAttributeSource(); RuleBasedTransactionAttribute readOnly = this.readOnlyTransactionRule(); RuleBasedTransactionAttribute required = this.requiredTransactionRule(); // 默认的只读事务配置 for ( String methodName : DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES ) { transactionAttributeSource.addTransactionalMethod( methodName , readOnly ); } // 默认的传播事务配置 for ( String methodName : DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES ) { transactionAttributeSource.addTransactionalMethod( methodName , required ); } // 定制的只读事务配置 for ( String methodName : customizeReadOnlyMethodRuleTransactionAttributes ) { transactionAttributeSource.addTransactionalMethod( methodName , readOnly ); } // 定制的传播事务配置 for ( String methodName : customizeRequiredMethodRuleTransactionAttributes ) { transactionAttributeSource.addTransactionalMethod( methodName , required ); } return new TransactionInterceptor( transactionManager , transactionAttributeSource ); }
@Test public void nameMatchTransactionAttributeSourceWithStarAtStartOfMethodName() throws Exception { NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); Properties attributes = new Properties(); attributes.put("*ashCode", "PROPAGATION_REQUIRED"); tas.setProperties(attributes); TransactionAttribute ta = tas.getTransactionAttribute(Object.class.getMethod("hashCode"), null); assertNotNull(ta); assertEquals(TransactionDefinition.PROPAGATION_REQUIRED, ta.getPropagationBehavior()); }
/** * Parses the given properties into a name/attribute map. * Expects method names as keys and String attributes definitions as values, * parsable into TransactionAttribute instances via TransactionAttributeEditor. * @see #setNameMap * @see TransactionAttributeEditor */ public void setProperties(Properties transactionAttributes) { TransactionAttributeEditor tae = new TransactionAttributeEditor(); Enumeration<?> propNames = transactionAttributes.propertyNames(); while (propNames.hasMoreElements()) { String methodName = (String) propNames.nextElement(); String value = transactionAttributes.getProperty(methodName); tae.setAsText(value); TransactionAttribute attr = (TransactionAttribute) tae.getValue(); addTransactionalMethod(methodName, attr); } }
@Override @Nullable public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { if (!ClassUtils.isUserLevelMethod(method)) { return null; } // Look for direct name match. String methodName = method.getName(); TransactionAttribute attr = this.nameMap.get(methodName); if (attr == null) { // Look for most specific name match. String bestNameMatch = null; for (String mappedName : this.nameMap.keySet()) { if (isMatch(methodName, mappedName) && (bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) { attr = this.nameMap.get(mappedName); bestNameMatch = mappedName; } } } return attr; }
@Test public void serializableWithCompositeSource() throws Exception { NameMatchTransactionAttributeSource tas1 = new NameMatchTransactionAttributeSource(); Properties props = new Properties(); props.setProperty("methodName", "PROPAGATION_REQUIRED"); tas1.setProperties(props); NameMatchTransactionAttributeSource tas2 = new NameMatchTransactionAttributeSource(); props = new Properties(); props.setProperty("otherMethodName", "PROPAGATION_REQUIRES_NEW"); tas2.setProperties(props); TransactionInterceptor ti = new TransactionInterceptor(); ti.setTransactionAttributeSources(tas1, tas2); PlatformTransactionManager ptm = new SerializableTransactionManager(); ti.setTransactionManager(ptm); ti = (TransactionInterceptor) SerializationTestUtils.serializeAndDeserialize(ti); assertTrue(ti.getTransactionManager() instanceof SerializableTransactionManager); assertTrue(ti.getTransactionAttributeSource() instanceof CompositeTransactionAttributeSource); CompositeTransactionAttributeSource ctas = (CompositeTransactionAttributeSource) ti.getTransactionAttributeSource(); assertTrue(ctas.getTransactionAttributeSources()[0] instanceof NameMatchTransactionAttributeSource); assertTrue(ctas.getTransactionAttributeSources()[1] instanceof NameMatchTransactionAttributeSource); }
private TransactionInterceptor txAdvice() { NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource(); RuleBasedTransactionAttribute tran = new RuleBasedTransactionAttribute(); tran.setPropagationBehavior(TransactionAttribute.PROPAGATION_REQUIRED); tran.setIsolationLevel(TransactionAttribute.ISOLATION_READ_COMMITTED); RuleBasedTransactionAttribute tranNew = new RuleBasedTransactionAttribute(); tranNew.setPropagationBehavior(TransactionAttribute.PROPAGATION_REQUIRES_NEW); tranNew.setIsolationLevel(TransactionAttribute.ISOLATION_READ_COMMITTED); RuleBasedTransactionAttribute readOnly = new RuleBasedTransactionAttribute(); readOnly.setPropagationBehavior(TransactionAttribute.PROPAGATION_REQUIRED); readOnly.setReadOnly(true); // REQUIRES_NEW for (String method : PROPAGATION_REQUIRES_NEW_METHODS) { source.addTransactionalMethod(method, tranNew); } // readOnly for (String method : PROPAGATION_REQUIRES_READONLY_METHODS) { source.addTransactionalMethod(method, readOnly); } // REQUIRED source.addTransactionalMethod("*", tran); TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source); return txAdvice; }
@Test public void nameMatchTransactionAttributeSourceWithStarAtEndOfMethodName() throws Exception { NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); Properties attributes = new Properties(); attributes.put("hashCod*", "PROPAGATION_REQUIRED"); tas.setProperties(attributes); TransactionAttribute ta = tas.getTransactionAttribute(Object.class.getMethod("hashCode"), null); assertNotNull(ta); assertEquals(TransactionDefinition.PROPAGATION_REQUIRED, ta.getPropagationBehavior()); }
/** * Parses the given properties into a name/attribute map. * Expects method names as keys and String attributes definitions as values, * parsable into TransactionAttribute instances via TransactionAttributeEditor. * @see #setNameMap * @see TransactionAttributeEditor */ public void setProperties(Properties transactionAttributes) { TransactionAttributeEditor tae = new TransactionAttributeEditor(); for (Iterator it = transactionAttributes.keySet().iterator(); it.hasNext(); ) { String methodName = (String) it.next(); String value = transactionAttributes.getProperty(methodName); tae.setAsText(value); TransactionAttribute attr = (TransactionAttribute) tae.getValue(); addTransactionalMethod(methodName, attr); } }
public TransactionAttribute getTransactionAttribute(Method method, Class targetClass) { // look for direct name match String methodName = method.getName(); TransactionAttribute attr = (TransactionAttribute) this.nameMap.get(methodName); if (attr == null) { // look for most specific name match String bestNameMatch = null; for (Iterator it = this.nameMap.keySet().iterator(); it.hasNext();) { String mappedName = (String) it.next(); if (isMatch(methodName, mappedName) && (bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) { attr = (TransactionAttribute) this.nameMap.get(mappedName); bestNameMatch = mappedName; } } } return attr; }
/** * 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 TransactionAttributeEditor * @see NameMatchTransactionAttributeSource */ public void setTransactionAttributes(Properties transactionAttributes) { NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); tas.setProperties(transactionAttributes); this.transactionAttributeSource = tas; }
/** * Set a name/attribute map, consisting of method names * (e.g. "myMethod") and TransactionAttribute instances * (or Strings to be converted to TransactionAttribute instances). * @see TransactionAttribute * @see TransactionAttributeEditor */ public void setNameMap(Map nameMap) { Iterator it = nameMap.entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String name = (String) entry.getKey(); // Check whether we need to convert from String to TransactionAttribute. TransactionAttribute attr = null; if (entry.getValue() instanceof TransactionAttribute) { attr = (TransactionAttribute) entry.getValue(); } else { TransactionAttributeEditor editor = new TransactionAttributeEditor(); editor.setAsText(entry.getValue().toString()); attr = (TransactionAttribute) editor.getValue(); } addTransactionalMethod(name, attr); } }