Spring load time weaving - spring

After 12 hours of trying I don't seem to be able to get Spring load time weaving working on Tomcat.
Spring 4.2.1
Hibernate 4.3.11
Tomcat 8.09
I am trying to get an #Entity autowired.
The weaver output always says:
not weaving 'mypackage.MyEntity'
unless I also use a #Configuration annotation on it. It will then weave but I get back A SPRIGNCGLIB proxy where all the properties are null.
If I remove the #Configuration annotation (I don't think it should be there anyway) then I don't get any weaving and #Autowired property is always null.
This is my configuration:
applicationContext-beans.xml
<context:component-scan base-package="my.package" />
<context:spring-configured />
<context:load-time-weaver />
classes/META-INF/aop.xml
<aspectj>
<weaver options="-Xreweavable">
<include within="my.package.*"/>
</weaver>
<aspects>
<aspect name="org.springframework.beans.factory.aspectj.AbstractInterfaceDrivenDependencyInjectionAspect"/>
</aspects>
MyEntity.java
package my.package;
#Entity
#Table(name = "user")
#Configurable
public class User {
private Encrypter encrypter; // THE CLASS I WANT INJECTED
#Autowired
public void setEncrypter(Encrypter encrypter) {
this.encrypter = encrypter;
}
}
context.xml
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
The Tomcat lib folder has (I am not sure it needs both of these):
spring-instrument-4.2.1.RELEASE.jar
spring-tomcat-weaver-2.5.6.SEC03.jar
The apps WEB-INF/lib folder has:
aspectjweaver-1.8.6.jar
spring-aop-4.2.1.RELEASE.jar
spring-aspects-4.2.1.RELEASE.jar
I have tried starting Tomcat with
-javaagent:D:/my/path/to/server/apache-tomcat-8.0.9/lib/spring-instrument-4.2.1.RELEASE.jar
but it didn't help and according to the Spring LTW documentation the context.xml fragment is the preferred way to do this.
Does anyone have any ideas?

Related

IBM JDK throwing error 0 class {0} is already woven and has not been built in reweavable mode [Xlint:nonReweavableTypeEncountered]

We have few aspects, Aspect classes are defined with #Aspect and declared the same aspect in METAINFO/aop.xml:
aop.xml
<aspectj>
<weaver options="-Xset:weaveJavaxPackages=true">
<include within = "Test"/>
</weaver>
<aspects>
<aspect name = "Test"/>
</aspects>
</aspectj>
Below error is thrown only in IBM JDK environment with WebSphere.
Exception:
Error at Test.java::0 class {0} is already woven and has not been
built in reweavable mode [Xlint:nonReweavableTypeEncountered]
The same code works with Tomcat + Oracle JDK stack combination.
As per AspectJ Configuration.
Aspect does not require to add it to the Weaver tag, which was causing error to thrown in SystemOut.log of WAS.
<aspectj>
<weaver options="-Xset:weaveJavaxPackages=true">
// add only actual classes to be woven.
</weaver>
<aspects>
<aspect name = "Test"/>
</aspects>
</aspectj>
An aop.xml file contains two key sections: "aspects" defines one or more aspects to the weaver and controls which aspects are to be used in the weaving process; "weaver" defines weaver options and which types should be woven.
https://www.eclipse.org/aspectj/doc/next/devguide/ltw-configuration.html

#AspectJ aspects not being weaved in application that uses Spring

I have added the line <context:load-time-weaver/>
to my application-context.xml,
and have created a META-INF\aop.xml file with the following:
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver options="-verbose">
<!-- only weave classes in our application-specific packages -->
<include within="com.xxx.aspectj.*"/>
</weaver>
<aspects>
<aspect name="com.xxx.aspectj.StandardAspect"/>
</aspects>
</aspectj>
With the aspect including a catch-all to simply see if it is even working:
#After("call (public * *(..))")
public void interceptEverything() {
System.out.println("Hello");
}
But nothing seems to happen, any ideas?
Removing the include within tag solved my problem.
I realized that I have misinterpreted the include within tag, I thought it had meant only weave aspects in the package listed, but it meant only weave aspects into classes in the package listed.

how to setup load-time weaving with Spring and Tomcat WITHOUT using the -javaagent on the command line

