[jboss-dev] AS ClassLoading in Embedded Environments

Andrew Lee Rubinger andrew.rubinger at redhat.com
Sun Jan 31 18:24:40 EST 2010


Thanks for your comments, Adrian.

The NCDFE on jboss-deployers-vfs-spi was a simple omission; I missed 
this explicit import (it may be added safely).

https://jira.jboss.org/jira/browse/EMB-82

There's some non-trivial stuff underlying though; I'll tackle them on a 
case-by-case basis.  But first some explanation.

On 01/29/2010 10:57 PM, Adrian Brock wrote:
 > I'm not sure what you gain by minimising the classpath
 > for this stuff, other than making it configurable in some xml?
 > That's why we do it that way in jboss-as.

Two reasons:

1) Useability
Give users a single JAR boot dependency; make it easy for them to set up 
manually or in Ant.  Otherwise we have to repackage everything into an 
uberJAR or give a long list of JARs under $JBOSS_HOME to put on the 
--classpath
2) Stay as close to traditional AS as possible
If we put everything on the appCl then this will become the loading CL 
for all of our classes, introducing potential bugs if AS/subproject code 
depends/assumes something about CL structure.

The easiest way to solve 1) comes courtesy of Maven; if you add a 
dependency upon org.jboss.embedded:jboss-embedded-depchain, you get 
everything you need transitively.  But not everyone uses Maven. :)

Case in point for 2; if I want to add jnp-server and jnpclient at a 
level such that the client Thread has access, we get:

java.lang.IllegalArgumentException: interface 
org.jboss.ha.framework.interfaces.HARMIProxy is not visible from class 
loader
	at java.lang.reflect.Proxy.getProxyClass(Proxy.java:353)
	at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:581)
	at 
org.jboss.ha.framework.server.HARMIServerImpl.createHAStub(HARMIServerImpl.java:172)
	at 
org.jboss.ha.jndi.HANamingService.getNamingProxy(HANamingService.java:148)
	at 
org.jboss.ha.jndi.DetachedHANamingService.startService(DetachedHANamingService.java:367)
	at 
org.jboss.system.ServiceMBeanSupport.jbossInternalStart(ServiceMBeanSupport.java:376)
	at 
org.jboss.system.ServiceMBeanSupport.pojoStart(ServiceMBeanSupport.java:216)

This is because of the impl:

http://anonsvn.jboss.org/repos/jbossas/trunk/cluster/src/main/java/org/jboss/ha/framework/server/HARMIServerImpl.java@createHAStub

...where we rely on the loading CL of "intf" also has visibility to 
HARMIProxy.  So in essence the HAJNDI stuff must be at the same CL.

I'll have a look at fixing this at the AS level.  For now there's no way 
to create a JNDI Context using the slim-boot ClassLoading.

https://jira.jboss.org/jira/browse/EMB-83

 > P.S. This is very ugly, you're depending too much on impl
 > details of the AS distribution structure.
 > 
https://svn.jboss.org/repos/jbossas/projects/embedded/trunk/api/src/main/java/org/jboss/embedded/api/server/JBossHomeClassLoader.java
 > e.g. version control/maintenance problems when the appserver
 > changes but you don't either because you're not on the same
 > release cycle or the AS developer (especially the ones that
 > can't keep their fingers off the refactoring button :-)
 > simply doesn't know this dependency exists.

Because I don't consider the AS distribution an impl detail.  In many 
ways its structure is an API as users may depend upon it in their 
scripts.  We cannot change it in minor or point releases, so I'm 
comfortable depending upon it.  Eager to entertain other ideas to give 
users an easy way for slim boot dependency based of $JBOSS_HOME.

S,
ALR

On 01/29/2010 10:57 PM, Adrian Brock wrote:
> I don't get it?
>
> You've created this dependency by making your embedded server impl
> depend on deployers-vfs-spi.
>
> https://svn.jboss.org/repos/jbossas/projects/embedded/trunk/core/src/main/java/org/jboss/embedded/core/server/JBossASEmbeddedServerImpl.java
>
> import org.jboss.deployers.vfs.spi.client.VFSDeploymentFactory;
>
> If you're not doing what jboss-as does, i.e. use a peer classloading
> model for those classes, then all the stuff you've compiled over
> (imported) needs to be in the same classloader (or a parent
> classloader).
>
> Its the classpath in your case, so run
> mvn dependency:tree
> in your embedded project to work out the classpath.
>
> Alternatively, don't compile over those classes and use an
> interface/delegate (or reflection with dynamic classloading) for
> that stuff to keep the classes in the classpath to a minimum.
>
> I'm not sure what you gain by minimising the classpath
> for this stuff, other than making it configurable in some xml?
> That's why we do it that way in jboss-as.
>

>
> On Fri, 2010-01-29 at 14:22 -0500, Andrew Lee Rubinger wrote:
>> Open call for comments/suggestions.  I'm running low on ideas.
>>
>> ClassLoading in AS has a few phases:
>>
>> 1) Launch (application classpath, run.jar, some minimal APIs only)
>> 2) Bootstrap (A bunch of JARs in $JBOSS_HOME/lib, enough to start the
>> Kernel and deploy the bootstraps)
>> 3) Service Deployments (jboss-cl takes over, adding in support from
>> $JBOSS_HOME/common as appropriate)
>>
>> In an Embedded environment, the client is in the same JVM as the server.
>>    The TCCL of the Main Thread needs to be able to:
>>
>> * Establish a JNDI Context via "new InitialContext();"
>> * Deploy
>>
>> For these, TCCL needs to have access to runtime internals provided via
>> jbossall-client.jar.  If this is loaded by a parent CL of something it
>> references, we get NCDFE.  For instance:
>>
>> java.lang.NoClassDefFoundError:
>> org/jboss/deployers/vfs/spi/client/VFSDeploymentFactory
>> 	at
>> org.jboss.embedded.core.server.JBossASEmbeddedServerImpl.deploy(JBossASEmbeddedServerImpl.java:256)
>>
>> Here the AS deployment mechanism is loaded in a ClassLoader higher in
>> the hierarchy than VFS Deployers SPI.  I could move where we load VFS
>> Deployers SPI higher up, which would then leak out something else, and
>> on and on.
>>
>> I currently cannot concoct an environment where:
>>
>> * User has a minimal application ClassPath
>> * Other ClassLoading is transparent
>> * Everything works
>>
>> Some attempt to use an isolated ClassLoader result in ClassCastException
>> when equal FQNs end up w/ separate defining ClassLoaders.
>>
>> I believe I'm trying in vain to hack around the underlying problem where
>> the AS module system is not separated out to support this kind of use.
>> We have ClassLoading requirements not being met:
>>
>> * JARs safe for client use at all CL levels (ie. no references to
>> outside dependencies which would also need to be loaded by the same CL)
>> * JARs for compilation only, and runtime will be provided by the
>> container (ie. Maven scope "provided")
>> * JARs used by AS internals *only*.
>>
>> For now I think the only way forward is to either put:
>>
>> 1) Every single one of AS's dependencies on the application ClassPath
>>     * http://community.jboss.org/docs/DOC-14441
>> 2) Use a JBossHomeClassLoader which refers out to every AS runtime
>> dependency in $JBOSS_HOME/lib, $JBOSS_HOME/common/lib, and the server libs.
>>
>> S,
>> ALR
>>
>

-- 
Andrew Lee Rubinger
Sr. Software Engineer
JBoss by Red Hat
http://exitcondition.alrubinger.com
http://twitter.com/ALRubinger



More information about the jboss-development mailing list