使用AspectJ

时间:2015-06-16 12:35:16

标签: java spring neo4j aspectj spring-data-neo4j

使用AspectJ,Neo4j NodeEntities和事务时,我遇到了一个奇怪的问题。

我正在开发一个spring应用程序并使用spring-data-neo4j和aspectj编织。问题是,我获取的实体在事务之外是空的。没有AspectJ,一切都按预期工作。

以下是maven的完整测试用例:

的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.test</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.4.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
        <neo4j.version>2.1.7</neo4j.version>
        <spring-data-commons.version>1.10.0.RELEASE</spring-data-commons.version>
        <spring-data-neo4j.version>3.3.0.RELEASE</spring-data-neo4j.version>
    </properties>

    <dependencies>
        <!-- spring dependencies -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-commons</artifactId>
            <version>${spring-data-commons.version}</version>
        </dependency>

        <!-- spring + neo4j dependencies -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-neo4j</artifactId>
            <version>${spring-data-neo4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-neo4j-tx</artifactId>
            <version>${spring-data-neo4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-neo4j-aspects</artifactId>
            <version>${spring-data-neo4j.version}</version>
        </dependency>

        <!-- for aspectj -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>persistence-api</artifactId>
            <version>1.0</version>
            <optional>true</optional>
            <scope>provided</scope>
        </dependency>

        <!-- for testing -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.neo4j</groupId>
            <artifactId>neo4j-kernel</artifactId>
            <version>${neo4j.version}</version>
            <type>test-jar</type>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <id>aspects</id>
            <build>
                <plugins>
                    <!-- disable default compiler -->
                    <plugin>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <executions>
                            <execution>
                                <id>default-compile</id>
                                <phase>none</phase>
                            </execution>
                        </executions>
                    </plugin>
                    <!-- enable aspectj compiler -->
                    <plugin>
                        <groupId>org.codehaus.mojo</groupId>
                        <artifactId>aspectj-maven-plugin</artifactId>
                        <version>1.7</version>
                        <dependencies>
                            <dependency>
                                <groupId>org.aspectj</groupId>
                                <artifactId>aspectjrt</artifactId>
                                <version>1.8.5</version>
                            </dependency>
                            <dependency>
                                <groupId>org.aspectj</groupId>
                                <artifactId>aspectjtools</artifactId>
                                <version>1.8.5</version>
                            </dependency>
                        </dependencies>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>compile</goal>
                                    <goal>test-compile</goal>
                                </goals>
                            </execution>
                        </executions>
                        <configuration>
                            <outxml>true</outxml>
                            <aspectLibraries>
                                <aspectLibrary>
                                    <groupId>org.springframework</groupId>
                                    <artifactId>spring-aspects</artifactId>
                                </aspectLibrary>
                                <aspectLibrary>
                                    <groupId>org.springframework.data</groupId>
                                    <artifactId>spring-data-neo4j-aspects</artifactId>
                                </aspectLibrary>
                            </aspectLibraries>
                            <complianceLevel>${java.version}</complianceLevel>
                            <source>${java.version}</source>
                            <target>${java.version}</target>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

    <repositories>
        <repository>
            <id>spring-libs-milestone</id>
            <name>Spring Milestone</name>
            <url>https://repo.spring.io/libs-milestone</url>
        </repository>
    </repositories>
</project>

演示/ DemoNode.java

package demo;

import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.Indexed;
import org.springframework.data.neo4j.annotation.NodeEntity;

@NodeEntity
public class DemoNode {
    @GraphId
    private Long id;

    @Indexed(unique = true)
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

演示/ DemoRepository.java

package demo;

import org.springframework.data.neo4j.repository.GraphRepository;

public interface DemoRepository extends GraphRepository<DemoNode> {
    public DemoNode findByName(String name);
}

演示/ DemoApplicationTests.java

package demo;

import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Transaction;
import org.neo4j.test.TestGraphDatabaseFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.aspects.config.Neo4jAspectConfiguration;
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.support.node.Neo4jHelper;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class DemoApplicationTests {
    @Configuration
    @ComponentScan("demo")
    @EnableTransactionManagement
    @EnableNeo4jRepositories(basePackages = "demo")
    public static class DemoConfiguration extends Neo4jAspectConfiguration {
        public DemoConfiguration() {
            setBasePackage("demo");
        }

        @Bean(destroyMethod = "shutdown")
        public GraphDatabaseService graphDatabaseService() {
            return new TestGraphDatabaseFactory().newImpermanentDatabase();
        }
    }

    @Autowired
    private GraphDatabaseService graphDbService;

    @Autowired
    private DemoRepository demoRepo;

    @Before
    public void resetDb() {
        Neo4jHelper.cleanDb(graphDbService);
    }

    // NOT successful
    @Test
    public void testNeo4jTransaction() {
        DemoNode node;
        final String name = "demo";

        try (Transaction tx = graphDbService.beginTx()) {
            node = new DemoNode();
            node.setName(name);

            node = demoRepo.save(node);
            tx.success();
        }
        assertEquals(name, node.getName());

        try (Transaction tx = graphDbService.beginTx()) {
            node = demoRepo.findByName(name);

            tx.success();
        }

        assertEquals(name, node.getName()); // expected:<demo> but was:<null>
    }

    // successful
    @Test
    public void testNeo4jWithGetTransaction() {
        DemoNode node;
        final String name = "demo";

        try (Transaction tx = graphDbService.beginTx()) {
            node = new DemoNode();
            node.setName(name);

            node = demoRepo.save(node);
            tx.success();
        }
        assertEquals(name, node.getName());

        try (Transaction tx = graphDbService.beginTx()) {
            node = demoRepo.findByName(name);

            tx.success();
        }

        try (Transaction tx = graphDbService.beginTx()) {
            assertEquals(name, node.getName());
        }
    }
}

使用mvn test测试时,一切都很好。但是当使用aspectj(mvn test -Paspects)时,它将失败: DemoApplicationTests.testNeo4jNativeTransaction:64 expected:<demo> but was:<null>

我在调试时发现:在使用AspectJ的事务中,我可以使用getter检索名称。但是:所有属性始终为null。所以我的猜测是:AspectJ weaving将值存储在其他地方并覆盖setter / getter。新的getter需要一个活动的事务,因此在事务之外它将不起作用/将使用不与null属性一起使用的默认getter。

当我提高调试级别时,我可以看到一些关于此的消息: DEBUG o.s.d.n.f.DetachedEntityState - Outside of transaction, GET value from field class java.lang.String name rel: false idx: true

我做错了吗?我需要创建一个克隆并返回吗? Imho这将是一个丑陋的方式......

提前致谢!我已经搜索并尝试了几个小时,但无法在stackoverflow或互联网上的其他地方找到任何解决方案和任何其他问题。也许这是一个错误......也许是预期的行为,或者我做错了......我不知道。

更新

我添加了第二个有效的测试。它有一个围绕getter的事务。因此,当在事务中调用getter时,一切都很好。但我认为这是一种奇怪的行为。在交易之外,实体应该分离,但可以使用。

0 个答案:

没有答案