I've got some trouble while configuring spring transaction manager. The application I'm working on has a layered architecture. Therefore it has a service layer containing all the transactional services. I wanted for spring to rollback the transaction when a checked (application specific) exception has occurred. I succeeded doing that by annotation as follows:
#Transactional(value="transactionDds", rollbackfor="Throwable")
This works fine. But since I've so many services hence I want to move this configuration to XML (spring DAO context file). This is what I've done:
<tx:advice id="txAdvice" transaction-manager="transactionManagerDds">
<tx:attributes>
<tx:method name="*" read-only="false" propagation="REQUIRED" rollback-for="Throwable"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="transRollbackOp" expression="execution(*fr.def.iss.ult.moduleManagement.service.dds.*.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="transRollbackOp"/>
</aop:config>
<bean id="transactionManagerDds" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="beanDataSourceFactory" />
<qualifier value="transactionDds"/>
</bean>
So basically, I'va a transaction manager which is associated to an advice which rolls back for the possible methods when a Throwable exception occurs. And this advice is linked to an AOP config that way we specify all the interfaces in the service layer of application on which this transaction configuration is to be applied. But this doesn't work. Transaction doesn't roll back Throwable exception occurs. I don't understand that this works with annotation but not with declarative configuration in XML.
I'm really looking forward for your suggestions. I'm totally blocked. Plz help me out. Thanx in advance.
<aop:config>
<aop:pointcut id="transRollbackOp" expression="execution(*fr.def.iss.ult.moduleManagement.service.dds.*.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="transRollbackOp"/>
</aop:config>
In your <aop:config /> the expression you entered is invalid. It should at least contain a whitespace between * and fr.def.
Next instead of .*.*.* I suggest writing ..*.* which selects all classes in all subpackages regardless of depth.
In short change your expression to execution(* fr.def.iss.ult.moduleManagement.service.dds..*.*(..)) should make it work.
Related
I am using spring jpa. I have implemented transaction management using
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'find' are read-only -->
<tx:method name="find*" read-only="true" />
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="transactionalServiceOperation"
expression="execution(* com.test..*ServiceImpl.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="transactionalServiceOperation" />
</aop:config>
Recently i noticed that although in some cases transaction management is working but in other cases it is not. For example , i have this piece of code inside a service method which is annotated by #org.springframework.transaction.annotation.Transactional.
The code inside the method
guardianService.save(newFather);
parentsSet.add(newFather);
Guardian oldMother = guardianService.findById(motherId);
In the above case the data in the database does not persis till the 3rd line. As soon as the application finishes executing the 3rd line the data of newFather gets comited to the database even if the application generates Exception after the 3rd line.
Code snippet of guardianService.findById(motherId)
#Override
public Guardian findById(long guardianId) {
return guardianRepository.findByGuardianId(guardianId);
}
Inside GuardianRepository
public interface GuardianRepository extends JpaRepository<Guardian, Long> {
Guardian findByGuardianId(long id);
}
Code snippet of guardianService.save(newFather);
#Override
#Transactional
public Guardian save(Guardian guardian) {
return guardianRepository.save(guardian);
}
So my question is does the find() method somehow calls the flush() or commit()?
The find() method actually does invoke the flush method. By default in JPA, FlushModeType is set to AUTO, which means that if query to database occurs, the data in database has to be up to date for current transaction. From definition:
When queries are executed within a transaction, if FlushModeType.AUTO
is set on the Query object, or if the flush mode setting for the
persistence context is AUTO (the default) and a flush mode setting has
not been specified for the Query object, the persistence provider is
responsible for ensuring that all updates to the state of all entities
in the persistence context which could potentially affect the result
of the query are visible to the processing of the query.
we are using Spring and hibernate in our project and i have noticed that we have defined <tx:annotation-driven /> in sprint context file and if i put #Transactionalannotation for method i am successfully able to interact with database but if i remove #Transactional annotation from method i am getting exception stating that "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here"
is there any way by which i can define all the select operation as non Transactional(i mean without #Transactional annotation) and update and insert as Transactional
Using #Transactional(readOnly=true) is usually the best thing for select-only operations. Using hibernate in auto-commit mode can be wasteful when multiple select statements are needed to complete an operation.
I am able to resolve this issue by using below code in context xml file.
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="allServiceMethods" expression="execution(* com.test.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="allServiceMethods"/>
</aop:config>
As by default read-only="false" for #Transactional annotation.
So we need to make it as read-only="true" for all read operation(Thanks Affe for pointer)
to set read-only="true" for all select select operation make sure that you start your method name from get and rest below code will code for us. you can change your below configuration as per your need.
<tx:method name="get*" read-only="true"/>
For more information you can refer to below link
Spring Docs
I have "inherited" an old legacy Spring application. Currently it is using Spring 2.5 (just upgraded it once), and am looking to further upgrade it to Spring 3.
I understand most of the application configuration. There is just one part that I am "not 100%" about. I can guess roughly what it might mean but I need to be absolutely sure hence posting this question:
Here is the configuration snippet (depends on an annotation driven transaction manager not shown here):
<aop:config>
<aop:advisor pointcut="execution(* *..ProductManager.*(..))"
advice-ref="txAdvice" />
</aop:config>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="save*" />
<tx:method name="*" read-only="false" />
</tx:attributes>
</tx:advice>
My specific two questions are:
What does "execution(* ..ProductManager.(..))" mean (I understand pointcut parlance)
In the attributes section of the advice we are saying apply transaction to all save* related methods, and for everything read-only is false. Can anyone explain why that setting makes sense? Is it additive and effectively saying, for all methods with transaction support (ie. just save* methods) I also want those methods to NOT be read-only transactions. Or is it applying something different (ie. some form of transaction support) to every method of inclusive transacion filter (defined in pointcut).
Thanks for any clarifications. Please, no general answers - I need a concrete explanation for this.
As tx:method has attribute read-only with default value as false, means transaction is read/write.
So in my opinion,
<tx:method name="save*" read-only="false" />
<tx:method name="*" />
is equivalent to
<tx:method name="*" />
execution(* *..ProductManager.*(..)) means that, "for all the methods in the ProductManager class"
tx:advice settings are not additive.
It says that for all methods beginning with save use the default transaction settings.
For the others, this setting means they are NOT read-only transactions.
For the common sense, one would expect
<tx:method name="save*" read-only="false" />
<tx:method name="*" />
I have AOP based loggin functionality with the following settings
Context xml configuration:
<bean id="performanceMonitor"
class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor" />
<aop:config>
<aop:pointcut id="allServiceMethods"
expression="execution(* com.eshop.sfweb.service.impl..*(..))" />
<aop:pointcut id="allEpServices"
expression="execution(* com.service.catalog..*(..))" />
<aop:advisor pointcut-ref="allServiceMethods"
advice-ref="performanceMonitor" order="2" />
<aop:advisor pointcut-ref="allEpServices"
advice-ref="performanceMonitor" order="2" />
</aop:config>
Log4j properties:
log4j.logger.org.springframework.aop.interceptor.PerformanceMonitorIntercept
or=${ep.perflog.level},PERFORMANCE
log4j.appender.PERFORMANCE.File=webAppRoot:WEB-INF/log/performance.log
log4j.appender.PERFORMANCE.threshold=DEBUG
log4j.appender.PERFORMANCE=org.apache.log4j.DailyRollingFileAppender
log4j.appender.PERFORMANCE.DatePattern='.'yyyy-MM-dd
log4j.appender.PERFORMANCE.layout=org.apache.log4j.PatternLayout
log4j.appender.PERFORMANCE.layout.ConversionPattern=%d -- %-5p [%t | %F:%L]
-- %m%n
Is there any way that I can disable the AOP invocations itself depending upon the enviroment?
I can disable the logging very easily but can I disable/enable the entire background process and invocations?
Please let if any clarifications are required.
Since you are using Spring AOP, one quick way to enable or disable aspects could be to simply use Bean profiles.
Define a profile say enableAOP:
Wrap the aop:config in say a configuration file under the specific profile
<beans profile="enableAOP">
<aop:config> <aop:pointcut id="allServiceMethods"
expression="execution(* com.eshop.sfweb.service.impl..*(..))" />
<aop:pointcut id="allEpServices" expression="execution(*
com.service.catalog..*(..))" />
....
</beans>
Now, whichever environment you want the specific aspects enabled, just run with enableAOP profile on.
it's been a while since this question was asked, but here is what I came up with for Spring 2:
Create an empty xml file (aop-context-off.xml) with an empty <beans> declaration.
Then create for example an aop-context-enabled.xml file with your AOP declaration.
Finally when importing the XML you could use :
<import resource="aop-context-${AOP_CONTEXT_SUFFIX:off}.xml" />
This will look for a system variable called AOP_CONTEXT_SUFFIX and if not found force the value to off.
So in the example above, by setting AOP_CONTEXT_SUFFIX to enabled it will load the aop-context-enabled.xml
So the switch being the system variable, you can easily Enable/Disable it at server start.
<tx:advice id="txAdvice" transaction-manager="jtaTxManager">
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<aop:pointcut id="fooServiceOperation"
expression="execution(* x.y.SampClass.save(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation" />
</aop:config>
<bean id="Samp1" class=" x.y.SampClass"></bean>
<bean id="SearchDispatchRpcGwtServlet" class="x.y.server.SearchDispatchRpcGwtServlet">
<constructor-arg>
<list>
<ref bean="webServiceClient"/>
</list>
</constructor-arg>
</bean>
<!-- Service Clients -->
<bean id="webServiceClient" class="x.y.KSBClientProxyFactoryBean">
<property name="serviceEndpointInterface" value="x.y.service.WebService" />
<property name="serviceQName" value="{http://x.y.org/wsdl/organization}WebService" />
</bean>
This is the part of sample spring context file. I am trying to create a transaction advice for SampClass to execute on the save method.
So from my understanding it should create a proxy for SampClass only.
I have a SearchDispatchRpcGwtServlet which takes as an argument a webservice Client which is also a proxy in itself. This bean is also getting proxied for some reason where it fails because it cannot create a proxy of a proxy.
I must add that SearchDispatchRpcGwtServlet creates an instance of SampClass and calls the save method.
I get the following exception:
java.lang.IllegalArgumentException:
Cannot subclass final class class
$Proxy118 at
net.sf.cglib.proxy.Enhancer.generateClass(Enhancer
.java:446) at
net.sf.cglib.transform.TransformingClassGenerator.
generateClass(TransformingClassGenerator.java:33)
I dont understand why SearchDispatchRpcGwtServlet proxy is getting created. Can someone explain.
Addition Stack Trace
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class $Proxy117]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy117
at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:213)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:473)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:348)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:309)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:361)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1427)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport$1.run(FactoryBeanRegistrySupport.java:139)
... 85 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy117
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
at net.sf.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:201)
a subclass of AbstractAutoProxyCreator is trying to proxy a bean, but that bean is already itself a CGLIB proxy created using another mechanism such as aop:config proxy-target-class="true.
To avoid this, make sure to avoid mixing the different aspect weaving mechanisms (ProxyBeanFactory and aop:config ) for the same bean.
In this case the transaction aspects can also be weaved via <tx:annotation:driven/> via the #Transactional annotation.
Alternatively it would be possible to remove the autowiring/scan from the bean and do the injection of dependencies via XML using setters.
Another alternative is to use load time weaving everywhere by declaring <context:load-time-weaver/> and adding the needed jars.
Have a look also at this post, it general it would be better to use only one one way of applying the aspects in the whole application, in order to avoid this problem.