简体   繁体   中英

How Maven loads classes using ClassLoader

My knowledge of ClassLoader in Java at the moment, is a little obscure. That's because I have not found any good documentation geared towards beginner of CLassLoader, thus far. And what I am looking for exactly is in relation to Maven. With disclaimer stated, let me get into my question.

I am writing a Spring MVC application, and I decided to look into how the Dependencies - Jars and classes are loaded using ClassLoader. And what I found is according to the documentation of ClassLoader, classes in Jar are loaded from CLASSPATH, and I can see them under the.m2/repository directory, but CLASSPATH does not yield anything, it's practically empty.

Can somebody please explain to me, how the classes from JAR are loaded into JVM Memory using ClassLoader using Maven, if the CLASSPATH is empty.

Thanks

You're confusing a few things.

The ClassLoader

The ClassLoader is a runtime concept. Maven is a compile time concept. Therefore, one has nothing whatsoever to do with the other. Maven and ClassLoaders do not interact. At all.

When you start a basic java app ( java -jar foo.jar or java com.foo.MainClass ), you get 2 classloaders. One loader will load system stuff: java.lang.String , for example. the executable itself 'just knows' how to do this (you don't need to configure PATH , CLASSPATH or JAVA_HOME - it just works); up to java 8, it finds rt.jar automatically, which contains String.class and other core classes. Starting from java 11, it finds the jmod files in your java distro.

Then, once the VM has 'booted up', the VM makes another classloader, also based on its built-in stuff: The app classloader.

This one uses 'the classpath'. The source of this depends on how you ran your java app:

  • java -jar somejar.jar

The source of the classpath in this case is the Class-Path: line in the jar's manifest (the file at META-INF/MANIFEST.MF ). And nothing else - the CLASSPATH environment variable, and any -cp or -classpath options are entirely ignored.

  • java -cp a.jar:b.jar:. com.foo.ClassName

Note that -cp is short for -classpath (they mean the same thing): Here, the classpath is taken to be all the files and directories listed (on windows, use ; as separator instead), and classes are loaded from there. Including com.foo.ClassName itself.

  • java com.foo.ClassName

If you don't explicitly specify a -cp param, then the environment var CLASSPATH is used. You don't want this though. Always specify classpath.

That's runtime - maven has nothing whatsoever to do with this.

Make your own

You can make your own ClassLoader; the abstraction is such that all it needs to be able to do, is turn a resource name into bytes. That's it. You can make a ClassLoader (literally! public class MyLoader extends java.lang.ClassLoader {... } ) that.. loads data from a network, or generates it on the fly, or fetches it from an encrypted data store. Whatever you like.

Using custom classloaders like this is a solution for finding classes in 'weird' places (not jar files or directories), as well as a mechanism to allow java to 'reload classes' on the fly - very useful when developing, say, web apps, without the use of a hot-code-replacing debugger like eclipse has. ClassLoaders is a mechanism whereby a web server can have the following feature: "I load jars or wars from a certain preconfigured directory.. and if you replace the jar, I will see it and start using the new one ".

Writing your own ClassLoader is bordering on rocket science and not usually required unless you're, say, writing an app server. Not a common job.

Maven

To compile source code, the compiler must know the methods and fields and such of all the types you refer. You can't compile "Hello".toLowerCase(); if the compiler doesn't know what String contains.

Thus, compilers also have this notion of 'I need to find classes'. But This is not called class loading , and notably, maven never loads any classes . If it did, any static initializers in any class would run, and mess up your compile. Maven instead just inspects the class file, never letting the VM actually load it, to know what kind of methods and fields and the like are on offer.

java.lang.ClassLoader plays no part in this .

javac itself has a -classpath option as well. So does maven, really.

Maven constructs the classpath automatically, by putting the stuff it already compiled for you (eg when compiling the stuff in src/test/java , the compiled stuff from src/main/java is on the classpath), as well as all the dependencies. How? Well, does it matter? Maven does. It constructs a large list of dirs and jars and passes it to javac via the -classpath parameter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM