Spring #transactional behaving strangely with mode=aspectj - java

I've been trying to get Spring transactions working properly in my application for days, and now I have nowhere to turn but to the community. Thanks in advance for your help.
My application has specific requirements where I need to annotate a protected overridden method with #Transactional and call this method from the abstract parent class. From what I've read, I can not use proxies, and must use mode=aspectj.
First, some configuration:
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="false" mode="aspectj" />
<context:load-time-weaver />
<bean name="ID_DataAccessor" class="dal.DataAccessor">
<constructor-arg ref="dataSource" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost" />
.....
<property name="defaultAutoCommit" value="true" />
</bean>
If I use the #Transactional annotation on a method in ID_DataAccessor, then the connection is transactional (DataSourceUtils.isConnectionTransactional(c, dataSource) == true). This is useless to me though, because the transaction commits as soon as the method is completed. When I use #Trasnactional on a method that calls a method in DataAccessor, the connection aquired in DataAccessor (from DataSourceUtils.getConnection(dataSource)) is NOT transactional. Additionally, I put a breakpoint in DataSourceTransactionManager.doGetTransaction(), and this is only called if the #Transactional annotation is directly on the method acquiring the connection. Forgive me for overloading the terminology, but it appears that the #Transactional annotation does not propagate up the stack.
I'm completely baffled. Please help! :)

I just about gave up on this one. It was quite non-obvious. Your problem is caused by using the EndOfDayProcess class in your entry point. It's a problem because it causes the class to be loaded, and more generally, it'll extend to any of your *Process and *EntryPoint classes. At that point in your code, Spring hasn't been started yet, so its load-time weaver isn't active, and the class gets loaded normally, without the transaction code woven into it. Of course, classes are only loaded once, so it's there to stay, and when you create the bean in Spring, it's a bean whose type doesn't have anything to do with transactions, except it has #Transactional annotations on it. By then, there's nobody there to see them anymore, though. I see two possible (good) solutions:
Switch to build-time weaving. Then it's impossible to load a class before it's woven.
Change the way you determine which *Process bean to use based on the entry point. Use anything you like except for something that causes the *Process class to be loaded.

Related

Understanding spring proxying

The Spring documentation provides the following example to show us the reason why we need to define aop:scoped-proxy explicitly in beans of scope session, reques, etc.
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
We need proxy here, because for each request to the userPreferences bean we want to delegate one to the actual session-scoped bean's instance. That's clear. But the documentation also said that this's a deafult behavior for singletone/prototype scoped beans.
Consider the following example:
<bean id="userPreferences" class="com.foo.UserPreferences" />
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
Why do we need in proxy in the case of singletone-scoped beans? Doesn't injecting and calling to proxy cause some performance overhead?
Question: For performance sakes, could we avoid injecting proxy and inject actual bean instances in the case of the singletone-scoped beans instead?

#Transactional in the controller

First of all I want to mention that I fully agree to only make the service layer transactional, but sometimes world is not perfect, and right now I´m in the middle of that situation.
Basically I have been assigned into a wonderful project with a legacy code of 4+ years. The thing is that the developers did not follow any pattern where to introduce the bussines logic so you can image multiples services call from the controller and after that some extra call to private method into the controller.
No budget to refactor, and we have many issues with ACID so the only solution that I found is make the controllers transactional and at least then have a full rollback if something in the middle of the request/response go wrong.
The problem is that I cannot make it works. I will describe you my configuration to see if you can help me out guys.
I have a DispatcherServlet that invoke webmvc-config.xml where I have the declaration of the controllers
<context:component-scan base-package="com.greenvalley.etendering.web.controller**" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
Then the contextConfiguration invoke my applicationContext.xml where I have all the rest of my Spring configuration.
After read so many tickets I tried many convination, for example try to declare again my controllers into the application context.
<tx:annotation-driven mode="aspectj"/> I tried with proxy as well
<context:component-scan base-package="com.greenvalley.etendering.web.controller.*" />
But still nothing.
In the configuration of my txManager I dont do nothing fancy, just add the reference to the entityManagerFactory and that´s it
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
In my controller I add the #Transactional, but nothing every time that I made a request to the #transactional class/method I dont see that the breakpoint into JpaTransactionalManager doBegin method stop
any suggestion please!
Regards

Nesting abstract beans in Spring and init-method does not seem to work

