Understood in Java class loader

0. class life cycle

Class loader is an innovative Java, which makes the Java virtual machine can then read into a Java virtual machine class in the process of implementation, improving the flexibility of the program. In Java, the class information is stored in the method area. Before introducing the class loader, we first look at the life cycle of Java classes. The life cycle of a Java class can be divided into the following six steps:

  1. Loading, by the class loader, the binary read into a class of virtual machine, and finally generates a Class instance object;
  2. Link, the binary data to merge running virtual machine state to go, this step can be divided into the following three parts:
    1. Verification, to ensure the correct binary format;
    2. Ready, it needs to allocate memory for the class in the method area;
    3. Parsing the constant pool reference symbols into reference (this step may also be used to further variables, i.e. lazy loading)
  3. initialization:
    • If the class of the parent class has not been initialized, then initialize the parent class;
    • If there is a class initialization method <clinit>(), then perform this method (method for initializing generated by the compiler, the programmer can not be manually added in the Java source code);
  4. Create an object, if the program found the following keywords new, newInstance, clone, getObjectwhen, it means you need to create an object in the heap memory, calls to create an object <init>()method (corresponding to the class constructor), executed before the initialization method must call the parent class initialization method;
  5. The end of the object, if an object is no longer referenced, it will be garbage collected in the garbage collection program execution, when an object collected garbage collector will call its explicit void finalize()method (if defined, then the method );
  6. Class of unloading, if a class is no longer used, it will be garbage collected. Only ClassLoader loaded user-defined class will be unloaded, BootStrapClassLoader loaded class can not be uninstalled.

Wherein steps 1 through 3 above may be collectively referred to as class initialization, class initialization may occur only in the following five cases (class initialization only once, if the class has been initialized and is not unloaded, the next use do not need to be initialized):

  1. Encountered new, getstatic, putstatic, invokestaticwhen the keyword;
  2. Use java.lang.reflectpackage reflecting the class when invoked;
  3. When initializing a class, if the parent class is not initialized parent class will be initialized;
  4. When the virtual machine is started, it contains main()the class method will be initialized;
  5. When using a dynamic language support JDK1.7 if a java.lang.invoke.MethodHandlefinal example is the analysis result REF_getStatic, REF_putStatic, REF_invokeStaticthe method handle time;

Basic concepts classloader

Class loader to be discussed in this article is the first step in the life cycle of corresponding class of: loading.

As the name suggests, it is the role of the class loader to load a Java byte code data into the JVM, and generates an java.lang.Classinstance of the class. Each such instance of a Java class used to represent, by this example newInstance()method can be used to create an object of that class.

We can java.lang.ClassLoaderbe loading data to a byte code class, which includes the following major class loading and related methods:

method Explanation
getParent() Returns the parent class loader class loader
loadClass(String name) Loading a class name for the name, the result returned is an instance of class java.lang.Class
findClass(String name) Find a name for the name of the class, the result returned is an instance of class java.lang.Class
findLoadedClass(String name) Find the name had already been loaded class name of the returned result is an instance of class java.lang.Class
defineClass(String name, byte[] b, int off, int len) Converting the content into a byte array b Java classes, the returned result is an instance of class java.lang.Class. This method is declared as final
resolveClass(Class<?> c) Link specified Java class

The core of which is the method is defineClassa method, which is responsible for a series of bytes of data into a binary code Classinstance of the class, whether these come from somewhere in the bytecode.

2. JVM class loader provided

