I think Jared started down this path because we had a custom classloader
implementation that he was trying to get rid of -- that impl was pretty
limited and forced loading of all classes up-front.

Now the code uses fast classpath scanner and that old custom classloader
can't be used. The old classloader is so simplistic and limited that trying
to modify it looks like more work than writing a new one from scratch.
Implementing a new custom classloader or switching our codebase to use a
new classloader container (using an existing solution) are both possible
directions. Until that's completed the "deploy jar" command will continue
to force ALL classes to be loaded up-front.

One major concern is that implementing a new custom classloader is
non-trivial and could also introduce some new classloader bugs -- of
particular interest to "deploy jar" is the fact that Java remembers TWO
classloaders for each class [1] -- the CL that *loaded* the class AND the
CL that *initiated* the request to load the class -- dropping the
*initiating* CL at runtime can result in failures to load additional
classes from the CL that directly loaded the class even though that CL is
intact and available.

[1] states: "When one class loader delegates to another class loader, the
loader that initiates the loading is not necessarily the same loader that
completes the loading and defines the class. If L creates C, either by
defining it directly or by delegation, we say that L initiates loading of C
or, equivalently, that L is an *initiating* loader of C."

For better or worse, this is one of the reasons why that old custom CL was
naively force loading all classes up-front -- ie, to avoid runtime
classloading failures if the initiating CL was dropped or replaced and
ultimately GC'ed. Java won't let you drop the *loading* CL but it will
allow you to drop the *initiating* CL (or it did historically -- the
reference seems to be down in native code, not in java.lang.Class). You'd
have to find some way to force all initiating requests up to the parent
application CL (or somehow prevent code in deployed jars from initiating
requests from other CLs) and maybe that's what this old custom classloader
was missing all along.

The tradeoff mentioned by Jared is only necessary if we want a release
(soon) that does NOT eagerly class load all deployed classes up-front.
Otherwise, this is a feature request that users might have to wait a little
longer for (and maybe that's ok!).

[1] https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.3

On Mon, Apr 10, 2017 at 10:30 AM, Anthony Baker <aba...@pivotal.io> wrote:

> What about this:
>
> 1) Each jar is deployed into it’s own classloader.
> 2) If the classloader for jar1 is unable to load a class, it delegates to
> its parent which can load classes from siblings to jar1.
>
> The classloader hierarchy would be:
>
> bootstrap << system << application << (deploy jar)*
>
> where the application classloader manages the delegation to all deployed
> jars.
>
> Anthony
>
>
> > On Apr 10, 2017, at 10:20 AM, Jared Stewart <jstew...@pivotal.io> wrote:
> >
> > There is last one implementation decision for GEODE-2290 that I'm torn
> about, namely having one classloader for all deployed jars vs having
> separate classloaders for each deployed jar.
> >
> > If we have one class loader, e.g. new UrlClassLoader(jar1, jar2), then:
> >
> > - Jar1 will be able to load classes/resources from jar2  (this was the
> previous behavior of deployed jars with our custom class loader)
> > - But if we redeploy jar 1, jar 2 will also get its class loader
> rebuilt, which may raise the likelihood of weird classloader problems
> arising
> >
> > Does anyone else have thoughts about this tradeoff?
> >
> > Thanks,
> > Jared
>
>

Reply via email to