Ask a real Java expert about the class loader of ant build tool

Source: Internet
Author: User

Problem description: Each classloader can only load classes in specific locations and directories, but classloader is designed as a delegate mode, so that a classloader can delegate its parent class loader to load classes, so that the application can use a sub-level classloader to load classes in multiple locations and directories. This is like a "son" who can spend his own money, but also "father" who can spend money, and "father" who can also spend money, the money that can be spent by the "son" includes the money of his predecessors. The class loader is delegated to the bootstrap class loader at the first level. When Bootstrap cannot load the class to be loaded, it is then rolled back to the Child class loader for real loading. When it is rolled back to the original Class Loader, if it cannot complete the class loading itself, it should report the classnotfoundexception exception.
Now, I have compiled a class in the special directory where the loader is used to test the Class Loader. The test result is completely normal and the delegate effect is displayed. However, when I use the ant tool to call the test program, the result is a bit problematic. The class loader I wrote does not seem to delegate its parent class loader to load the class, and always load it by yourself. Due to the lack of talent and the inability to study the ant tool's source code, I am unable to understand the internal details of its class loading. I would like to ask the real Java experts for this question. In order to help the experts quickly understand my problem and to learn from some of them, I wrote detailed experiment steps. For beginners of Java, I suggest not to participate in the discussion, otherwise, I will delay your precious time.

1. source program: mainclass. Java
Package CN. itcast;
Public class mainclass
{
Public static void main (string [] ARGs)
{
Classloader loader = mainclass. Class. getclassloader ();
// Print out the current class loader and its parent class loaders at all levels.
While (Loader! = NULL)
{
System. Out. println (loader. getclass (). getname ());
Loader = loader. getparent ();
}
// Load the auxiliaryclass
System. Out. println (auxiliaryclass. Class. getname ());
}

}
Source program: auxiliaryclass. Java
Package CN. itcast;
Public class auxiliaryclass
{
}

2. directory structure of the source file and build result File
F:/Project
|__ SRC
| |__ CN
| |__ Itcast
| |__ Mainclass. Java
| |__ Auxiliaryclass. Java
|__ Build. xml
|__ Classes
|__ CN
|__ Itcast
|__ Mainclass. Class
|__ Auxiliaryclass. Class
3. Build. xml file content
<Project name = "antloader" default = "run">
<Property name = "classes. dir" value = "classes"/>
<Property name = "src. dir" value = "src"/>

<Target name = "init">
<Mkdir dir = "$ {classes. dir}"/>
</Target>

<Target name = "compile" depends = "init">
<Javac destdir = "$ {classes. dir}">
<SRC Path = "$ {SRC. dir}"/>
</Javac>
</Target>
 
<Target name = "run" depends = "compile">
<Java classname = "cn. itcast. myclassloader">
<Classpath>
<Pathelement location = "$ {classes. dir}"/>
</Classpath>
</Java>
</Target>
</Project>
4. Go to the project directory and run ant. The execution result is normal as follows:
Org. Apache. Tools. Ant. loader. antclassloader2
Sun. Misc. launcher $ appclassloader
Sun. Misc. launcher $ extclassloader
CN. itcast. auxiliaryclass
5. Modify the build. xml file and change the target (Execution target) named "run" to the following format, that is, do not set the <classpath> child element.
<Target name = "run" depends = "compile">
<Java classname = "cn. itcast. myclassloader">
<! -- Classpath>
<Pathelement location = "$ {classes. dir}"/>
</Classpath -->
</Java>
</Target>
Execute ant again and report the following error message.
Cocould not find CN. itcast. mainclass. Make sure you have it in your classpath
At org.apache.tools.ant.taskdefs.executejava .exe cute (executejava. Java: 170)
Set the classpath environment variable in the command line window for ant execution:
Set classpath = F:/project/classes;
Execute ant again and the execution result is normal as follows:
Java.net. urlclassloader
Sun. Misc. launcher $ appclassloader
Sun. Misc. launcher $ extclassloader
CN. itcast. auxiliaryclass
This experiment shows that the classpath environment variable plays a role in ant. In this case, the class loader is no longer Org. apache. tools. ant. loader. antclassloader2, but java.net. urlclassloader.
6. Modify the build. xml file so that the auxiliaryclass. Class file generated by ant is located in a different directory from the mainclass file. The result directory is as follows:
F:/Project
|__ SRC
| |__ CN
| |__ Itcast
| |__ Mainclass. Java
| |__ Auxiliaryclass. Java
|__ Build. xml
|__ Classes
| |__ CN
| |__ Itcast
| |__ Mainclass. Class
|__ CN
|__ Itcast
|__ Auxiliaryclass. Class
The modified build. xml file is as follows:
<Project name = "antloader" default = "run">
<Property name = "classes. dir" value = "classes"/>
<Property name = "src. dir" value = "src"/>
<Property name = "mainclass" value = "cn. itcast. mainclass"/>
 
<Target name = "init">
<Mkdir dir = "$ {classes. dir}"/>
</Target>

<Target name = "compile" depends = "init">
<Javac destdir = "$ {classes. dir}">
<SRC Path = "$ {SRC. dir}"/>
<Include name = "cN/itcast/mainclass. Java"/>
</Javac>
<Delete file = "$ {classes. dir}/CN/itcast/auxiliaryclass. Class"/>
<Javac destdir = ".">
<SRC Path = "$ {SRC. dir}"/>
<Include name = "cN/itcast/auxiliaryclass. Java"/>
</Javac>
</Target>
 