System class loader is provided by the JVM, can be used as a class loader, class loader in the JVM system has the following three:

  1. Bootstrap class loader (class Bootstrap Loader) : It is used to load the Java core libraries, the loader is implemented by C ++, not inherited from java.lang.ClassLoader. It is responsible for loading Java Foundation Classes, mainly %JRE_HOME/lib/under the directory rt.jar, , resources.jarr charsets.jaand classso on, if you want to use the bootstrap class loader to load our own jar package, you can use the following ways to achieve

    我们可以在运行时使用如下参数:
    
    -Xbootclasspath:完全取代系统Java classpath.最好不用。
    -Xbootclasspath/a: 在系统class加载后加载。一般用这个。
    -Xbootclasspath/p: 在系统class加载前加载,注意使用,和系统类冲突就不好了.
    win32     java -Xbootclasspath/a: some.jar;some2.jar;  -jar test.jar
    unix          java -Xbootclasspath/a: some.jar:some2.jar:  -jar test.jar
    win32系统每个jar用分号隔开,unix系统下用冒号隔开
    
  2. Extension class loader (Extensions class Loader) : It is used to load a Java extension library, mostly %JRE_HOME/lib/extjar and class files in the directory, you may need to load the jar are thrown %JRE_HOME%/lib/extbelow, jar package in this directory will Bootstrap Classloader after work to load the Extension Classloader.
  3. System class loader (class System Loader) : It is the Java class according to the class to load Java application path (CLASSPATH). In general, class Java applications are made it to finish loading, and can ClassLoader.getSystemClassLoader()acquire it. If you want to make the specified jar is loaded, only need to MANIFEST.MFadd the following code: Class-Path: lib/demo.jar lib/demo1.jarit can add to the specified jar in the CLASSPATH.

Wherein, Bootstrap ClassLoader initiated by the JVM, and the initialization sun.misc.Launcher, sun.misc.Launcher initialization Extension ClassLoader, App ClassLoader. In addition to Bootstrap ClassLoader, the rest of the class loader itself is loaded by another class loader, so a parent class loader class loader is the loader that loaded the class loader. In the JVM loader provided, the parent class loader system class loader is to extend the class loader, the parent class loader extension class loader is the bootstrap class loader.

3. custom class loader

If the JVM offers the class loader can not meet our needs, then we need to implement your own class loader.

Custom class loader is very simple, just by calling the ClassLoaderclass Class<?> java.lang.ClassLoader.defineClass(String name, byte[] b, int off, int len)method can be, but because the process is finaland protectedso we must inherit ClassLoaderthe class and use the super.xxx()format to call. Here is a demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Method;

public class {

public static void main (String [] args) throws Exception {
ClassLoaderSub classLoaderSub = new new ; ClassLoaderSub ()
<?> = classLoaderSub.getClassByFile clazz Class ( "C: \ the Users \ ADMIN \ Desktop \ that A.class" );
the System.out .println ( "class name:" + clazz.getName ());
System.out.println ( "class loader:" + clazz.getClassLoader ());
Object obj = clazz.newInstance ();
Method, Method = clazz.getMethod ( "Test" );
Method.invoke (obj, null large column   appreciated that the Java class loader PAN>);
}

}

class ClassLoaderSub extends ClassLoader {


* Call defineClass parent instance to generate Class
* @param name
* @param B
* @param OFF
* @param len
* @return
* / public Class <?> DefineClassByName (String name, byte [] B, int OFF, int len) { Class clazz = <?> Super .defineClass (name, B, OFF, len); return clazz; }






* Read byte code file and convert it into a byte array
*
* @param fileName
* @return
* @throws Exception
* /
( "the finally" ) public Class <?> GetClassByFile (String fileName) throws Exception { File classFile = new new File (fileName); byte bytes [] = new new byte [ 1024 * 100 ]; the FileInputStream FIS = null ; <?> Class clazz = null ; the try { FIS =






new FileInputStream(classFile);
int j = 0;
while (true) {
int i = fis.read(bytes);
if (i == -1)
break;
j += i;
}
clazz = defineClassByName(null, bytes, 0, j);
} finally {
fis.close();
return clazz;
}
}
}

A.class's very simple, the source code for compilation as follows:

1
2
3
4
5
6
7
public  class  A  {

public void test() {
System.out.println("我被加载成功并且方法执行了!");
}

}

执行main()方法,打印出以下内容:

