Spring / @Transactional with AspectJ is totally ignored

aspectj, java, spring, spring-data, spring-data-neo4j

Solution

Try adding `<context:load-time-weaver/>` to enable load time weaving and add the spring-aspects.jar to the classpath.

See http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html#aop-aj-ltw-spring for more info

Edit

For generic java applications, ie not running in a web or application container, you need to enable the java instrumentatioin via a javaagent option:

java -javaagent:path/to/spring-instrument.jar your.Main

If you want to weaving your own aspects, you need to provide a META-INF/aop.xml file with aspect declarations. (Not requiered for spring only aspects, it's already provided on spring-aspect.jar).

Finally you can use compile time weaving instead, using the maven aspectj plugin, for example:

<plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <configuration>
                <complianceLevel>1.6</complianceLevel>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

Problem

I use Spring-Data Neo4j 2.2.0-RELEASE. (my following issue would be applicable to any other kind of entity mapping, why not JPA) In my project, I have a public method annotated with `@Transactional` Spring's annotation, since I want to update/save an entity inside it: ``` public class MeetingServices { private UserRepository userRepository; private MeetingRepository meetingRepository; public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } public void setMeetingRepository(MeetingRepository meetingRepository) { this.meetingRepository = meetingRepository; } @Transactional("neo4jTransactionManager") public void save(Meeting meeting) { User creator = userRepository.getUserByEmail("test@test.com"); creator.participateIn(meeting); // this line leads to a NotInTransactionException since it signals that no transaction context is associated. meeting.setCreator(creator); } ``` My application-context.xml is the following: ``` <?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:neo4j="http://www.springframework.org/schema/data/neo4j" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <bean id="graphDatabaseService" class="org.neo4j.kernel.EmbeddedGraphDatabase"> <constructor-arg value="target/neo4jgraph" /> </bean> <neo4j:config graphDatabaseService="graphDatabaseService" /> <bean id="meetingServices" class="services.MeetingServices"> <property name="userRepository"><ref bean="userRepository"/></property> <property name="meetingRepository"><ref bean="meetingRepository"/></property> </bean> <bean id="userServices" class="services.UserServices"> <property name="userRepository"><ref bean="userRepository"/></property> </bean> <bean id="neo4jTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager"> <bean class="org.neo4j.kernel.impl.transaction.SpringTransactionManager"> <constructor-arg ref="graphDatabaseService" /> </bean> </property> <property name="userTransaction"> <bean class="org.neo4j.kernel.impl.transaction.UserTransactionImpl"> <constructor-arg ref="graphDatabaseService" /> </bean> </property> </bean> <tx:annotation-driven mode="aspectj" transaction-manager="neo4jTransactionManager" /> <!-- auto-generated repositories for Neo4j storage --> <neo4j:repositories base-package="repositories"/> <context:spring-configured/> <context:annotation-config/> </beans> ``` As we see in this configuration, aspectJ is used for transactions. So, I tried to test another way of doing by changing my application-context.xml to use the `proxy` feature instead of `aspectJ` feature: ``` <?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:neo4j="http://www.springframework.org/schema/data/neo4j" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <bean id="graphDatabaseService" class="org.neo4j.kernel.EmbeddedGraphDatabase"> <constructor-arg value="target/neo4jgraph" /> </bean> <neo4j:config graphDatabaseService="graphDatabaseService" /> <bean id="meetingServices" class="services.MeetingServices"> <property name="userRepository"><ref bean="userRepository"/></property> <property name="meetingRepository"><ref bean="meetingRepository"/></property> </bean> <bean id="userServices" class="services.UserServices"> <property name="userRepository"><ref bean="userRepository"/></property> </bean> <tx:annotation-driven mode="proxy" /> <neo4j:repositories base-package="repositories"/> <context:spring-configured/> <context:annotation-config/> </beans> ``` This configuration works pretty well since `@Transactional` (whose `neo4jTransactionManager` parameter was of course removed) annotation is now taken in account for my service's method. My question is, (no matter whether my project would work with simple `proxy` method): What did I miss or misconfigure in my first Spring's configuration that makes aspectJ transaction features failed? I'm currently improving my technical skills with Spring, and read few articles about "Load-time weaving" for aspectJ. Might this be linked to my issue?

Original source

Related problems