Re: context classloader

From: Oliver Jowett <oliver(at)opencloud(dot)com>
To: Vadim Nasardinov <vadimn(at)redhat(dot)com>
Cc: pgsql-jdbc(at)postgresql(dot)org
Subject: Re: context classloader
Date: 2005-01-19 04:12:59
Message-ID: 41EDDE4B.7030304@opencloud.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-jdbc

Vadim Nasardinov wrote:
> On Tuesday 18 January 2005 18:07, Oliver Jowett wrote:
>
>>I am of the opinion that thread context classloaders are evil
>
>
> If that's a moral judgment, I have no comment. If a technical one --
> where's the evidence? (My ignorance prevents me from taking sides in
> this argument. I'm just curious.)

It's just an opinion. I have been bitten by context classloader
weirdness often enough that I try to avoid it whenever I can.

If you use the CCL, you have added hidden coupling between whoever sets
the CCL and the use of the CCL. Hidden coupling is usually bad -- it
makes the code less obvious and more prone to context-sensitive
breakage. Many libraries depend on particular CCL settings *and do not
document this anywhere*. Really hidden coupling!

It gets worse if you are in a managed environment -- the environment may
be using the CCL for its own purposes, and your code may not even have
permission (security policy) to change the CCL.

To use a CCL-using library reliably in that sort of environment, you end
up setting and resetting the CCL on every call to the library (might
involve writing a privileged wrapper -- ugh!). This defeats the purpose
of having a CCL in the first place. Why not just configure the library
with the right ClassLoader via another mechanism, or explicitly pass a
ClassLoader to those methods that need to do class/resource loading?

Sorry .. it's a pet peeve of mine :)

Given that there is a non-ClassLoader-aware layer (DriverManager)
between the JDBC client and JDBC driver that we cannot change, if we
needed to pass a ClassLoader then using the CCL is probably the best
way. But I don't see that we *need* to pass a ClassLoader at all; see below.

> When you register the Driver instance with the DriverManager in the
> static initializer, a (weak) reference to the current context
> classloader may be saved in a static field. The field can be used
> later on in the getDefaultProperties() method, if
> getClass().getClassLoader() turns out to be null.

Ok, but I don't understand why you'd want to jump through all these
hoops in the first place. It is even less predictable when the static
initializer will be run (and therefore what the CCL will be set to at
that point). What's the point?

> (BTW, couldn't this
> be Driver.class.getClassLoader() instead?)

Yes. getClass() tends to be a bit friendlier to anything that tweaks the
bytecode, though, since a .class reference compiles down to a call to
Class.forName() which breaks if the class is renamed, etc.

>>Does it make sense to have the driver defaults change depending on
>>who is obtaining the connection?
>
> The fact that this is nonsensical is irrelevant. Changing defaults on
> a per connection basis has never been proposed.

*shrug* It's the logical conclusion of using the CCL to find the
defaults. The context can change -- why do the defaults *not* change if
you change the context? What is special about the context of the first
call to getConnection(), or the first action that happens to cause class
initialization (if you go with magic in the static initializer)?

> More to the point, can someone explain what
> /org/postgresql/driverconfig.properties files are actually used for?

Briefly, configuring driver defaults globally without having to mess
around with every application URL.

See http://archives.postgresql.org/pgsql-jdbc/2004-10/msg00023.php for
the thread that spawned it.

> Without knowing what this feature is actually used for, I'd speculate
> groundlessly that the context-classloader-based implementation is more
> likely to work in the application server scenario. Within the same
> app server instance, multiple *.properties files are likely to exist
> for use by different apps. These files aren't likely to be on the
> CLASSPATH.

I don't think it makes sense to allow a particular application to
override a bit of "global" data for the driver that is shared between
multiple applications. App servers can reconfigure the driver either
globally or on a per-application basis easily enough anyway.

> Rather, they're likely to be in a per-application config directory that the system classloader can't see.

The system classloader only gets involved when the driver has been
loaded in the *bootstrap* classpath. In all other cases, we use the
classloader that loaded the driver to load the defaults. Still, this
will usually be a classloader that cannot see the per-application resources.

If an application wants a customized set of defaults, it can arrange for
a separate instance of the driver packaged with the appropriate defaults
to be loaded with the application; in that case, there's no problem with
finding the right classloader.

-O

In response to

Responses

Browse pgsql-jdbc by date

  From Date Subject
Next Message Vadim Nasardinov 2005-01-19 14:57:26 Re: context classloader
Previous Message Vadim Nasardinov 2005-01-19 03:08:21 Re: context classloader