类的名字:A
类的加载器:ClassLoaderSub@15db9742
我被加载成功并且方法执行了!

以上代码的主要功能就是把 A.class的字节码读入到JVM中并且创建一个对应该字节码所对应的类的Class实例。然后根据该类来创建一个该类的对象并且调用其test()方法,方法成功执行。自定义的类加载器的核心组件就是defineClass方法,这个需要重点理解。

4.类加载器的树状组织结构

如果把JVM类加载器和自定义类加载器结合起来看的话,那么会构成一个继承的层次结构。我们已经知道,JVM的三个类加载器有继承关系,那么加上自定义类加载器之后继承关系会变成什么样呢,下面这张图很清晰的描述了这种结构

Java class loader structure

由于这种目录结构,JVM提出了类加载器的双亲委派机制,即

  • 如果某个类加载器需要加载一个类,那么此类加载器会调用它的父类加载器来加载这个类(如果某个类加载器的父类加载器为 null,那么就直接调用bootstrap class loader来进行类加载操作),一直向上直到bootstrap class loader被调用了,那么bootstrap class loader不会再调用父类加载器(也没有可以调用的),而是会自己对该类进行加载;
  • 如果bootstrap class loader的类加载操作失败了,那么就会调用其子类加载器进行加载;如果还是失败,就继续向下调用,直到成功为止。如果一直无法成功,则会抛出找不到类的异常。

双亲委派机制保证了JVM的安全性,因为恶意程序无法把自己伪造成JVM所信任的类。例如,我伪造了一个java.lang.Object类,想让JVM把它加载进去,但是由于双亲委派机制的存在,JVM默认会使用bootstrap class loader来加载java.lang.Object类,而因为bootstrap class loader默认会加载%JRE_HOME/lib/下的 java.lang.Object 文件,所以我的攻击自然失效。

那么,如果我更换一种攻击方式呢。我想让启动类加载器加载一个由我书写的名为java.lang.Attack的带有攻击代码类,那么我的攻击能成功吗?答案是不能。因为对于不同的类加载器所加载的类,它们将属于不同的运行时包。运行时包这个词在《Java虚拟机规范第2版》中第一次出现,如果两个类是由不同的类加载器进行加载的,那么他们就不可以进行相互访问。更典型的,如果我使用了两个类加载器加载了同一个类,那么这两个类是不一样的,如果让这两个类之中的某一个类的对象由另一个类来进行强制类型转换,会产生异常。

5. 关于Class.forName()方法:

Class.forName() 是一个静态方法,同样可以用来加载类。该方法有两种形式:Class.forName(String name, boolean initialize, ClassLoader loader)Class.forName(String className)。第一种形式的参数 name表示的是类的全名,initialize表示是否是初始化类,loader表示加载时使用的类加载器;第二种形式则相当于设置了参数 initialize的值为 true,loader的值为当前类的类加载器。

Class.forName()方法本身已经包含了类的加载过程。除此之外,Class.forName()还包括了第0节中的第2、3步操作,也就是说Class.forName()方法不仅会加载一个类,还会初始化这个类。这个方法一般被用于加载数据库的驱动,我们可以打开MySQL的驱动com.mysql.jdbc.Driver的源码看一下,可以发现如下代码:

1
2
3
4
5
6
7
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}

As static block code can only be performed in the case of initialization, you can use the Class.forName()method to load the database driver. If you simply use ClassLoader to load the database driver, because of the lack of action class initialization, the driver will fail to load.

reference:

  1. Java class loader depth study
  2. Depth Java Virtual Machine (the original book version 2)
  3. Dynamically loaded class files - Java integrated - Java - ITeye Forum
  4. Run jar application references are four ways other jar package
  5. Illustrates classloader class loading process, and custom ClassLoader
  6. Depth analysis of the Java ClassLoader principle
  7. Using the methods and examples URLClassLoader

Guess you like

Origin www.cnblogs.com/lijianming180/p/12389211.html
Recommended