in "applicationContext-base.xml" I add below:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
>
.....
<!-- transaction support-->
<!-- PlatformTransactionMnager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- enable transaction annotation support -->
<tx:annotation-driven transaction-manager="txManager" />
and I want to setup a transaction to a function in the "controller"
#Controller
#RequestMapping("/ywdata")
public class YwController extends BaseController{
....
#Transactional(timeout=1)
private void submitNewSXSQ(Map map, HttpServletRequest request, HttpServletResponse response) throws Exception {
...//STEP1 :do some db insert and update STEP1
if(true)
throw new Exception("test transaction ");
...//STEP2: do another db insert and update
and I expected the db operation should never be commit since I throw a exception before return. but actually not.
There are multiple issues with your code:
#Transactional on private methods don't work
#Transactional on #Controller annotated classes usually don't work
rollback is not performed for checked exceptions
The last issue can be easily understood. Let me explain the first two problems. AOP in Spring works like this:
before the application context is initialized, Spring searches for beans which require method interception
a special proxy bean is registered for each of these beans... the proxy is either dynamic interface implementation (JDK proxy) or a dynamic subclass (CGLIB proxy) of your target bean
the proxy replaces the definition of your bean... original definition is renamed and marked as not eligible for autowiring (but it is still present on application context)
the methods on proxy are very dumb - all they do is interception logic (i.e. calling some aspect before/after/around execution) and calling the original proxied target bean method
Why private methods are problem:
with JDK proxying (default):
#Transactional won't work if you have #Transactional on non-interface method (only interface methods are present on the proxy)
with CGLIB proxying:
##Transactional won't work if you have #Transactional on private or final method (only non-private and non-final methods can be overridden in dynamic subclass)
And why controllers are problem:
Spring's RequestMappingHandlerMapping (bean responsible for mapping requests to your #Controllers) asks application context to get all beans with #Controller annotation
this might return your original class, not the proxy (I think there was a bug for this in Spring JIRA, so it might be already fixed)
in case of JDK proxying, you need to add the annotation to the interface (so that the proxy is annotated)... this means that you would need to define interfaces for your controllers
What to do:
I suggest you to move transaction handling to service level
If you want your transaction to be wrapped around the whole request, you might take your inspiration from OpenSessionInViewFilter.
Also I encourage you to put breakpoint in your code and check the stack trace and look for the AOP proxy.
If you still want to manually handle transactions in some random part of code, you can use TransactionTemplate helper class.
From Spring documentation, it is the default behavior: Transactions are marked for rollback only for unchecked exceptions.
See section 10.5.3 of doc
Related
To work via annotations in Spring need to define:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
xmlns:context="http://www.springframework.org/schema/context">
<context:annotation-config/>
</beans>
at
annotation-config.xml
But I created a simplest Spring boot Application (lets say I select lust Web in initialazr)
It works on annotations but there isn't any annotation-config.xml there and nor mentioning of ,
where is hidden?
You only need to add <context:annotation-config /> or <context:component-scan /> (which implies annotation driven config) when using an ApplicationContext implementation that doesn't support annotations out-of-the-box.
When only using XML based configuration you also use one of the XML enabled ApplicationContext implementations, generally that would be XmlWebApplicationContext. With these you would need to instruct the ApplicationContext to enable annotation processing.
When using Java based configuration you generally use an annotation based ApplicationContext, default would be AnnotationConfigWebApplicationContext. Due to its nature of processing Java configuration classes it has annotation processing enabled by default.
Spring Boot uses the latter (it actually uses a specialized subclass for this). Hence you don't need to explicitly enable it.
I found some code in my project.By seeing that i am confused how it scanning the package.we are not mentioning aspect package com.abc.b any where.I have few question
Why aop:aspectj-autoproxy is commentout in xml file?
why is used ?
How com.abc.b package is scanned by spring or there is no need of it or It has link from 'factory-method="aspectOf"'
serviceContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cxf="http://cxf.apache.org/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd" default-lazy-init="true">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!-- <aop:aspectj-autoproxy /> -->
<!-- Enable message logging using the CXF logging feature -->
<cxf:bus>
<!-- <cxf:features>
<cxf:logging/>
</cxf:features> -->
<cxf:inFaultInterceptors>
<bean class="com.flipswap.interceptor.cxf.SafeLoggingInFaultInterceptor"/>
</cxf:inFaultInterceptors>
</cxf:bus>
<context:component-scan base-package="com.abc.service.impl,">
<context:exclude-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>
<bean id="eSSyncAspect" class="com.abc.b.ES" factory-method="aspectOf"/>
.
.
.
ES.java
package com.abc.b;
#Aspect
public class ES{
// some code
}
Unless you specify a custom instantiation model, aspects are by default singletons. That means - in case your code is properly woven -, that you can access the singleton instance of the aspect with AspectName.aspectOf().
In order for your classes to be woven by the AspectJ weaver, you need to either use compile-time/build-time weaving or load-time weaving.
In your spring configuration you are telling Spring to configure your aspect as a spring bean by telling how to access the singleton instance (through the static 'factory' method aspectOf). Spring will do the usual configuration (autowiring and any configured post-processors) on the singleton aspect instance.
aop:aspectj-autoproxy is commented out in your configuration because that would conflict with native aspectj support, as it would enable Spring AOP's dynamic proxy based AOP solution, which is very limited compared to native aspectj, and has a different mechanism to configure aspect beans than the one used in your configuration, namely through the static factory method AspectName.aspectOf().
In most cases, AspectJ aspects are singletons, with one instance per class loader. This single instance is responsible for advising multiple object instances.
A Spring IoC container cannot instantiate an aspect, as aspects don't have callable constructors. But it can obtain a reference to an aspect using the static aspectOf() method that AspectJ defines for all aspects, and it can inject dependencies into that aspect.
7.2.1.1. Example
Consider a security aspect, which depends on a security manager. This aspects applies to all changes in the value of the balance instance variable in the Account class. (We couldn't do this in the same way using Spring AOP.)
The AspectJ code for the aspect (one of the Spring/AspectJ samples), is shown below. Note that the dependency on the SecurityManager interface is expressed in a JavaBean property:
public aspect BalanceChangeSecurityAspect {
private SecurityManager securityManager;
public void setSecurityManager(SecurityManager securityManager) {
this.securityManager = securityManager;
}
private pointcut balanceChanged() :
set(int Account.balance);
before() : balanceChanged() {
this.securityManager.checkAuthorizedToModify();
}
We configure this aspect in the same way as an ordinary class. Note that the way in which we set the property reference is identical. Note that we must use the factory-method attribute to specify that we want the aspect "created" using the aspectOf() static method. In fact, this is locating, rather than, creating, the aspect, but the Spring container doesn't care:
<bean id="securityAspect"
class="org.springframework.samples.aspectj.bank.BalanceChangeSecurityAspect"
factory-method="aspectOf">
<property name="securityManager" ref="securityManager"/>
</bean>We don't need to do anything in Spring configuration to target this aspect. It contains the pointcut information in AspectJ code that controls where it applies. Thus it can apply even to objects not managed by the Spring IoC container.
We use Spring IoC and Struts as the web app framework. There is a helper class in the presentation layer which reads some stuff from request and populates some data as request attributes for the action and other classes to use. So we need the request object (HttpServletRequest) in this class, and we use ServletActionContext.getRequest() for this.
The helper class is a Spring bean in request scope, and gets invoked for all requests. The data loading happens in a method which is configured as "init-method" in the helper's Spring bean. The actions are also Spring beans.
In struts.xml, we refer to the action beans configured in spring by name. For eg:
<action name="myAction" class="actionBeanNameFromSpring">
<result>myResult.jsp</result>
</action>
In this case, the ServletActionContext.getRequest() method in the helper returns the proper request object. However, we have other actions in the XML where we directly refer to the action class instead of action bean i.e. we bypass Spring. In these cases, the request comes out as null.
Now I know that the solution to this is to change all action entries in XML to refer to Spring beans. But I would like to know why exactly this happens. AFAIK, ServletActionContext is a Struts thing and is handled completely by Struts. How does going through Spring (i.e. using Spring action beans) populate the context, and not going through Spring (i.e. using Action class name) doesn't?
#Roman
I am assuming the entire content is unnecessary. Given below is the relevant part:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
....
<!-- the helper which accesses request -->
<bean id="myActionHelper" class="com.company.product.webapp.package.MyActionHelper" init-method="init" scope="request">
<property name="someSvcBean" ref="someSvcBean" />
</bean>
....
<!-- a typical action -->
<bean id="myAction" class="com.company.product.webapp.action.MyAction" scope="request">
</bean>
....
</beans>
I am trying to do my first steps using spring, but I don't manage to get it working, I would appreciate your assistance.
I am using tomcat and I have added to tomcat lib directory a file: jdbc-service.xml:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:spring-configured />
<context:component-scan base-package="com.myproject"/>
<context:property-placeholder location="database.properties"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
I have a database.properties that defines several properties to be used to obtain DataSource object.
I also have a class that uses #Configuration and it takes the properties for the DB.
In addition i have another #Configuration class that inherits from the first one and added JdbcTemplate object each method is annotated #Bean.
I created an interface UserRepository and an implementation for this called UserRepositoryImpl - which has an annotated #Autowired member JdbcTemplate and implementation of only one method findById inherited from the interface UserRepository.
I have another interface called UserManager and it's implementation UserManagerImpl - which is annotated as #Service, it has a member UserRepository annotated with #Autowired.
it is implementing a method to findById and just tried to get the user from the DB using the UserRepository.
Last, I have a servlet that uses a member
#Autowired
private UserManager userManager;
the problem is that userManager is null. I think that the spring does not get initiated, but i don't know why. I am probably missing something important.
Please help me as I can't progress.
Thanks in advance.
Servlets are not Spring beans. They're instantiated by tomcat directly, and not by Spring. They are thus out of Spring's scope and can't be injected.
Consider using Spring MVC controllers instead of servlets.
Are you sure your UserManagerImpl is in package com.myproject which is specified as base package?
In your web.xml specify two context listeners but make sure the first listener is Spring's:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
I have an aspect working correctly in my unit tests, a log message is printed from the actual method, and afterwards from the aspect applied.
When running my webapp though, I only see the result of the '#afterReturning' advice applied, my method does not execute first.
My config:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:aspectj-autoproxy proxy-target-class="true" />
<bean id="loggingAspect" class="com.mypackage.MyAspect" />
</beans>
Any ideas ?
Thanks for your help.
Information you provided in not enough to analyze. So check below things in your web app,
1) Verify that the method you are expecting to be intercepted by your advice, belongs to spring bean class & not some other servlet or other class defined outside spring. If any class is not initialized through spring then aop advice can not be applied to that class.
2) Verify that above aop & advice configs are put in proper context xml for spring. Like in case of spring-mvc, you have to explicitely define the name of your application context xml. And in that application context xml only you have to write aop configurations.
3) Verify if your pointcut is appropriate to find exact class & method for advice.
See if these things are in place.