<Target name = "run" depends = "clean, compile">
<Java classname = "$ {mainclass}">
<! -- Classpath>
<Pathelement location = "$ {classes. dir}"/>
</Classpath -->
<Arg line = "$ {arg0 }$ {arg1}"/>
</Java>
</Target>
 
<Target name = "clean">
<Delete dir = "$ {classes. dir}"/>
</Target>
 
</Project>
Because the first javac task compiles mainclass. java will also compile the auxiliaryclass it references. java file. Therefore, the delete task is added to delete the generated auxiliaryclass. class file, and then use a javac task to convert auxiliaryclass. compile Java into another directory. A <Arg> sub-element is added to the Java task to pass parameters to the Java Virtual Machine. This element is not required in this step. This element will be used in the next experiment.
Execute ant again and report the following error message.
Cocould not find CN. itcast. Auxiliary. Make sure you have it in your classpath
At org.apache.tools.ant.taskdefs.executejava .exe cute (executejava. Java: 170)
Set the classpath environment variable in the command line window for ant execution, and add the directory of the compiled auxiliaryclass. Class class to the classpath environment variable:
Set classpath = F:/project/classes; F:/project;
Execute ant again and the execution result is normal as follows:
Java.net. urlclassloader
Sun. Misc. launcher $ appclassloader
Sun. Misc. launcher $ extclassloader
CN. itcast. auxiliaryclass
This experiment once again demonstrates that the classpath environment variable plays a role in ant, placing auxiliaryclass. Class in another directory specified by the classpath environment variable can also be loaded by the Java task of ant tool.
7. Modify the mainclass. Java file so that it can be extended into a class loader which is responsible for loading classes from a specific directory. Mainclass is also used as a startup class. In its main method, the Class Loader mainclass is used to load the auxiliaryclass class.
Source program: mainclass. Java
Package CN. itcast;
Import java. Io .*;

Public class mainclass extends classloader
{
Private string Path = NULL;
Public mainclass (string path)
{
// Error check omitted
This. Path = path;
}

Protected class findclass (string name) throws classnotfoundexception
{
Try
{
File F = new file (path, name. substring (name. lastindexof ('.') + 1) + ". Class ");
Fileinputstream FCM = new fileinputstream (f );
Bytearrayoutputstream Bos = new bytearrayoutputstream ();
Int B = 0;
While (B = FCM. Read ())! =-1)
{
Bos. Write (B );
}
Byte [] Buf = Bos. tobytearray ();
FCM. Close ();
Bos. Close ();
Return defineclass (name, Buf, 0, Buf. Length );
} Catch (exception E)
{
Throw new classnotfoundexception (name + "is not found! ");
}
}
 
Public static void main (string [] ARGs) throws exception
{
Class CLS = new mainclass (ARGs [1]). loadclass (ARGs [0]);
Classloader loader = Cls. getclassloader ();
// Print out the Dynamically Loaded auxiliaryclass class loader and its parent class loaders at all levels.
While (Loader! = NULL)
{
System. Out. println (loader. getclass (). getname ());
Loader = loader. getparent ();
}
}

}
Run the ant command as follows. The first parameter is the class to be loaded, and the second parameter is the directory to which the class is loaded.
Ant-darg0 = cn. itcast. auxiliaryclass-darg1 = Cn/itcast
The command execution result is:
CN. itcast. mainclass
Sun. Misc. launcher $ appclassloader
Sun. Misc. launcher $ extclassloader
The first line shows that the class loader of the auxiliaryclass class is mainclass. This result is different from my expectation, because according to the delegate mechanism of the Class Loader, The mailclass loader will first delegate its parent class loader appclassloader to load auxiliaryclass, And the auxiliaryclass directory F: /Project has been added to the classpath environment variable in step 1. appclassloader can successfully load auxiliaryclass. Therefore, the Class Loader printed in the first line should be appclassloader.To verify my idea, I used java.exe to execute the above program:
Java CN. itcast. mainclass CN. itcast. auxiliaryclass cN/itcast
The execution result is as follows:
Sun. Misc. launcher $ appclassloader
Sun. Misc. launcher $ extclassloader
When java. EXE is used to execute the above program, the Class Loader of the auxiliaryclass class is indeed the parent class loader appclassloader of the mailclass class loader. This is my question: why does the mailclass Class Loader load the auxiliaryclass class without entrusting its parent class loader appclassloader to run in the ant environment? In this case, I would like to ask the real Java experts? Please help me explain the cause.
8. To verify the delegate mechanism of the Class Loader, we reset the classpath environment variable, which no longer contains the directory F:/project where auxiliaryclass is located.
Set classpath = F:/project/classes;
Run the CD command to enter the F:/directory (to avoid interference with the current directory), and then run the following Java command again:
Java CN. itcast. mainclass CN. itcast. auxiliaryclass Project/CN/itcast
The execution result is as follows:
CN. itcast. mainclass
Sun. Misc. launcher $ appclassloader
Sun. Misc. launcher $ extclassloader
It can be seen that the class loader of the auxiliaryclass class is the mailclass class this time, because the parent class loader of the mailclass class loader, appclassloader, cannot find the auxiliaryclass class, the loading process is returned to the mailclass loader. The mailclass Class Loader successfully finds the auxiliaryclass class from the project/CN/itcast directory. Therefore, the printed class loader is mailclass.

 

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.