/** * Test the important case where the invocation is on a proxied interface method * but the attribute is defined on the target class. */ @Test public void transactionAttributeDeclaredOnCglibClassMethod() throws Exception { Method classMethod = ITestBean.class.getMethod("getAge"); TestBean1 tb = new TestBean1(); ProxyFactory pf = new ProxyFactory(tb); pf.setProxyTargetClass(true); Object proxy = pf.getProxy(); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(classMethod, proxy.getClass()); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); }
/** * Test that when an attribute exists on both class and interface, class takes precedence. */ @Test public void transactionAttributeOnTargetClassMethodOverridesAttributeOnInterfaceMethod() throws Exception { Method interfaceMethod = ITestBean3.class.getMethod("getAge"); Method interfaceMethod2 = ITestBean3.class.getMethod("getName"); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(interfaceMethod, TestBean3.class); assertEquals(TransactionAttribute.PROPAGATION_REQUIRES_NEW, actual.getPropagationBehavior()); assertEquals(TransactionAttribute.ISOLATION_REPEATABLE_READ, actual.getIsolationLevel()); assertEquals(5, actual.getTimeout()); assertTrue(actual.isReadOnly()); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); TransactionAttribute actual2 = atas.getTransactionAttribute(interfaceMethod2, TestBean3.class); assertEquals(TransactionAttribute.PROPAGATION_REQUIRED, actual2.getPropagationBehavior()); }
@Test public void customClassAttributeWithReadOnlyOverrideOnInterface() throws Exception { Method method = TestInterface9.class.getMethod("getAge"); Transactional annotation = AnnotationUtils.findAnnotation(method, Transactional.class); assertNull("AnnotationUtils.findAnnotation should not find @Transactional for TestBean9.getAge()", annotation); annotation = AnnotationUtils.findAnnotation(TestBean9.class, Transactional.class); assertNotNull("AnnotationUtils.findAnnotation failed to find @Transactional for TestBean9", annotation); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean9.class); assertNotNull("Failed to retrieve TransactionAttribute for TestBean9.getAge()", actual); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); assertTrue(actual.isReadOnly()); }
@Test public void customMethodAttributeWithReadOnlyOverrideOnInterface() throws Exception { Method method = TestInterface10.class.getMethod("getAge"); Transactional annotation = AnnotationUtils.findAnnotation(method, Transactional.class); assertNotNull("AnnotationUtils.findAnnotation failed to find @Transactional for TestBean10.getAge()", annotation); annotation = AnnotationUtils.findAnnotation(TestBean10.class, Transactional.class); assertNull("AnnotationUtils.findAnnotation should not find @Transactional for TestBean10", annotation); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean10.class); assertNotNull("Failed to retrieve TransactionAttribute for TestBean10.getAge()", actual); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); assertTrue(actual.isReadOnly()); }
/** * Test the important case where the invocation is on a proxied interface method * but the attribute is defined on the target class. */ @Test public void testTransactionAttributeDeclaredOnCglibClassMethod() throws Exception { Method classMethod = ITestBean.class.getMethod("getAge", (Class[]) null); TestBean1 tb = new TestBean1(); ProxyFactory pf = new ProxyFactory(tb); pf.setProxyTargetClass(true); Object proxy = pf.getProxy(); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(classMethod, proxy.getClass()); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); }
/** * Test that when an attribute exists on both class and interface, class takes precedence. */ @Test public void testTransactionAttributeOnTargetClassMethodOverridesAttributeOnInterfaceMethod() throws Exception { Method interfaceMethod = ITestBean3.class.getMethod("getAge", (Class[]) null); Method interfaceMethod2 = ITestBean3.class.getMethod("getName", (Class[]) null); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(interfaceMethod, TestBean3.class); assertEquals(TransactionAttribute.PROPAGATION_REQUIRES_NEW, actual.getPropagationBehavior()); assertEquals(TransactionAttribute.ISOLATION_REPEATABLE_READ, actual.getIsolationLevel()); assertEquals(5, actual.getTimeout()); assertTrue(actual.isReadOnly()); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); TransactionAttribute actual2 = atas.getTransactionAttribute(interfaceMethod2, TestBean3.class); assertEquals(TransactionAttribute.PROPAGATION_REQUIRED, actual2.getPropagationBehavior()); }
/** * 支持当前事务;如果不存在创建一个新的 */ private RuleBasedTransactionAttribute requiredTransactionRule () { RuleBasedTransactionAttribute required = new RuleBasedTransactionAttribute(); required.setRollbackRules( Collections.singletonList( new RollbackRuleAttribute( Exception.class ) ) ); required.setPropagationBehavior( TransactionDefinition.PROPAGATION_REQUIRED ); required.setTimeout( TransactionDefinition.TIMEOUT_DEFAULT ); return required; }
/** * 只读事务 */ private RuleBasedTransactionAttribute readOnlyTransactionRule () { RuleBasedTransactionAttribute readOnly = new RuleBasedTransactionAttribute(); readOnly.setReadOnly( true ); readOnly.setPropagationBehavior( TransactionDefinition.PROPAGATION_NOT_SUPPORTED ); return readOnly; }
/** * 支持当前事务;如果不存在创建一个新的 * {@link org.springframework.transaction.annotation.Propagation#REQUIRED} */ private RuleBasedTransactionAttribute requiredTransactionRule () { RuleBasedTransactionAttribute required = new RuleBasedTransactionAttribute(); required.setRollbackRules( Collections.singletonList( new RollbackRuleAttribute( Exception.class ) ) ); required.setPropagationBehavior( TransactionDefinition.PROPAGATION_REQUIRED ); required.setTimeout( TransactionDefinition.TIMEOUT_DEFAULT ); return required; }
/** * 只读事务 * {@link org.springframework.transaction.annotation.Propagation#NOT_SUPPORTED} */ private RuleBasedTransactionAttribute readOnlyTransactionRule () { RuleBasedTransactionAttribute readOnly = new RuleBasedTransactionAttribute(); readOnly.setReadOnly( true ); readOnly.setPropagationBehavior( TransactionDefinition.PROPAGATION_NOT_SUPPORTED ); return readOnly; }
/** * Test the important case where the invocation is on a proxied interface method * but the attribute is defined on the target class. */ @Test public void transactionAttributeDeclaredOnClassMethod() throws Exception { Method classMethod = ITestBean.class.getMethod("getAge"); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(classMethod, TestBean1.class); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); }
/** * Test case where attribute is on the interface method. */ @Test public void transactionAttributeDeclaredOnInterfaceMethodOnly() throws Exception { Method interfaceMethod = ITestBean2.class.getMethod("getAge"); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(interfaceMethod, TestBean2.class); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); }
/** * Test that transaction attribute is inherited from class * if not specified on method. */ @Test public void defaultsToClassTransactionAttribute() throws Exception { Method method = TestBean4.class.getMethod("getAge"); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean4.class); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); }
@Test public void customClassAttributeDetected() throws Exception { Method method = TestBean5.class.getMethod("getAge"); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean5.class); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); }
@Test public void customMethodAttributeDetected() throws Exception { Method method = TestBean6.class.getMethod("getAge"); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean6.class); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); }
@Test public void customClassAttributeWithReadOnlyOverrideDetected() throws Exception { Method method = TestBean7.class.getMethod("getAge"); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean7.class); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); assertTrue(actual.isReadOnly()); }
@Test public void customMethodAttributeWithReadOnlyOverrideDetected() throws Exception { Method method = TestBean8.class.getMethod("getAge"); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean8.class); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); assertTrue(actual.isReadOnly()); }
/** * Construit un transactionInterceptor avec une configuration par défaut. */ public static TransactionInterceptor defaultTransactionInterceptor(PlatformTransactionManager transactionManager, List<Class<? extends Exception>> additionalRollbackRuleExceptions) { TransactionInterceptor transactionInterceptor = new TransactionInterceptor(); Properties transactionAttributes = new Properties(); List<RollbackRuleAttribute> rollbackRules = Lists.newArrayList(); rollbackRules.add(new RollbackRuleAttribute(ServiceException.class)); // TODO voir si on ajoute SecurityServiceException.class en fonction de ce que ça donne sur le Wombat // ou voir si on ne la dégage pas carrément en fait... for (Class<? extends Exception> clazz : additionalRollbackRuleExceptions) { rollbackRules.add(new RollbackRuleAttribute(clazz)); } DefaultTransactionAttribute readOnlyTransactionAttributes = new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED); readOnlyTransactionAttributes.setReadOnly(true); RuleBasedTransactionAttribute writeTransactionAttributes = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, rollbackRules); String readOnlyTransactionAttributesDefinition = readOnlyTransactionAttributes.toString(); String writeTransactionAttributesDefinition = writeTransactionAttributes.toString(); // read-only transactionAttributes.setProperty("is*", readOnlyTransactionAttributesDefinition); transactionAttributes.setProperty("has*", readOnlyTransactionAttributesDefinition); transactionAttributes.setProperty("get*", readOnlyTransactionAttributesDefinition); transactionAttributes.setProperty("list*", readOnlyTransactionAttributesDefinition); transactionAttributes.setProperty("search*", readOnlyTransactionAttributesDefinition); transactionAttributes.setProperty("find*", readOnlyTransactionAttributesDefinition); transactionAttributes.setProperty("count*", readOnlyTransactionAttributesDefinition); // write et rollback-rule transactionAttributes.setProperty("*", writeTransactionAttributesDefinition); transactionInterceptor.setTransactionAttributes(transactionAttributes); transactionInterceptor.setTransactionManager(transactionManager); return transactionInterceptor; }
@Override public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) { StorageTx ann = AnnotationUtils.getAnnotation(ae, StorageTx.class); if (ann != null) { RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); return rbta; } else { return null; } }
/** * Test the important case where the invocation is on a proxied interface method * but the attribute is defined on the target class. */ @Test public void testTransactionAttributeDeclaredOnClassMethod() throws Exception { Method classMethod = ITestBean.class.getMethod("getAge", (Class[]) null); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(classMethod, TestBean1.class); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); }
/** * Test case where attribute is on the interface method. */ @Test public void testTransactionAttributeDeclaredOnInterfaceMethodOnly() throws Exception { Method interfaceMethod = ITestBean2.class.getMethod("getAge", (Class[]) null); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(interfaceMethod, TestBean2.class); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); }
/** * Test that transaction attribute is inherited from class * if not specified on method. */ @Test public void testDefaultsToClassTransactionAttribute() throws Exception { Method method = TestBean4.class.getMethod("getAge", (Class[]) null); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean4.class); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); }
@Test public void testCustomClassAttributeDetected() throws Exception { Method method = TestBean5.class.getMethod("getAge", (Class[]) null); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean5.class); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); }
@Test public void testCustomMethodAttributeDetected() throws Exception { Method method = TestBean6.class.getMethod("getAge", (Class[]) null); AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean5.class); RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class)); assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); }
private RootBeanDefinition parseAttributeSource(Element attrEle, ParserContext parserContext) { List<Element> methods = DomUtils.getChildElementsByTagName(attrEle, METHOD_ELEMENT); ManagedMap<TypedStringValue, RuleBasedTransactionAttribute> transactionAttributeMap = new ManagedMap<TypedStringValue, RuleBasedTransactionAttribute>(methods.size()); transactionAttributeMap.setSource(parserContext.extractSource(attrEle)); for (Element methodEle : methods) { String name = methodEle.getAttribute(METHOD_NAME_ATTRIBUTE); TypedStringValue nameHolder = new TypedStringValue(name); nameHolder.setSource(parserContext.extractSource(methodEle)); RuleBasedTransactionAttribute attribute = new RuleBasedTransactionAttribute(); String propagation = methodEle.getAttribute(PROPAGATION_ATTRIBUTE); String isolation = methodEle.getAttribute(ISOLATION_ATTRIBUTE); String timeout = methodEle.getAttribute(TIMEOUT_ATTRIBUTE); String readOnly = methodEle.getAttribute(READ_ONLY_ATTRIBUTE); if (StringUtils.hasText(propagation)) { attribute.setPropagationBehaviorName(RuleBasedTransactionAttribute.PREFIX_PROPAGATION + propagation); } if (StringUtils.hasText(isolation)) { attribute.setIsolationLevelName(RuleBasedTransactionAttribute.PREFIX_ISOLATION + isolation); } if (StringUtils.hasText(timeout)) { try { attribute.setTimeout(Integer.parseInt(timeout)); } catch (NumberFormatException ex) { parserContext.getReaderContext().error("Timeout must be an integer value: [" + timeout + "]", methodEle); } } if (StringUtils.hasText(readOnly)) { attribute.setReadOnly(Boolean.valueOf(methodEle.getAttribute(READ_ONLY_ATTRIBUTE))); } List<RollbackRuleAttribute> rollbackRules = new LinkedList<RollbackRuleAttribute>(); if (methodEle.hasAttribute(ROLLBACK_FOR_ATTRIBUTE)) { String rollbackForValue = methodEle.getAttribute(ROLLBACK_FOR_ATTRIBUTE); addRollbackRuleAttributesTo(rollbackRules,rollbackForValue); } if (methodEle.hasAttribute(NO_ROLLBACK_FOR_ATTRIBUTE)) { String noRollbackForValue = methodEle.getAttribute(NO_ROLLBACK_FOR_ATTRIBUTE); addNoRollbackRuleAttributesTo(rollbackRules,noRollbackForValue); } attribute.setRollbackRules(rollbackRules); transactionAttributeMap.put(nameHolder, attribute); } RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchTransactionAttributeSource.class); attributeSourceDefinition.setSource(parserContext.extractSource(attrEle)); attributeSourceDefinition.getPropertyValues().add("nameMap", transactionAttributeMap); return attributeSourceDefinition; }
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(!(bean instanceof NameMatchTransactionAttributeSource)) { return bean; } try { NameMatchTransactionAttributeSource transactionAttributeSource = (NameMatchTransactionAttributeSource)bean; Field nameMapField = ReflectionUtils.findField(NameMatchTransactionAttributeSource.class, "nameMap"); nameMapField.setAccessible(true); @SuppressWarnings("unchecked") Map<String, TransactionAttribute> nameMap = (Map<String, TransactionAttribute>) nameMapField.get(transactionAttributeSource); for(Entry<String, TransactionAttribute> entry : nameMap.entrySet()) { RuleBasedTransactionAttribute attr = (RuleBasedTransactionAttribute)entry.getValue(); //仅对read-only的处理 if(!attr.isReadOnly()) { continue; } String methodName = entry.getKey(); Boolean isForceChoiceRead = Boolean.FALSE; if(forceChoiceReadWhenWrite) { //不管之前操作是写,默认强制从读库读 (设置为NOT_SUPPORTED即可) //NOT_SUPPORTED会挂起之前的事务 attr.setPropagationBehavior(Propagation.NOT_SUPPORTED.value()); isForceChoiceRead = Boolean.TRUE; } else { //否则 设置为SUPPORTS(这样可以参与到写事务) attr.setPropagationBehavior(Propagation.SUPPORTS.value()); } //logger.debug(arg0);.debug("read/write transaction process method:{} force read:{}", methodName, isForceChoiceRead); readMethodMap.put(methodName, isForceChoiceRead); } } catch (Exception e) { throw new ReadWriteDataSourceTransactionException("process read/write transaction error", e); } return bean; }