【问题标题】:Lazy Loading using Spring Data Neo4j 4 + AspectJ LTW running on Tomcat使用运行在 Tomcat 上的 Spring Data Neo4j 4 + AspectJ LTW 进行延迟加载
【发布时间】:2016-06-14 09:14:10
【问题描述】:

我尝试了所有可能性,试图让我的项目在 Tomcat 上运行,并使用 AspectJ Load Time Weaver 对模型(getter)进行切入和编织。 基本上,我遵循了 Spring 文档http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-atconfigurable 中的所有步骤。我也遵循Lazy/Eager loading/fetching in Neo4j/Spring-Data 提到的相同方法。 我的项目分为两个主要项目: - 核心:spring-data-neo4j(存储库和配置),专用包中的域模型,LoggingAspect 和 LazyLoadingAspect。 p.s.我没有在 XML 文件中使用任何配置。我纯粹使用注释。 - 内容:依赖于核心项目的Tomcat上运行的Web应用程序,当我在域项目中调用getter方法时我想编织。

运行核心本身我设法使用 maven 插件运行它并添加 aspectj 的依赖项。但是当我搬到Tomcat时,一切都开始了。我尝试了所有可能性,例如使用 -javaagent、创建自定义 context.xml、将 spring-instrument 放入 tomcat/lib 文件夹等。我收到以下异常:

java.lang.IllegalStateException:后处理器试图用 [org.springframework.beans.factory.aspectj.$ 类型的(代理)对象替换 [com.test.server.graph.domain.model.Sequence] 类型的 bean 实例Proxy96] - 不支持方面配置的类! 在 org.springframework.beans.factory.wiring.BeanConfigurerSupport.checkExposedObject(BeanConfigurerSupport.java:173) 在 org.springframework.beans.factory.wiring.BeanConfigurerSupport.configureBean(BeanConfigurerSupport.java:143) 在 org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect.configureBean(AnnotationBeanConfigurerAspect.aj:63) 在 org.springframework.beans.factory.aspectj.AbstractDependencyInjectionAspect.ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$2$1ea6722c(AbstractDependencyInjectionAspect.aj:88) 在 com.test.server.graph.domain.model.Sequence.(Sequence.java:29) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) 在 sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 在 java.lang.reflect.Constructor.newInstance(Constructor.java:422) 在 org.neo4j.ogm.annotations.EntityFactory.instantiate(EntityFactory.java:135) 在 org.neo4j.ogm.annotations.EntityFactory.instantiateObjectFromTaxa(EntityFactory.java:110) 在 org.neo4j.ogm.annotations.EntityFactory.newObject(EntityFactory.java:61) 在 org.neo4j.ogm.context.GraphEntityMapper.mapNodes(GraphEntityMapper.java:147) 在 org.neo4j.ogm.context.GraphEntityMapper.mapEntities(GraphEntityMapper.java:132) 在 org.neo4j.ogm.context.GraphEntityMapper.map(GraphEntityMapper.java:107) 在 org.neo4j.ogm.context.GraphEntityMapper.map(GraphEntityMapper.java:102) 在 org.neo4j.ogm.context.RestModelMapper.mapEntity(RestModelMapper.java:157) 在 org.neo4j.ogm.context.RestModelMapper.map(RestModelMapper.java:76) 在 org.neo4j.ogm.session.delegates.ExecuteQueriesDelegate.query(ExecuteQueriesDelegate.java:94) 在 org.neo4j.ogm.session.delegates.ExecuteQueriesDelegate.query(ExecuteQueriesDelegate.java:73) 在 org.neo4j.ogm.session.Neo4jSession.query(Neo4jSession.java:313) 在 org.springframework.data.neo4j.template.Neo4jTemplate.query(Neo4jTemplate.java:217) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:497) 在 org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302) 在 org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) 在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) 在 org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) 在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 在 org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) 在 com.sun.proxy.$Proxy58.query(未知来源)

pom.xml (core.project)

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-neo4j</artifactId>
        <version>${sdn.version}</version>
    </dependency>
    <dependency>
        <groupId>org.neo4j</groupId>
        <artifactId>neo4j-ogm-core</artifactId>
        <version>2.0.3-SNAPSHOT</version>
    </dependency>

我的配置类(核心项目)

@org.springframework.context.annotation.Configuration
@ComponentScan(basePackages = "org.test.server.graph")
@EnableNeo4jRepositories(basePackages = "org.test.server.graph.repository")
@EnableAspectJAutoProxy
@EnableSpringConfigured
public class Neo4jConfig extends Neo4jConfiguration { 
    @Bean
    public Configuration getConfiguration() {
        Configuration config = new Configuration();
        config.driverConfiguration().setDriverClassName("org.neo4j.ogm.drivers.http.driver.HttpDriver")
                .setURI(System.getProperty("neo4j.host")).setCredentials(System.getProperty("neo4j.user"),System.getProperty("neo4j.password"));
        return config;
    }

    @Bean
    public SessionFactory getSessionFactory() {
        return new SessionFactory(getConfiguration(), "org.test.server.graph.domain" );
    }

    @Bean
    @Scope(value = "prototype")
    public Session getSession() throws Exception {
        return super.getSession();
    }
}

领域模型类

按照 Spring 文档的建议,我在域模型中注释了类

@可配置

