Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How does JAVA classloader understand?

2025-03-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces you how to understand JAVA classloader, the content is very detailed, interested friends can refer to, hope to be helpful to you.

What is ClassLoader?

Among the popular commercial programming languages, the Java language stands out because it runs on the Java Virtual Machine (JVM). This means that compiled programs are an extraordinary, platform-independent format that does not depend on the machine on which they run. To a large extent, this format is different from the traditional executable format.

Unlike programs written by C or C++, Java programs are not an executable file, but are made up of many separate class files, each corresponding to a Java class.

In addition, these class files are not all loaded into memory immediately, but according to the needs of the program. ClassLoader is the part of JVM that loads classes into memory.

Moreover, Java ClassLoader is written in the Java language. This means that creating your own ClassLoader is very easy and you don't have to know the details of JVM.

Why write ClassLoader?

If JVM already has one ClassLoader, why write another one? That's a good question. The default ClassLoader only knows how to mount class files from the local file system. However, this is only suitable for the general situation, that is, all the Java programs have been compiled and the computer is waiting.

But the most innovative thing about the Java language is that JVM can easily get classes from non-local hard drives or from the network. For example, visitors can use custom ClassLoader to load executable content from a Web site.

There are many other ways to get class files. In addition to simply loading files locally or on the network, you can use a custom ClassLoader to accomplish the following tasks:

Automatically verify digital signatures before executing unbelievable code

Use the password provided by the user to transparently decrypt the code

Dynamically create custom build classes that meet the specific needs of users

Anything you think can generate Java bytecode can be integrated into your application.

[@ more@]

Custom ClassLoader exampl

If you've ever used JDK or any Applet viewer in a Java-based browser, you've almost certainly used a custom ClassLoader.

