3
  • I don't want to use the URL Classloader to load classes.
  • I want to implement this myself.
  • I don't want to use a solution like JRebel (although it's great).

I've got prior experience of JavaAssist, bytecode generation, implementing javaagent class transformers etc.

I would like to write a javaagent which hooks into the classloader or defines it's own system classloader.

I'll store the class files in an in memory cache, and for particular files, periodically reload them from disk.

I'd prefer to do this in a way which doesn't involve continuously polling the file system and manually invalidating specific classes. I'd much rather intercept class loading events.

I last messed around with this stuff 4 years ago, and I'm sure, although my memory may deceive me that it was possible to do, but 8 hours of searching google doesn't present an obvious solution beyond building a patched JVM.

Is this actually possible?

I've created a stub implementation at https://github.com/packetops/poc_agent if anyone's interested in a simple example of javaagent use.

update

Just found this post - I may have been using the wrong approach, I'll investigate further.

Community
  • 1
  • 1
bryan hunt
  • 644
  • 4
  • 20

1 Answers1

1

It depends on what you want to do. If you want to reload your classes and define new ones, then you are fine with implementing your own classloader, as you already found.

If you want to replace existing classes, things become more "envolved". You can do this by implementing your own tiny Java agent. See the Java documentation, how to do this: http://docs.oracle.com/javase/7/docs/api/java/lang/instrument/package-summary.html

With the instrumentation mechanism you can not freely redefine classes, quote from Instrumentation.redefineClass:

The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance. These restrictions maybe be lifted in future versions. The class file bytes are not checked, verified and installed until after the transformations have been applied, if the resultant bytes are in error this method will throw an exception.

If you want to do more, you need to load it again. This can be done under the same name, by using a different classloader. The previous class definition will be unloaded, if no one else is using it any more. So, you need to reload any class that uses your previous class also. Utlimatly, you end up reinventing something like OSGi. Take a look at: Unloading classes in java?

Community
  • 1
  • 1
cruftex
  • 5,545
  • 2
  • 20
  • 36
  • I guess to be more specific, I'd like to prevent the caching of the class definitions so that every time (or at least very frequently) the definition will be requested from my custom classloader (it will maintain an internal cache, with a very short TTL ( say 60 seconds or so ) ). – bryan hunt Jan 06 '16 at 11:00
  • @bryan hunt: you can’t “prevent the caching of class definitions”. Once a `Class` object has been created, it will live as long as its defining `ClassLoader` exists. You will notice when you try to define (again) a class with the same name on the same class loader. Since that won’t work, you *must* remember the name to `Class` mapping of previously defined classes and return them on request. An Instrumentation Java Agent is a completely different thing. – Holger Jan 06 '16 at 11:16
  • Good comment from Holger. Actually, there is no thing such as a cache. It's either in use or not. Updated the answer also. – cruftex Jan 06 '16 at 11:19
  • Thanks guys. OK. So what about something that takes the list of classes loaded through the custom classloader, and periodically loads the new definitions, or evicts the existing definitions so they get reloaded? Can something like that be done. Wish Sun had just gone the BEAM route and made reloading a bit easier than having to restart the entire VM. – bryan hunt Jan 06 '16 at 12:01