Lazy Loading using Spring Data Neo4j 4 + AspectJ LTW running on Tomcat

我的梦境 提交于 2020-01-06 20:08:31

问题


I went through all the possibilities trying to make my project running on Tomcat and point cut the model (getters) and woven them using AspectJ Load Time Weaver. Basically, I followed all the steps in the Spring Documentation http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-atconfigurable. I also followed the same approach mentioned Lazy/Eager loading/fetching in Neo4j/Spring-Data. My project is divided in two main project: - core: spring-data-neo4j (repository and configuration), domain-model in a dedicated package, LoggingAspect and LazyLoadingAspect. p.s. I am not using any configuration in XML files. I am using Annotation purely. - content: web application running on Tomcat which depends on core project and I want to weave when I invoke getter methods in the domain project.

Running the core itself I managed to get it running using maven plugin and adding the dependencies for aspectj. But all the hell starts when I move to Tomcat. I tried all the possibilities e.g using -javaagent, create the custom context.xml, put spring-instrument into tomcat/lib folder, etc etc. I am receiving the following exception:

java.lang.IllegalStateException: 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!
    at org.springframework.beans.factory.wiring.BeanConfigurerSupport.checkExposedObject(BeanConfigurerSupport.java:173)
    at org.springframework.beans.factory.wiring.BeanConfigurerSupport.configureBean(BeanConfigurerSupport.java:143)
    at org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect.configureBean(AnnotationBeanConfigurerAspect.aj:63)
    at org.springframework.beans.factory.aspectj.AbstractDependencyInjectionAspect.ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$2$1ea6722c(AbstractDependencyInjectionAspect.aj:88)
    at com.test.server.graph.domain.model.Sequence.(Sequence.java:29)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
    at org.neo4j.ogm.annotations.EntityFactory.instantiate(EntityFactory.java:135)
    at org.neo4j.ogm.annotations.EntityFactory.instantiateObjectFromTaxa(EntityFactory.java:110)
    at org.neo4j.ogm.annotations.EntityFactory.newObject(EntityFactory.java:61)
    at org.neo4j.ogm.context.GraphEntityMapper.mapNodes(GraphEntityMapper.java:147)
    at org.neo4j.ogm.context.GraphEntityMapper.mapEntities(GraphEntityMapper.java:132)
    at org.neo4j.ogm.context.GraphEntityMapper.map(GraphEntityMapper.java:107)
    at org.neo4j.ogm.context.GraphEntityMapper.map(GraphEntityMapper.java:102)
    at org.neo4j.ogm.context.RestModelMapper.mapEntity(RestModelMapper.java:157)
    at org.neo4j.ogm.context.RestModelMapper.map(RestModelMapper.java:76)
    at org.neo4j.ogm.session.delegates.ExecuteQueriesDelegate.query(ExecuteQueriesDelegate.java:94)
    at org.neo4j.ogm.session.delegates.ExecuteQueriesDelegate.query(ExecuteQueriesDelegate.java:73)
    at org.neo4j.ogm.session.Neo4jSession.query(Neo4jSession.java:313)
    at org.springframework.data.neo4j.template.Neo4jTemplate.query(Neo4jTemplate.java:217)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
    at com.sun.proxy.$Proxy58.query(Unknown Source) 

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>

My Configuration class (core project)

@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();
    }
}

Domain-model classes

As recommended by Spring Documentation I annotated the classes in the Domain model

@Configurable

mvc-dispatcher-servlet (webapp project)

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

I tried running using tomcat-maven-plugin and tomcat standalone installation (v7 and v8).

-- UPDATE --

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() {
    }
}

回答1:


The main problem seems to be that you are applying aspects to beans:

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!

This wont work, so you have to make sure your model classes are real POJOs and not beans and exclude them from spring. (Make sure that in domain.model.* there is no spring annotation) - maybe if you post your Sequence.java I can see what might be causing the conflict.

On the other hand you have to make sure that aspectj is only assigned to the models and not any beans. So make sure you have a /META-INF/aop.xml that only includes your pojo models:

<!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>

Parts of my pom.xml (i have a different setup by now - thats why the spring version is so old):

    <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>

I dont have any special build plugins or similar



来源:https://stackoverflow.com/questions/37807707/lazy-loading-using-spring-data-neo4j-4-aspectj-ltw-running-on-tomcat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!