mvc-dispatcher-servlet(webapp 项目)

<context:spring-configured />
<context:load-time-weaver aspectj-weaving="on" weaver-class="org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver" />

我尝试使用 tomcat-maven-plugin 和 tomcat 独立安装(v7 和 v8)运行。

-- 更新--

Sequence.java

@NodeEntity
@Configurable
public class Sequence extends DatabaseObject {

    @Relationship(type = "hasModifiedResidue", direction = Relationship.OUTGOING)
    private List<AbstractModifiedResidue> hasModifiedResidue;

    @Relationship(type = "referenceEntity", direction = Relationship.OUTGOING)
    private ReferenceSequence referenceEntity;

    public Sequence() {}

   //getter and setters

}

DatabaseObject.java

@NodeEntity
@Configurable(
    preConstruction = false
)
public abstract class DatabaseObject implements Serializable, Comparable<DatabaseObject> {

    @GraphId
    private Long id;

    // other common attributes + getter and setters, no more annotation

LazyLoadingAspect

@Aspect
@Component
public class LazyFetchAspect {

    @Autowired
    private Neo4jOperations neo4jTemplate;

    @Around("modelGetter()")
    public Object autoFetch(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println(" Testing Aspect ");

        return pjp.proceed();
    }

    @Pointcut("execution(public * com.test.server.graph.domain.model.*.get*(..))")
    public void modelGetter() {
    }
}

【问题讨论】:

  • 我的猜测是,当您在 Tomcat 下运行时,AspectJ 加载时编织不起作用。我认为您应该验证加载时编织确实生效并修复您的配置,直到它生效。您还可以考虑使用编译时编织(您可以使用 maven 来完成,也可以让 Eclipse 使用 AspectJ 编译器)。我使用 @Configurable 和编译时编织取得了巨大的成功。尝试使用 -javaagent vm 参数运行 Tomcat JVM。
  • 另外,您应该为 AspectJ 加载时编织器启用调试日志记录,这样您就可以实际看到它在做什么。有关如何执行此操作的详细信息,请参阅我的answer 关于一个无关问题的详细信息。
  • @NándorElődFekete。核心项目本身正在运行,执行时我可以看到输出“Testing Aspect”。您需要考虑两件事,我正在运行 IntelliJ,这应该不是问题,并且我正在使用 -javaagent 运行 tomcat。我将启用调试日志记录并提出更新。干杯。
  • 我猜您在不在 Tomcat 下运行项目时会看到“Testing Aspect”消息。这很好,但这并不意味着 LTW 在 Tomcat 下工作。也许尝试从&lt;context:load-time-weaver&gt; 配置标签中删除weaver-class="org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver" 属性。
  • @NándorElődFekete。这就是我在这里发布后尝试的!希望它现在正在工作。我会想出一个更干净的版本并在这里发布解决方案。

标签: tomcat lazy-loading aspectj spring-data-neo4j


【解决方案1】:

主要问题似乎是您将方面应用于 bean:

Post-processor tried to replace bean instance of type [com.test.server.graph.domain.model.Sequence] with (proxy) object of type [org.springframework.beans.factory.aspectj.$Proxy96] - not supported for aspect-configured classes!

这不起作用,因此您必须确保您的模型类是真正的 POJO 而不是 bean,并将它们从 spring 中排除。 (确保在 domain.model.* 中没有 spring 注释)-也许如果您发布您的 Sequence.java 我可以看到可能导致冲突的原因。

另一方面,您必须确保仅将 aspectj 分配给模型而不是任何 bean。因此,请确保您有一个仅包含您的 pojo 模型的 /META-INF/aop.xml:

<!DOCTYPE aspectj PUBLIC
        "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
    <aspectj>
        <weaver>
            <!-- only weave classes in our application-specific packages -->
            <include within="com.test.server.graph.domain.model.*" />
        </weaver>
        <aspects>
            <!-- weave in just this aspect -->
            <aspect name="my.util.aspects.Neo4jFetchAspect" />
        </aspects>
    </aspectj>

我的 pom.xml 的一部分(我现在有不同的设置 - 这就是为什么 spring 版本这么旧):

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.6.12</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.6.12</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>3.1.1.RELEASE</version>
    </dependency>

我没有任何特殊的构建插件或类似的东西

【讨论】:

  • 感谢您的回复。我在主要问题中添加了类作为更新。上面的 @Configurable 是因为 Spring Documentation 说的。该模型具有 Neo4j 注释(SDN4),我想 LTW 以应用 LazyLoading。我的 graphDB 的深度真的很大,如果我为给定的实体获取它们,它将永远持续下去。
  • @Guilherme 这可能是可配置的问题。我很确定你不能把它混在一起。当您删除注释并确保 spring 没有到达此类时会发生什么?
  • 我得到 NoSuchMethodError。您的 pom.xml 中的依赖项是什么?或者你使用什么样的配置?
  • 感谢你们在这里的所有帮助。我把这归功于你。
  • @Guilherme 谢谢,很高兴我们能提供帮助 - 你能更新你的问题,说明实际的解决方案/问题是什么 - 以防其他人偶然发现这个问题?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-09
  • 1970-01-01
  • 2012-02-09
  • 1970-01-01
  • 1970-01-01
  • 2016-09-20
相关资源
最近更新 更多