Reputation: 6104
I'm trying to access classes from the servlet-api within a javaagent jar that is added to my application via the -javaagent:my-agent.jar flag. My application runs on Tomcat. The problem is that I get a ClassNotFoundException, because the agent jar is loaded by a classloader that has no access to the servlet-api classes.
More specifically, I want to include a ServletContainerInitializer in my javaagent
public class MyInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
System.out.println(ctx);
}
}
META-INF/services/javax.servlet.ServletContainerInitializer
org.example.MyInitializer
The result is a ClassNotFoundException because ServletContainerInitializer could not be found.
Is there any way to access the servlet-api within a javaagent? Or more generally, is it possible to access any class that is loaded via the ApplicationClassLoader, like classes from the spring framework?
Upvotes: 4
Views: 848
Reputation: 363
What worked for me was I added servlet-api.jar file in the ClassPool.insertClassPath. And that resolved the issue.
ClassPool $pool = ClassPool.getDefault();
try {
$pool.insertClassPath("/apache-tomcat-7.0.50/lib/servlet-api.jar");
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
return $pool;
https://github.com/presci/MyAgent.git
Upvotes: 0
Reputation: 298173
If your agent has a premain
method with a signature like
public static void premain(String agentArgs, Instrumentation inst)
You get hands on an Instrumentation
object which provides the methods getAllLoadedClasses()
and getInitiatedClasses(ClassLoader)
. Now it would be awkward to search these arrays each time and use the Class
instances via Reflection only. But you can use these methods to find the desired API class, determine its runtime ClassLoader
and create a new ClassLoader
using it as a resolve parent and pointing to your agent classes which require them.
Upvotes: 1