[External] : Re: Inconsistency with service loading by layer or by class loader
David Lloyd
david.lloyd at redhat.com
Mon Dec 16 14:01:13 UTC 2024
On Sun, Dec 15, 2024 at 8:24 AM Ron Pressler <ron.pressler at oracle.com>
wrote:
>
>
> > On 14 Dec 2024, at 19:31, David Lloyd <david.lloyd at redhat.com> wrote:
> >
> >
> > I'm honestly baffled by your question, because it indicates that you
> probably haven't really read or understood the entirety of my message,
> though I tend to be pretty wordy so I acknowledge that I'm at least
> partially to blame if that is the case.
>
>
> Complaints related the configuration of the runtime are brought up from
> time to time. When I try to get to the bottom of the issue, people often
> get frustrated because they think the answer is obvious and I rarely get an
> answer.
>
> > You phrase the question as if users were being rebellious against some
> broadly accepted natural order of things, which does not reflect any
> reality that I or my colleagues are aware of. But to answer the question at
> exactly face value: the user typically doesn't even know the difference.
> Many users don't ever launch an application using the `java` launcher
> outside of university. They're running a Quarkus application, or deploying
> into WildFly or Tomcat, or launching via JBang, or running in Spring Boot,
> or maybe running a prepackaged application, or any one of dozens of other
> ways that an application can be packaged and deployed. A user doesn't
> usually have any idea about whether the class loader which loads their
> classes is setting them up as a named module or just defining classes the
> old fashioned way.
>
>
> Who is the user and what are the classes in this case?
The user in this paragraph is the one launching the application.
For one, 99.99% of classes don’t need to care whether they reside in a
> named or an unnamed module.
I am not talking about these classes. Obviously `a = a + 6` doesn't care
about modules or the lack thereof.
> For another, the application author does have full control over every JAR
> they list on the command to put it in a named or an unnamed module.
>
No, they don't, because the users we are talking about are generally using
a packaging solution of some sort. They have *some* control. They don't
have *full* control unless they're ready to break things. It's like saying
they have full control over what native libraries the JDK is using. It's
*technically* true. But in practice they're not going to mess with low
level stuff like that.
> But right now, I don’t think we’re talking about arbitrary libraries (or
> application classes). We’re not even talking about “regular" libraries that
> use a ServiceLoader.
Yes, we are in fact talking about regular libraries, or at least, that's
what I'm talking about: regular libraries which use ServiceLoader running
within dynamic containers.
> We’re talking about “container” frameworks with a plugin system using
> ClassLoaders/ModuleLayer isolation. Such frameworks are important
> cornerstones of the ecosystem, but they make up maybe 1 in 10,000
> libraries. It is only they who need to confront the class/module path
> decision.
>
We (container framework authors) generally don't use ServiceLoader for this
kind of thing (well, we do sometimes, but that's not anywhere near my
primary point of concern since we have full control over that code).
Let’s call such a container framework X. There's at most one, maybe two,
> such frameworks in an application. Unless I misunderstand the situation,
> framework X — where the difficulty lies — is not itself loaded dynamically
> by WildFly or JBoss. Rather, it is loaded directly by the application (i.e.
> X *is* WildFly or JBoss). And here’s my question:
>
I don't think this represents a correct understanding of the situation. If
you were to write a server side application today, and you want access to
some framework capability, you are most likely going to use e.g. CDI's
`@Inject` and/or container-provided annotations for dependency injection.
You are definitely not going to use ServiceLoader directly, because it has
weird ergonomics, especially for end users, and as I said it is
unpredictable within containers because it requires a knowledge of the
class loading environment by the caller. For any practical purpose,
ServiceLoader is going to be almost exclusively used by third-party
libraries which are consumed by the user and wired up by the container.
To use X, the application author needs to configure the runtime (on the
> launcher command line) to load X.jar, where “X.jar" would typically stand
> for multiple service provider JARs. For some years, applications had to
> configure the runtime to load X like this `-cp X.jar`. You’re not
> complaining about that. But when I suggested you tell the application
> author to configure the runtime to load X with `-p X.jar` rather than `-cp
> X.jar` you seemed to claim that this is almost impossible and that `-cp
> X.jar` must also work. Why?
>
The application author is not using `-cp X.jar` or `-p X.jar` because in
most cases, the application author is either not launching with Java at all
(i.e. they're launching a container startup script), or they're going to
launch an uberjar or some special launcher that sets up a class loading
environment and bootstraps the application, following the instructions
provided by the container (today this might just be e.g. `java -jar
startup.jar` but again, in most cases this will be wrapped up in a script
of some sort).
Is it because the application author would write `-cp X.jar` out of habit?
> Is it because the application author uses some build tool to construct the
> runtime configuration and is unable to tell the build tool to configure `-p
> X.jar`? I once asked a maintainer of such a framework this question and his
> answer was, “all my users are familiar with -cp, but many have not used -p
> before and I’m afraid they’ll find it weird/confusing.” Would that be your
> answer, too?
>
I've never heard that argument from our users, but our users are mostly
running startup scripts or just following the directions given by our
container documentation.
> > It's not really feasible to expect library authors to detect whether
> they are going to be run as a module or not, particularly if they have many
> entry points, as they sometimes do. They could for example add a run time
> check on every entry point, or on the class initializers of every entry
> point class.
>
> But this isn’t needed in 99% of cases, and we’re not talking about
> “library authors” in general. We’re talking about a handful of large (and
> important) frameworks. Even if such a framework doesn’t also provide the
> single entry point to the program, can’t you put the test in the same place
> you first create the ServiceLoader, which I expect would detect the
> misconfiguration quite early in a plugin-based framework?
>
You could, and that might work in many cases, maybe even most cases. Few
third party library authors are going to do that though, especially if
there isn't a standard blob of code to do that for them. Why would they?
What is their motivation? As I said, they want their libraries to be
ubiquitous, so I doubt you will be able to make me believe that they are
going to want to exclude a class of users in the name of boosting module
mode. Instead they will have the reasonable (based on documentation at
least) expectation that ServiceLoader does something sensible always:
specifically, that given some target environment, that it will find the
implementation(s) of that service. But do refer to my other email about
trying to work out the "correct" behavior of that class because it's not
obvious.
--
- DML • he/him
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/jigsaw-dev/attachments/20241216/4e875ec6/attachment-0001.htm>
More information about the jigsaw-dev
mailing list