I have the following construct Spring XML (Spring 3.1):
<bean id="taskRunner" abstract="true" init-method="startThreads"
class="my.class.TaskRunner" />
...
<bean id="taskRunnerA" parent="taskRunner">
<constructor-arg name="foo">...</constructor-arg>
<property name="bar">...</property>
</bean>
And I am trying to separate out the init method into a higher level abstract bean:
<bean id="taskRunnerLauncher" abstract="true" init-method="startThreads" />
<bean id="taskRunner" abstract="true" depends-on="taskRunnerLauncher"
class="my.class.TaskRunner" />
...
<bean id="taskRunnerA" parent="taskRunner">
<constructor-arg name="foo">...</constructor-arg>
<property name="bar">...</property>
</bean>
Somehow this does not work, i.e. startThreads() is never invoked in the second case. Does anybody know why? Does Spring support nested abstract beans?
My idea for doing this is so I can override "taskRunnerLauncher" in unit tests and set it to "mock" or "java.lang.Object" and suppress startThreads() call (which starts new thread and making it a pain to test).
Does anybody know why?
The taskRunnerLauncher bean is set to be abstract. This means it will only act as a template for other beans. Spring will not actually create a bean for it. Therefore there won't be any invocation of startThreads because there is nothing to invoke it on.
Found the problem. I mistakenly used depends-on instead of parent attribute on taskRunner bean.

Spring MVC: disable DefaultAnnotationHandlerMapping

I'm using Spring MVC with <mvc:annotation-driven />
I've implemented my own mapping handler extending DefaultAnnotationHandlerMapping, but I'm not sure how to use it. I've declared it like this:
<bean class="es.kcsolutions.boulevard.DispatcherMappingHandler" />
It works, but, obviously, DefaultAnnotationHandlerMapping works too and always before mine. Is there a way to disable it and use only mine?
Thanks.
My advice would be to remove the <mvc:annotation-driven /> altogether. It doesn't really do anything particularly useful - most of the beans it declares are there already. And in cases where you want to declare your own handler mapping or handler adapter, it just gets in the way.
So take it out, declare your own DefaultAnnotationHandlerMapping bean, and it should work. No need to mess about with ordering in 99.9% of cases.
If you take out any explicit declarations of the DefaultAnnotationHandlerMapping then your custom mapper is supposed to replace it in the dispatcher. (according to javadoc) If you need/want more than one mapping, then you control them by setting their Order property. Lower order numbers execute first.
<bean class="es.kcsolutions.boulevard.DispatcherMappingHandler">
<property name="order" value="0"/>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="order" value="1"/>
</bean>

problem in Spring session scope bean with AOP

I want to inject currentUser instance in HomeController class. so for every request, HomeController will have currentUser object.
My configuration:
<bean id="homeController" class="com.xxxxx.actions.HomeController">
<property name="serviceExecutor" ref="serviceExecutorApi"/>
<property name="currentUser" ref="currentUser"/>
</bean>
<bean id="userProviderFactoryBean" class="com.xxxxx.UserProvider">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="currentUser" factory-bean="userProviderFactoryBean" scope="session">
<aop:scoped-proxy/>
</bean>
But I am getting following error.
Caused by: java.lang.IllegalStateException: Cannot create scoped proxy for bean 'scopedTarget.currentUser': Target type could not be determined at the time of proxy creation.
at org.springframework.aop.scope.ScopedProxyFactoryBean.setBeanFactory(ScopedProxyFactoryBean.java:94)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1350)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:540)
What is the problem? and Is there any better/simple alternative?
Cheers.
With scoped-proxies, Spring still needs to know the type of the bean when the context is initialized, and in this case it's failing to do so. You need to try and give it more information.
I notice that you're only specifying factory-bean in your definition of currentUser, with no factory-method specified. I'm actually rather surprised that that's a valid definition, since the two are normally used together. So try adding the factory-method attribute to currentUser, which specifies the method on userProviderFactoryBean which creates the user bean. That method needs to have a return type of your User class, which Spring will use to infer the type of currentUser.
Edit: OK, after your comment below, it seems you've misunderstood how to use factory beans in Spring. When you have a bean of type FactoryBean, you don't need to use the factory-bean attribute as well. So instead of this:
<bean id="userProviderFactoryBean" class="com.xxxxx.UserProvider">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="currentUser" factory-bean="userProviderFactoryBean" scope="session">
<aop:scoped-proxy/>
</bean>
You just need this:
<bean id="currentUser" class="com.xxxxx.UserProvider" scope="session">
<aop:scoped-proxy/>
<property name="userDao" ref="userDao"/>
</bean>
Here, UserProvider is a FactoryBean, and Spring knows how to handle that. The end result will be that the currentUser bean will be whatever UserProvider generates, rather than an instance of UserProvider itself.
The factory-bean attribute is used when the factory is not a FactoryBean implementation, but just a POJO, and it allows you to tell Spring explicitly how to use the factory. But because you're using FactoryBean, there's no need for this attribute.

Categories

Resources