I am using Spring 3.2.9, Tomcat 6.0.44
I am trying to configure my application's Spring instrumentation provider (e.g. spring-instrumentation.jar) for load-time weaving, when it is deployed on Tomcat.
I have a requirement to NOT use:
"-javaagent:/path/path/spring-instrument.jar" on the command line to do the configuration.
I've read that I can configure the Spring instrumentation by modifying the <Context> element of my application's Tomcat configuration (in either Tomcat's server.xml or my web app's context.xml). Adding the appropriate <Context> element to the server.xml results in my application being correctly configured to run with Spring's instrumentation provider. Adding it to the context.xml (see below) does NOT result in a working setup.
I have a META-INF/aop.xml file, looks like this:
<aspectj>
<weaver options="-verbose -showWeaveInfo -debug">
<include within="com.mv.xx.services..*"/>
<exclude within="com.mv.xx.aop..*"/>
</weaver>
<aspects>
<aspect name="com.mv.xx.aop.MyAspect"/>
</aspects>
</aspectj>
I also specify that I want to use load-time weaving by adding this to my Spring context config:
<context:load-time-weaver />
And I add this jar to my application's classpath:
spring-instrument-tomcat.jar
WHAT I HAVE TRIED:
When starting Tomcat, If I identify the location of the spring-instrument.jar on the command line using the -javaagent parameter like this:
-javaagent:/path/path2/spring-instrument-3.2.9.RELEASE.jar
Everything works fine.
Next I removed "-javaagent:/path/path2/spring-instrument-3.2.9.RELEASE.jar" from the command line.
In Tomcat's server.xml file (located in $CATALINE_HOME/conf), I added a a <Context> element to the <Host> element, like this:
<Context path="/myApp" docBase="myApp">
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
</Context>
With this configuration everything behaves properly. However I have a requirement to not modify Tomcat's server.xml, since I don't have control over the server.xml (DevOps does, and is reluctant to modify it).
Next I removed the <Context> element from Tomcat's server.xml.
According to the Spring docs, I can add a /META-INF/context.xml to my webapp, and put the <Context> element that used to be in Tomcat's server.xml into the context.xml, like so:
<Context>
<Context path="/myApp" docBase="myApp">
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
</Context>
</Context>
However when I restart Tomcat, I get an error message in the logs saying:
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.weaving.AspectJWeavingEnabler#0': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loadTimeWeaver': Initialization of bean failed; nested exception is java.lang.IllegalStateException: ClassLoader [org.apache.catalina.loader.WebappClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar
After digging around, I read something that suggested that I modify the <context:load-time-weaver/> element in my Spring config, like this:
<context:load-time-weaver weaver-class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
And add the jar containing InstrumentationLoadTimeWeaver.class to my classpath.
However when I do that, I get this error message in the logs:
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
java.lang.IllegalStateException: Must start with Java agent to use InstrumentationLoadTimeWeaver. See Spring documentation.
etc....
Can anyone explain how to setup load-time weaving with Spring and Tomcat WITHOUT using the -javaagent on the command line, and WITHOUT modifying the server.xml?
This is the code that I managed to use in order to removed the exception that you mentioned.
Basically you have to implement the LoadTimeWeavingConfigurer and override the method getLoadTimeWeaver().
#Configuration
#ComponentScan(basePackages = "org.myproject")
#EnableAspectJAutoProxy
#EnableSpringConfigured
#EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.AUTODETECT)
public class Config implements LoadTimeWeavingConfigurer {
#Override
public LoadTimeWeaver getLoadTimeWeaver() {
return new ReflectiveLoadTimeWeaver();
}
#Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver() throws Throwable {
InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
return loadTimeWeaver;
}
}
I used invesdwin-instrument to perform that. It allows you to use Load time weaving instrumentation dynamically so that you don't have to use any javaagent.
It took me a bit of effort to make it work with Tomcat 8.5 though. But it finally work using this configuration with Spring Boot :
#SpringBootApplication
#EnableLoadTimeWeaving // instead of #ImportResource(locations = "classpath:/META-INF/ctx.spring.weaving.xml")
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
}
}
It should also work with previous version of Tomcat.
Regards
https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving/Static_Weaving
Try maven plug-in from the above link. It's working

Spring Aspects: specify which packages to weave

I have a Spring / Hibernate application. Custom type created by Hibernate needs Spring context, so I use Spring Aspects to provide it.
#Configurable(preConstruction = true)
public class EncryptedStringUserType implements EnhancedUserType {
...
#EnableSpringConfigured
#EnableLoadTimeWeaving
public class RootConfiguration {
...
After adding Spring Security, I got number of messages in stderr like this:
[AppClassLoader#14dad5dc] error can't determine implemented interfaces of missing type org.springframework.security.ldap.authentication.LdapAuthenticationProvider
when weaving type org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer
when weaving classes
when weaving
[Xlint:cantFindType]
Is it possible to specify packages of classes that should be weaved and avoid trying to weaving other ones?
SOLUTION
Put META-INF/aop.xml to resources root and exclude unnecessary packages:
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<exclude within="org.springframework.security.config.annotation.authentication.configurers.ldap.*"/>
<exclude within="org.springframework.security.config.annotation.web.configurers.openid.*"/>
</weaver>
</aspectj>
You can limit the scope of weaving by adding a <include within="your.package.here.*"/> tag to the META-INF/aop.xml file in your classpath. Here's a full example of META-INF/aop.xml taken from the Spring documentation:
<!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="foo.*"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="foo.ProfilingAspect"/>
</aspects>
</aspectj>

AspectJ not seeing META-INF/aop.xml

I am trying to get Load Time Weaving working with my Tomcat 7 webapp, in order to weave a class from an external jar file (located in WEB-INF/lib).
I have done the following:
Started Tomcat with the following parameters: -javaagent:/path/aspectjweaver-1.7.0.jar -classpath /path/aspectjrt-1.7.0.jar:etc
Placed aop.xml into WAR_ROOT/META-INF/, WEB-INF/lib/META_INF, WEB-INF/lib and WEB-INF/
aop.xml:
<aspectj>
<aspects>
<aspect name="ca.gc.agr.agrishare.web.jsf.chartlet.AgriShareGanttRendererAspect"/>
</aspects>
<weaver options="-verbose -debug -XnoInline">
<include within="org.jfree..*"/>
<dump within="org.jfree..*" />
</weaver>
</aspectj>
No matter where I place the file, my target class is not woven, and I keep seeing errors like this:
[WebappClassLoader#495b317b] error can't determine implemented interfaces of missing type javax.validation.ValidatorFactory
when weaving type org.hibernate.cfg.beanvalidation.TypeSafeActivator
when weaving classes
when weaving
[Xlint:cantFindType]
The fact that it is trying to weave a class outside of the package I specified, and considering that server startup time quadrupled, I think that it is trying to weave all classes.
What am I missing?
Figured it out.
WAR_ROOT/META-INF/ is the webapp metadata, looked up by servletContext.getResource("/META-INF/bla").
WAR_ROOT/WEB-INF/classes/META-INF is java classes metadata, looked up by getContextClassLoader().getResource("/META-INF/bla").
I created META-INF/aop.xml in my Config project (which is on the classpath), and everything is working properly now.

Resources