Newb
Newb

Reputation: 11

How to specify a loadTimeWeaver for Spring with maven

I have a strange error. I have a basic spring boot web server running (on jetty) in my intelliJIDEA IDE.

When I run a maven 'package' command, and instead try to run the web server from the command line, it gives me a loadTimeWeaver error. I do not understand the difference between the two run environments, it really seems to me like it should work.

In IDEA, I specify the following in the run config:
Main class: package.Starter
VM Options: -javaagent:C:/Users/newb/EXT_LIBS/spring-instrument-4.0.3.RELEASE.jar -noverify

On the command line I try to do the following:
java -javaagent:C:/Users/newb/EXT_LIBS/spring-instrument-4.0.3.RELEASE.jar -noverify -jar target\MySpringServer.war

But I get the following error:

java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:53)
        at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Cannot apply class transformer without LoadTimeWeaver specified
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1553)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
        at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:973)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:750)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:120)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:648)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:909)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:898)
        at au.net.iinet.operational.Starter.main(Starter.java:48)
        ... 6 more
Caused by: java.lang.IllegalStateException: Cannot apply class transformer without LoadTimeWeaver specified
        at org.springframework.orm.jpa.persistenceunit.SpringPersistenceUnitInfo.addTransformer(SpringPersistenceUnitInfo.java:80)
        at org.eclipse.persistence.jpa.PersistenceProvider.createContainerEntityManagerFactory(PersistenceProvider.java:348)
        at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:336)
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
        ... 21 more

What is the best way to fix this loadTimeWeaver issue? And is there a reason that it would work in my IDE, but not outside of it? I have already gone down the rabbit hole of trying to forcibly set the loadTimeWeaver, but it isn't trivial, and surely the fact that it works in my IDE means that I just have some very minor thing to check.

Thanks in advance.

EDIT:
I have found the answer! The following question was very helpful to me: I use load time weaving in spring. How can i set class loader in jetty?
Basically, I needed to also specify -Xbootclasspath/a:C:/Users/newb/EXT_LIBS/spring-instrument-4.0.3.RELEASE.jar on the command line. And now it doesn't give me those load time weaver errors! Woo!

Upvotes: 1

Views: 15022

Answers (1)

Vikram Palakurthi
Vikram Palakurthi

Reputation: 2506

This should fix your problem.

@Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver()  throws Throwable {
    InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
    return loadTimeWeaver;
}

The same can be done in xml configuration.

Found a new library that just solves to dynamically setup spring InstrumentationLoadTimeWeaver to enable support for aspects without having to start the JVM with an explicit java agent

<dependency>
    <groupId>de.invesdwin</groupId>
    <artifactId>invesdwin-instrument</artifactId>
    <version>1.0.2</version>
</dependency>

Spring boot config

@SpringBootApplication
/** 
 * Make @Configurable work via @EnableLoadTimeWeaving.
 * If it does not work, alternatively you can try: 
 * @ImportResource(locations = "classpath:/META-INF/ctx.spring.weaving.xml") 
 */
@EnableLoadTimeWeaving
public class MySpringBootApplication {
    public static void main(final String[] args) {
        DynamicInstrumentationLoader.waitForInitialized(); //dynamically attach java agent to jvm if not already present
        DynamicInstrumentationLoader.initLoadTimeWeavingContext(); //weave all classes before they are loaded as beans
        SpringApplication.run(MySpringBootApplication.class, args); //start application, load some classes
    }
}

Upvotes: 5

Related Questions