When Sun first released the Java language, one of the most exciting things was to see how this new technology executes code loaded at run time from a remote Web server. (in addition, there is something even more exciting-Java technology provides a powerful language that is easy to write code. Even more exciting is the ability to execute bytecode sent over a HTTP connection from a remote Web server

This feature is due to the fact that the Java language can install custom ClassLoader. The Applet viewer contains a ClassLoader that does not look for classes in the local file system, but accesses Web sites on remote servers, loads the original bytecode files through HTTP, and converts them into classes within JVM.

ClassLoaders in browsers and Applet viewers can also do other things: they support security and have different Applet run on different pages without interfering with each other.

Echidna written by Luke Gorrie is an open source package that allows you to run multiple Java applications on a single virtual machine. It uses a custom ClassLoader to prevent applications from interfering with each other by providing each application with its own copy of the file.

Our ClassLoader example

Now that we understand how ClassLoader works and how to write ClassLoader, we will create a Classloader called CompilingClassLoader (CCL). CCL compiles the Java code for us without us interfering with the process. It is basically similar to a "make" program that is built directly into the runtime system.

Note: prior to further understanding, it should be noted that some aspects of the ClassLoader system have been improved in JDK version 1.2 (that is, the Java 2 platform). This tutorial is written in JDK versions 1.0 and 1.1, but it can also be run in later versions.

The changes to ClassLoader in Java 2 describe the changes in Java version 1.2 and provide some specific information to modify ClassLoader to take advantage of these changes.

The basic goal of ClassLoader is to serve requests for classes. When JVM needs to use a class, it requests the class from ClassLoader by name, and ClassLoader attempts to return a Class object that represents the class. You can create a custom ClassLoader by overriding methods that correspond to different stages of the process.

In the rest of this article, you will learn the key methods of Java ClassLoader. You will learn what each method does and how it fits into the process of loading class files. You will also know what code you need to write when you create your own ClassLoader.

In the following sections, you will use this knowledge to use our ClassLoader example, CompilingClassLoader.

Method loadClass

ClassLoader.loadClass () is the entry point for ClassLoader. Its characteristics are as follows:

Class loadClass (String name, boolean resolve)

The name parameter specifies the name of the class required by JVM, which is represented in package notation, such as Foo or java.lang.Object. The resolve parameter tells the method whether the class needs to be parsed. Before preparing to execute a class, you should consider class parsing. You don't always need to parse. If JVM only needs to know whether the class exists or to find out the superclass of the class, there is no need to parse.

In Java version 1.1 and prior, the loadClass method was the only method that needed to be overridden when creating a custom ClassLoader. (changes to ClassLoader in Java 2 provide information about the findClass () method in Java 1.2. )

Method defineClass

The defineClass method is the main knack of ClassLoader. This method takes an array of raw bytes and converts it to a Class object. The original array contains data, such as mounted from a file system or network.

DefineClass governs many complex, mysterious, and implementation-dependent aspects of JVM-- it analyzes bytecode into run-time data structures, validates validity, and so on. Don't worry, you don't have to write it yourself. In fact, you can't overwrite it even if you want to, because it has been marked as final.

Method findSystemClass

The findSystemClass method mounts files from the local file system. It looks for a class file in the local file system and, if it exists, uses defineClass to convert the original bytes into Class objects to convert the file into a class. This is the default mechanism for JVM to load classes normally when running Java applications. (the changes to ClassLoader in Java 2 provide specific information about the process changes in Java version 1.2. )

For a custom ClassLoader, use findSystemClass only after trying other methods to load the class. The reason is simple: ClassLoader is responsible for the extraordinary step of loading classes, not for all classes. For example, even if ClassLoader loads some classes from a remote Web site, you still need to load a large number of basic Java libraries on the local machine. These classes are not our concern, so JVM loads them by default: from the local file system. This is what findSystemClass is for.

The workflow is as follows:

Request a custom ClassLoader load class.

Check the remote Web site to see if there are any required classes.

If there is, then good; grab this class and complete the task.

If not, assuming that the class is in the base Java library, call findSystemClass to load the class from the file system.

In most custom ClassLoaders, call findSystemClass first to save the time it takes to find many Java library classes that can be loaded locally on a remote Web site. However, as you'll see in the next section, we don't let JVM load classes from the local file system until we're sure that our application code will be compiled automatically.

Method resolveClass

As mentioned earlier, classes can be loaded either incompletely (without parsing) or completely (with parsing). When writing our own loadClass, we can call resolveClass, depending on the value of the resolve parameter of the loadClass.

Method findLoadedClass

FindLoadedClass acts as a cache: when loadClass is asked to load a class, it calls this method to see if ClassLoader has loaded the class, thus avoiding the hassle of reloading existing classes. The method should be called first.

Assembly

Let's look at how to assemble all the methods.

Our loadClass implementation example performs the following steps. (here, we don't specify which technique is used to generate the class file-- it can be loaded from the Net, extracted from the archive, or compiled in real time. Either way, it's an extraordinary magic way to get the bytes of the original class file. )

CCL disclosure

The task of our ClassLoader (CCL) is to ensure that the code is compiled and updated.

Here's how it works:

When requesting a class, first check to see if it is in the current directory of the disk or the corresponding subdirectory.

If the class does not exist but is in the source code, the Java compiler is called to generate the class file.

If the class already exists, check that it is older than the source code. If so, call the Java compiler to regenerate the class file.

If the compilation fails, or if the class file cannot be generated from the existing source code for some other reason, return ClassNotFoundException.

If you still don't have this class, maybe it's in another library, so call findSystemClass to find the class.

If still not, ClassNotFoundException is returned.

Otherwise, the class is returned.

Call findLoadedClass to see if there is a loaded class.

If not, use that extraordinary and magical way to get the original bytes.

If you already have the original bytes, call defineClass to convert them into Class objects.

If there are no original bytes, then call findSystemClass to see if the class is obtained from the local file system.

If the resolve parameter is true, then call resolveClass to parse the Class object.

If there is no class already, return ClassNotFoundException.

Otherwise, the class is returned to the caller.

How Java compilation works

Before going any further, you should take a step back and talk about Java compilation. In general, the Java compiler does not just compile the classes that you ask it to compile. It also compiles other classes if they are required by the class you require to compile.

CCL compiles each class in the application that needs to be compiled one by one. But in general, after the compiler compiles the first class, CCL looks for all the classes that need to be compiled, and then compiles it. Why? The Java compiler is similar to the rule we are using: if the class does not exist, or if it is older than its source code, then it needs to be compiled. In fact, the Java compiler does most of the work in a step before CCL.

When CCL compiles them, it reports the class on which application it is compiling. In most cases, CCL invokes the compiler on the main class in the program, and it does all that needs to be done-- a single call from the compiler is sufficient.

However, there is a situation where some classes are not compiled in the first step. If you use the Class.forName method to load the class by name, the Java compiler will not know what is needed for the class. In this case, you will see that CCL runs the Java compiler again to compile the class. This process is demonstrated in the source code.

Use CompilationClassLoader

To use CCL, the program must be called in an extraordinary way. Cannot run the program directly, such as:% java Foo arg1 arg2

It should be run in the following ways:

% java CCLRun Foo arg1 arg2

CCLRun is an extraordinary stub program that creates CompilingClassLoader and uses it to load the main class of the program to ensure that the entire program is loaded through CompilingClassLoader. CCLRun uses Java Reflection API to call the main method of a particular class and pass parameters to it. For more information, see the source code.

Run the sample

The source code includes a set of small classes that demonstrate how it works. The main program is the Foo class, which creates an instance of the class Bar. The class Bar creates another instance of the class Baz, which is in the baz package, to show how CCL handles the code in the subpackage. Bar is also loaded by name, which is called Boo, which is used to show that it can also work with CCL.

Each class declares that it is loaded and running. Now try it with the source code. Compile CCLRun and CompilingClassLoader. Be sure not to compile other classes (Foo, Bar, Baz, and Boo), otherwise CCL will not be used because these classes have already been compiled.

% java CCLRun Foo arg1 arg2

CCL: Compiling Foo.java...

Foo! Arg1 arg2

Bar! Arg1 arg2

Baz! Arg1 arg2

CCL: Compiling Boo.java...

Boo!

Please note that the compiler, Foo.java governance Bar and baz.Baz are called first. Until Bar loads Boo by name, it is called, and CCL calls the compiler again to compile it.

CompilingClassLoader.java

The following is the source code for CompilingClassLoader.java

/ / $Id$

Import java.io.*

/ *

A CompilingClassLoader compiles your Java source on-the-fly. It checks

For nonexistent .class files, or .class files that are older than their

Corresponding source code.

, /

Public class CompilingClassLoader extends ClassLoader

{

/ / Given a filename, read the entirety of that file from disk

/ / and return it as a byte array.

Private byte [] getBytes (String filename) throws IOException {

/ / Find out the length of the file

File file = new File (filename)

Long len = file.length ()

/ / Create an array that's just the right size for the file's

/ / contents

Byte raw [] = new byte [(int) len]

/ / Open the file

FileInputStream fin = new FileInputStream (file)

/ / Read all of it into the array; if we don't get all

/ / then it's an error.

Int r = fin.read (raw)

If (r! = len)

Throw new IOException ("Can't read all,"+ r +"! = "+ len)

/ / Don't forget to close the file!

Fin.close ()

/ / And finally return the file contents as an array

Return raw

}

/ / Spawn a process to compile the java source code file

/ / specified in the 'javaFile' parameter. Return a true if

/ / the compilation worked, false otherwise.

Private boolean compile (String javaFile) throws IOException {

/ / Let the user know what's going on

System.out.println ("CCL: Compiling" + javaFile+ "...")

/ / Start up the compiler

Process p = Runtime.getRuntime () .exec ("javac" + javaFile)

/ / Wait for it to finish running

Try {

P.waitFor ()

} catch (InterruptedException ie) {System.out.println (ie);}

/ / Check the return code, in case of a compilation error

Int ret = p.exitValue ()

/ / Tell whether the compilation worked

Return ret==0

}

/ / The heart of the ClassLoader-- automatically compile

/ / source as necessary when looking for class files

Public Class loadClass (String name, boolean resolve)

Throws ClassNotFoundException {

/ / Our goal is to get a Class object

Class clas = null

/ / First, see if we've already dealt with this one

Clas = findLoadedClass (name)

/ / System.out.println ("findLoadedClass:" + clas)

/ / Create a pathname from the class name

/ / E.g. Java.lang.Object = > java/lang/Object

String fileStub = name.replace ('.,'/')

/ / Build objects pointing to the source code (.java) and object

/ / code (.class)

String javaFilename = fileStub+ ".java"

String classFilename = fileStub+ ".class"

File javaFile = new File (javaFilename)

File classFile = new File (classFilename)

/ / System.out.println ("j" + javaFile.lastModified () + "c" +)

/ / classFile.lastModified ()

/ / First, see if we want to try compiling. We do if (a) there

/ / is source code, and either (b0) there is no object code

/ / or (b1) there is object code, but it's older than the source

If (javaFile.exists () & &

(! classFile.exists ()

JavaFile.lastModified () > classFile.lastModified ()) {

Try {

/ / Try to compile it. If this doesn't work, then

/ / we must declare failure. (It's not good enough to use

/ / and already-existing, but out-of-date, classfile)

If (! compile (javaFilename)! classFile.exists ()) {

Throw new ClassNotFoundException ("Compile failed:" + javaFilename)

}

} catch (IOException ie) {

/ / Another place where we might come to if we fail

/ / to compile

Throw new ClassNotFoundException (ie.toString ())

}

}

/ / Let's try to load up the raw bytes, assuming they were

/ / properly compiled, or didn't need to be compiled

Try {

/ / read the bytes

Byte raw [] = getBytes (classFilename)

/ / try to turn them into a class

Clas = defineClass (name, raw, 0, raw.length)

} catch (IOException ie) {

/ / This is not a failure! If we reach here, it might

/ / mean that we are dealing with a class in a library

/ / sUCh as java.lang.Object

}

/ / System.out.println ("defineClass:" + clas)

/ / Maybe the class is in a library-- try loading

/ / the normal way

If (clas==null) {

Clas = findSystemClass (name)

}

/ / System.out.println ("findSystemClass:" + clas)

/ / Resolve the class, if any, but only if the "resolve"

/ / flag is set to true

If (resolve & & clas! = null)

ResolveClass (clas)

/ / If we still don't have a class, it's an error

If (clas = = null)

Throw new ClassNotFoundException (name)

/ / Otherwise, return the class

Return clas

}

}

CCRun.java

The following is the source code for CCRun.java

/ / $Id$

Import java.lang.reflect.*

/ *

CCLRun executes a Java program by loading it through a

CompilingClassLoader.

, /

Public class CCLRun

{

Static public void main (String args []) throws Exception {

/ / The first argument is the Java program (class) the user

/ / wants to run

String progClass = args [0]

/ / And the arguments to that program are just

/ / arguments 1..n, so separate those out into

/ / their own array

String progArgs [] = new string [args.length-1]

System.arraycopy (args, 1, progArgs, 0, progArgs.length)

/ / Create a CompilingClassLoader

CompilingClassLoader ccl = new CompilingClassLoader ()

/ / Load the main class through our CCL

Class clas = ccl.loadClass (progClass)

/ / Use reflection to call its main () method, and to

/ / pass the arguments in.

/ / Get a class representing the type of the main method's argument

Class mainArgType [] = {(new String [0]) .getClass ()}

/ / Find the standard main method in the class

Method main = clas.getMethod ("main", mainArgType)

/ / Create a list containing the arguments-- in this case

/ / an array of strings

Object argsArray [] = {progArgs}

/ / Call the method

Main.invoke (null, argsArray)

}

}

Foo.java

The following is the source code for Foo.java

/ / $Id$

Public class Foo

{

Static public void main (String args []) throws Exception {

System.out.println ("foo!" + args [0] + "" + args [1])

New Bar (args [0], args [1])

}

}

Bar.java

The following is the source code for Bar.java

/ / $Id$

Import baz.*

Public class Bar

{

Public Bar (String a, String b) {

System.out.println ("bar!" + a + "" + b)

New Baz (a, b)

Try {

Class booClass = Class.forName ("Boo")

Object boo = booClass.newInstance ()

} catch (Exception e) {

E.printStackTrace ()

}

}

}

Baz/Baz.java

The following is the source code for baz/Baz.java

/ / $Id$

Package baz

Public class Baz

{

Public Baz (String a, String b) {

System.out.println ("baz!" + a + "" + b)

}

}

Boo.java

The following is the source code for Boo.java

/ / $Id$

Public class Boo

{

Public Boo () {

System.out.println ("Boo!")

}

}

On how to understand JAVA classloader to share here, I hope that the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report