-
Notifications
You must be signed in to change notification settings - Fork 40.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
javaagent could not work normally when application is started as a uber executable jar #4868
Comments
If launched correctly, Java Agents should work as far as we know. For example, AspectJ load-time weaving is known to work. Can you please provide a sample project that illustrates the problem along with exact details of how to launch your failing application? |
@wilkinsona here is a sample project git@github.com:segeon/agent-example.git. This sample project contains two modules, one is the agent and the other is testapp. When launched from testapp's main method, the agent works fine. However, when launched from an executable jar, the agent fails. |
@segeon Thanks for the sample. Can you please provide exact details of how you are running the app when you use the main method and when you use the executable jar? |
@wilkinsona I've added two scripts in script dir. start_from_exec_jar.sh is for starting the testapp as a spring boot uber jar, while the other script is for starting testapp from it's main method directly, imitating the way running an application from an IDE like Idea. When started using the former method, the agent fails. However, it's ok to start using the latter way. Pls have a try |
@segeon Thanks again |
@segeon I don't think we'll be able to do anything about this in 1.3.x, but I believe we can simplify things in 1.4. I've prototyped some changes for #4897 which dramatically simplifies Boot's custom class loader, allowing it to use standard delegation to the app/system class loader. With these changes in place, you executable jar sample works, albeit with one change. I had to remove |
When an application is run as an executable archive with nested jars, the application's own classes need to be able to load classes from within the nested jars. This means that the application's classes need to be loaded by the same class loader as is used for the nested jars. When an application is launched with java -jar the contents of the jar are on the class path of the app class loader, which is the parent of the LaunchedURLClassLoader that is used to load classes from within the nested jars. If the root of the jar includes the application's classes, they would be loaded by the app class loader and, therefore, would not be able to load classes from within the nested jars. Previously, this problem was resolved by LaunchedURLClassLoader being created with a copy of all of the app class laoder's URLs and by using an unconventional delegation model that caused it to skip its parent (the app class loader) and jump straight to its root class loader. This ensured that the LaunchedURLClassLoader would load both the application's own classes and those from within any nested jars. Unfortunately, this unusual delegation model has proved to be problematic. We have seen and worked around some problems with Java Agents (see spring-projectsgh-4911 and spring-projectsgh-863), but there are others (see spring-projectsgh-4868) that cannot be made to work with the current delegation model. This commit reworks LaunchedURLClassLoader to use a conventional delegate model with the app class loader as its parent. With this change in place, the application's own classes need to be hidden from the app class loader via some other means. This is now achieved by packaging application classes in BOOT-INF/classes (and, for symmetry, nested jars are now packaged in BOOT-INF/lib). Both the JarLauncher and the PropertiesLauncher (which supports the executable jar layout) have been updated to look for classes and nested jars in these new locations.
I'm trying to instrument a spring boot application using javaagent. My agent works fine when started from my ide by running my main method. However, when I package my app into an executable jar using
spring-boot-maven-plugin
, my agent fails due to some classloading issues. Detail problem description can be found here raphw/byte-buddy#87After a probe into spring boot's source code, I found the root cause of this problem. When starting a uber jar, spring boot uses a dedicated classloader named LaunchedURLClassLoader to load resources from the uber jar. This classloader does not respect the normal convention of classloading process. It delegates classloading task to ExtClassloader instead of default system classloader. Moreover, it excludes javaagent jars out of its classpath URLs. Consequently java agent classes are invisible to my application classes and java agent classes can't reference third party classes that packaged in the uber jar neither.
One solution is to package the agent into uber jar too. But it's not so elegant.
What puzzles me is why spring boot doesn't respect the normal classloading semantics and skip default system classloader during class loading process and why should the LaunchedURLClassLoader ignore javaagent jars.
Pls help me understand spring boot's considerations. Thanks a lot!
FYI, I'm using spring boot 1.3.1.RELEASE
The text was updated successfully, but these errors were encountered: