Since the programmer is forced to catch all checked exception, I to throw checked exception in case of any problem. I would like to rollback on any of those expections. Writing rollbackFor=Exception.classon every #Transactional annotation is very error-prone, so I would like to tell spring, that: "whenever I write #Transactional, I mean #Transactional(rollbackFor=Exception.class)".
I know, that I could create a custom annotation, but that seems unnatural.
So is there a way to tell spring how it should handle checked excpetions globally?
Custom Shortcut Annotations
I know, that I could create a custom
annotation, but that seems unnatural.
No, this is exactly the use case for a Custom Annotation. Here's a quote from Custom Shortcut Annotations in the Spring Reference:
If you find you are repeatedly using
the same attributes with
#Transactional on many different
methods, then Spring's meta-annotation
support allows you to define custom
shortcut annotations for your specific
use cases.
Sample Code
And here's a sample annotation for your use case:
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Transactional(rollbackFor=Exception.class)
public #interface MyAnnotation {
}
Now annotate your services and / or methods with #MyAnnotation (you'll think of a better name). This is well-tested functionality that works by default. Why re-invent the wheel?
Approach with custom annotation looks good and straightforward, but if you actually don't want to use it, you can create a custom TransactionAttributeSource to modify interpretation of #Transactional:
public class RollbackForAllAnnotationTransactionAttributeSource
extends AnnotationTransactionAttributeSource {
#Override
protected TransactionAttribute determineTransactionAttribute(
AnnotatedElement ae) {
TransactionAttribute target = super.determineTransactionAttribute(ae);
if (target == null) return null;
else return new DelegatingTransactionAttribute(target) {
#Override
public boolean rollbackOn(Throwable ex) {
return true;
}
};
}
}
And instead of <tx:annotation-driven/> you configure it manually as follows (see source of AnnotationDrivenBeanDefinitionParser):
<bean id = "txAttributeSource"
class = "RollbackForAllAnnotationTransactionAttributeSource" />
<bean id = "txInterceptor"
class = "org.springframework.transaction.interceptor.TransactionInterceptor">
<property name = "transactionManagerBeanName" value = "transactionManager" />
<property name = "transactionAttributeSource" ref = "txAttributeSource" />
</bean>
<bean
class = "org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor">
<property name="transactionAttributeSource" ref = "txAttributeSource" />
<property name = "adviceBeanName" value = "txInterceptor" />
</bean>
Also you need <aop:config/> or <aop:aspectj-autoproxy />.
However note that such overrides may be confusing for other developers who expect a normal behaviour of #Transactional.
You can:
catch and wrap the checked exception into an unchecked exception - throw new RuntimeException(checkedException)
create a proxy around the method, using MethodInterceptor (or #AroundInvoke, or any other means to create aspects in spring), declare it to be executed before the <tx:annotation-driven /> by specifying order="1" and order="2" and catch and wrap there.
Looks like you can configure a transactional advice based on method name like this:
(from the Spring 2.0 docs)
Exactly which Exception types mark a transaction for rollback can be configured. Find below a snippet of XML configuration that demonstrates how one would configure rollback for a checked, application-specific Exception type.
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="false" rollback-for="NoProductInStockException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
Related
This issue has started after migrating from spring 4.1.2 to 5.0.5, spring batch to 3.0.9 to 4.0.1 and hibernate 4.2.0 to 5.2.16
I have a spring batch tasklet of the format -
public class MyTasklet implements Tasklet {
public RepeatStatus execute(StepContribution arg0, ChunkContext arg1) {
a();
}
public void a(){
//a few hibernate calls here
}
}
Now I want my hibernate transaction boundary to be the method a() [being called from execute] and not the execute() method.
But when I try applying point-cuts to achieve the same I get a message "no transaction in progress". I have provided the sample xml below.
In the aop pointcut -instead of the method name 'a'[i.e public * myPackage.MyTasklet.a(..)], if I use * (i.e public * myPackage.MyTasklet.*(..)] or 'execute'[i.e public * myPackage.MyTasklet.execute(..)] the code works fine. Due to some technical reasons it is important to have the boundary at 'a' due to which I cannot have 'execute' or any other method as the boundary.
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory" />
</bean>
<aop:config>
<aop:pointcut id="Op1"
expression="execution(public * myPackage.MyTasklet.a(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="Op1" />
</aop:config>
This question has been asked hundreds of times here. Your method a() is called internally, but internal method calls are never intercepted by Spring AOP because in that case you actually call this.a(). This does not go through the wrapping dynamic proxy used by Spring AOP. If a() was called from outside, e.e. by another component, it would work. This behaviour is comprehensively documented in the Spring AOP manual.
If you want to intercept internal method calls you have to use AspectJ instead of Spring AOP. How to configure Spring for AspectJ and LTW (load-time weaving) is also documented in the Spring manual.
P.S.: This is completely unrelated to your version upgrades. In older Spring and Spring Batch versions it would be the same. You mixed refactoring (version upgrade) with functional changes, which you should never do. Too many moving targets for debugging. Refactoring means to change the code (or the configuration, in this case) without changing its functionality.
In my Spring 4 application, I have a class like this:
class Address {
public getAdress(){
...
List<Town> towns = getTowns();
...
}
#CustomAnnotation
private List<Town> getTowns(){
}
}
With AspectJ I can easily intercept the getAdress() call.
The problem is with getTowns() that is not intercepted.
There are solutions such as Load-Time Weaving but that is difficult to tune and I don't what to reconfigure my application.
How can I capture any call made to any method annotated with CustomAnnotation without AspectJ ?
Regards
PS: I know that there is a workaround with self-reference but I don't find it very "clean".
Extracting interface:
interface TempIfc{
public getAdress();
}
class Address implements TempIfc{
#Override
public getAdress(){
...
List<Town> towns = getTowns();
...
}
#CustomAnnotation
private List<Town> getTowns(){
}
}
Adding config:
<bean id="tgt" class="Address">
<!-- your bean properties here -->
</bean>
<bean id="proxified" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="TempIfc"/>
<property name="target" ref="tgt"/>
<property name="interceptorNames">
<list>
<value>myInterceptor</value>
</list>
</property>
</bean>
<bean id="myInterceptor" class="MyMethodInterceptor"/>
<!-- Example of usage with some service -->
<bean id="someYourService" class="Service">
<property name="adress" ref="proxified" />
</bean>
And finally interceptor:
public class MyMethodInterceptor implements org.aopalliance.intercept.MethodInterceptor{
public Object invoke(org.aopalliance.intercept.MethodInvocation invocation){
System.out.println("Before calling any TempIfc method ");
// Actionally, you may use getMethod, getArguments here to explore details, or modify arguments
Object result = invocation.proceed(); //also it is not obligatory to call real method
System.out.println("After calling any TempIfc method ");
//you may modify result of invocation here
return result;
}
}
Here is the docs and javadocs about ProxyFactoryBean.
I think we can use ControlFlowPointcut provided by Spring.
ControlFlowPointcut looks at stacktrace and matches the pointcut only if it finds a particular method in the stacktrace. essentially pointcut is matched only when a method is called in a particular context.
In this case, we can create a pointcut like
ControlFlowPointcut cf = new ControlFlowPointcut(MyClass.class, "method1");
now, using ProxyFactory create a proxy on MyClass instance and call method1().
In above case, only method2() will be advised since it is called from method1().
I have the question. If my class has dependency like:
public class Test {
public Depend depend;
//Here methods
}
And it does not have setter for Depend property or constructor with Depend as argument, and it has no annotation for Spring but has xml config like:
<bean id="depend" class="xxx.Depend"></bean>
<bean id="test" class="xxx.Test">
<property name="depend" ref="depend" />
</bean>
Is it possible to inject Depend into Test using such config (actually his config does not work. I just wonder - can I change smth to make it work not using annotations or setter/constructor)?
It is not possible without using annotations.
Your current configuration needs some simple changes to make this work. Annotate the depend field with #Autowired and enable component scanning.
Here's a detailed explanation: http://www.mkyong.com/spring/spring-auto-scanning-components/
Yes it is possible without annotations, but you would need to create a TestBeanFactory and then create an object of Test and set Depend yourself before returning it.
<bean id="depend" class="xxx.Depend"></bean>
<bean id="testFactory" class="xxx.TestFactory">
<property name="depend" ref="depend" />
</bean>
<bean id="test" factory-bean="testFactory" factory-method="createTest">
</bean>
Then your test factory would look something like this.
public class TestFactory {
private Depend depend;
public setDepend(Depend depend) {
this.depend = depend
}
public Test createTest() {
Test test = new Test();
test.depend = this.depend;
return test;
}
}
I have a confusion about Spring transaction management. In my application I implemented transaction management using #Transactional in the service class. And I configured my spring.xml is like:
<beans:bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">${jdbc.dialect}</beans:prop>
<beans:prop key="hibernate.show_sql">false</beans:prop>
<beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<!-- Transaction manager -->
<beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="sessionFactory" />
</beans:bean>
If I implement transaction management in the configuration file like below without using #Transactional in the service class:
<aop:pointcut id="defaultServiceOperation"
expression="execution(* x.y.service.*Service.*(..))"/>
<aop:pointcut id="noTxServiceOperation"
expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/>
<aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>
<aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>
</aop:config>
does it give me any benefits over #Transactional? Someone told me using #Transactional is also implementation of AOP in spring. Can anyone explain me how?
It won't.
Benefits
If you don't need some very specified requirements or you have no performance issues, you shouldn't reinvent the wheel. Spring is almost perfectly designed, tested and sharped instrument, which can be replacement even for enterprise application servers. #Transactional is declarative way for managing transactions, it's far more convenient and readable than any aop xml configs. It's benefits include automatic handling of all transaction management aspects in declarative way: isolation and propagation levels (it's not easy to control nested transactions), timeouts, rollback conditions and distinct TransactionManagers for every single method of your service's class. Easy to read, easy to configure, easy to use.
#Transactional(readOnly = false, rollbackFor = ServiceException.class, isolation = Isolation.READ_COMMITTED)
public void myServiceJob(...)
When you see this method, it's easy to understand it's transactional attributes (without providing transactions implementation details in method). In case of plain AOP every time you want to know what happens in this method, you should check your xml config and find corresponding method, which is way less elegant.
On other hand, it's very hard to debug or use these proxies for any other declarative management. E.g. it's tricky (but not impossible) extract your bean from context and get something out of your wrapped bean using reflection (let's say, for monitoring purposes). In addition, when bean calls one of its method, it won't be delegated to proxy, because your bean knows nothing about proxy, so this refers to bean itself. The only way to cure this it to provide "self" field and set it in custom bean postprocessor (but your implementation suffers from this either).
Implementation
If Spring is configured to use transactional management, it's looking for #Transactional annotation on bean's definitions and creates auto-generated AOP proxy, which is subclass of your bean. Default behavior of Spring proxy is just delegating method's calls to underlying bean. Then Spring injects TransactionInterceptor with necessary TransactionManagers.
Code of interceptor looks quite simple:
public Object invoke(final MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {#code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
#Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
Inside of invokeWithinTransaction TransactionInterceptor determines whether should invocation be in scope of caller transaction (if one exists) or in a new one (it's about propagation level). Then it choses corresponding TransactionManager, configures timeout and isolation level, then invokes the method. After it decides if transaction should be commited or rolled back (choice is made based on caught exception and timing).
Using Spring and Java;
I have a pointcut which works OK. Now I want to remove the pointcut and AOP from the spring and just trigger the event with an event from inside the java code but I want "myAdvice" bean still called via Spring and its properties set.
I want to get ridoff all advice things even in java code, no more advice or any trace of AOP, I already have a nice event system working. I just want to instantiate my bean via Spring.
When I remove the second code block (one starting with "aop:config") then I noticed the bean "myAdvice" is not called and instantiated anymore. How can i stil call it set its properties without referencing it from the "aop:aspect" ?
in my application context ;
<bean id="myAdvice" class="com.myclass">
<property name="name1" ref="ref1" />
<property name="name2" ref="ref2" />
</bean>
<aop:config proxy-target-class="true">
<aop:aspect id="myAspect" ref="myAdvice">
<aop:pointcut id="myPointcut" expression="execution(* com.myexcmethod" />
<aop:around pointcut-ref="myPointcut" method="invoke" />
</aop:aspect>
</aop:config>
Your configuration looks fine . Your bean should be instantiated as a singleton bean when the ApplicationContext loads up . Maybe you would want to check if you have a default-lazy-init setting which prevents eager loading of the beans.
If you want to be able to get at the bean itself, you can pass it into this function:
public static Object unwrapProxy(Object proxiedBean) throws Exception {
while(proxiedBean instanceof Advised) {
proxiedBean = ((Advised) proxiedBean).getTargetSource().getTarget();
}
return proxiedBean;
}
Note that you need to have the loop in order to ensure that you unwrap all the AOP advice.