Question

I've got an interesting question about classloader behavior.

Question one: What is the order in which the classloader will load jars?

The following jars and containing classes are given:

a.jar
  +-com/scheffield/foo/A.class

b.jar
  +-com/scheffield/foo/B.class

Which class will be loaded?

Question two: Is it true that the path and name of a file in the classpath is unique?

The following jars and containing classes are given (realworld example):

spring-beans-3.0.3.RELEASE.jar
  +-META-INF/spring.schemas

spring-aop-3.0.3.RELEASE.jar
  +-META-INF/spring.schemas

What I can tell you is that both files are be loaded by Spring otherwise an exception would occur (see this article).

Why am I asking that:

I made a so called big jar (cookbook entry for gradle). Thats a jar with the application classes and all other dependencies unzipped and packet in the big jar. And I'm not absolutely sure what to do with duplicated files.

Was it helpful?

Solution

  1. Classes are resolved however a classloader wants to resolve them (that's the whole point of having a classloader architecture). Most classloaders you deal with in practice are variants of java.net.URLClassLoader which loads classes (and resources) based on a search path (class path) of directories and jars. Each location in the search path is treated as a source of classes and the locations are searched in order.

  2. No, names are not unique. The first one encountered in the search order will be used.

If you combine jars into one big jar there is a definite possibility of conflict. If you are careful to merge them from the last source in your effective classpath to the first (thus overriding later jars with earlier jars), you will get approximately the same result.

I say approximately because the manifests in jars contain additional processing instructions that need to be merged as well. For example, a manifest can contain a Class-Path attribute that includes additional jars in the classpath. It's possible to merge jars but lose manifest attributes that are specifying part of your actual necessary classpath. If your manifest contains sealed or signed jars then you might not be able to do this merging at all without violating the signed parts of the jar.

In summary, jars are not really designed to be merged in this way. It can work but there are many possibilities for error, some of which are not possible to solve. One common cause of error is to merge two jar files and end up with more than one entry with the same path, which is allowed in zip files. The ant jar and zip tasks allow you to merge multiple sources and can produce these kinds of issues.

Really, it's better to instead bundle web apps consisting of many jars and sources into a single WAR or EAR archive. That's kind of the whole point of why they exist.

OTHER TIPS

  1. the files are being loaded in the order the containing jars appear on the classpath. this applies to classes. if you are loading other resources (like the spring.schema) you may use either classloader.getResource(...) or classloader.getResources(...). the first one returnes the first resource on the classpath, the second one also returnes shadowed resources.
  2. I don't think a valid zip archive contains duplicate entries.

regards

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top