您的位置:首页 > 其它

JVM类加载器

2015-11-03 20:05 211 查看
一:类加载器的层次结构
1、引导类加载器:用来加载java的核心库。
2、扩展类加载器:用来加载java的扩展库。实现类:sun.misc.Launcher$ExtClassLoader
3、应用类加载器:加载本应用所需要的类。实现类:sun.misc.Launcher$AppClassLoader
4、自定义类加载器
注意:1-4依次是后者的父类,但不是通过继承来实现的,而是通过组合来实现的
 1不是用java实现的,而是用c语言,后面三者都是用java语言实现的,都实现了java.lang.ClassLoader类

二:类加载采用代理模式
一般的类加载使用双亲委托机制,这样做主要是为了安全。如程序员定义的java.lang.String永远都不能被加载。
并不是所有的都是使用双亲委托机制。

三:ClassLoader常用方法:
getParent() 
loadClass(String name) 
findClass(String name) 
findLoadedClass(String name) 
defineClass(String name, byte[] b, int off, int len) 
resolveClass(Class<?> c) 

四:自定义类加载器
继承java.lang.ClassLoader 重写findClass(String name)方法
1、文件类自定义加载器
2、网络类自定义加载器
两者操作差不多,只是.class文件源头一个来自于文件,一个来自于url指定的服务器。
加密的类加载器:就是用一定的算法,先对.class文件进行加密操作,然后用相应的解密算法解密并进行类加载。
注意:同一个类被同一个类加载器加载会得到相同的Class对象
 同一个类被不同的类加载器加载会得到不同的Class对象

五:系统默认的类加载器是双亲委托机制,但并不是所有的类都要使用这种机制,如TOMCAT服务器就开始默认的类加载机制
而是使用自定义的类加载机制。
线程上线文类加载器,就可以用来获得当前线程的类加载器、修改当前线程的类加载器
Thread.currentThread().getContextClassLoader()获得当前线程的类加载器
Thread.currentThread().setContextClassLoader()设置当前线程的类加载器

1、文件类加载器:

package com.chen.File;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
* 自定义类加载器
* 1、文件类加载器
* @author CHJ
*
*/
public class FileSystemClassLoader extends ClassLoader{

// 加载路径。如:F:/New 中的  com.chen.Base_Points.First.class
private String rootDir;

public FileSystemClassLoader(String rootDir) {

this.rootDir = rootDir;
}

//重写方法
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {

Class<?> c = findLoadedClass(name);

if(c != null) {

return c;
}else{

// 这里为了简单不使用双亲委托模式
byte[] classData = getClassData(name);
if(classData == null) {

throw new ClassNotFoundException();
}else{

c = defineClass(name, classData, 0, classData.length);// defineClass为ClassLoader中的方法
}
}

return c;
}

/**
* 将制定的.class文件写入字节数组中
* @param name
* @return
*/
private byte[] getClassData(String name) {

// 拼出.class文件的完整路径
String path = rootDir + "/" + name.replace('.', '/') + ".class";
InputStream is = null;
ByteArrayOutputStream bos = null;
try {

is = new FileInputStream(path);
bos = new ByteArrayOutputStream();

byte[] buffer = new byte[1024];
int len = 0;
while((len = is.read(buffer)) != -1){

bos.write(buffer, 0, len);
}
bos.flush();

return bos.toByteArray();
} catch (Exception e) {

e.printStackTrace();
return null;
}finally{

try {
if(is != null) {

is.close();
}

if(is != null) {

bos.close();
}
} catch (IOException e) {

e.printStackTrace();
}

}

}
}

package com.chen.File;

public class Test {

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

FileSystemClassLoader loader = new FileSystemClassLoader("F:/New");
FileSystemClassLoader loader2 = new FileSystemClassLoader("F:/New");

Class<?> c1 = loader.loadClass("com.chen.Base_Points.First");
Class<?> c2 = loader.loadClass("com.chen.Base_Points.First");
Class<?> c3 = loader2.loadClass("com.chen.Base_Points.First");

Class<?> c4 = loader.loadClass("java.lang.String");

System.out.println(c1.hashCode());
System.out.println(c2.hashCode());// 同一个.class文件被同一个类加载器加载生成同一个Class对象
System.out.println(c3.hashCode());// 同一个.class文件被不同的类加载加载生成不同的Class对象

System.out.println(c1.getClassLoader());// 用自定义类加载器加载的
System.out.println(c4.getClassLoader());// 返回值为lang用引导构造器加载的

}
}

2、加密型文件类加载器:
加密算法:

package com.chen.File_Encryption;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
* 简单的加密工具(取反操作)
* @author Administrator
*
*/
public class EncryptionUtil {

/**
* 演示取反
* @param args
*/
public static void main(String[] args) {

int a = 3;// 二进制为00000011
// 转换成二进制
System.out.println(Integer.toBinaryString(a));// 11
// 取反(做异或运算)
System.out.println(Integer.toBinaryString(a^0xff));// 11111100
}

/**
* 加密方法:把一个文件中二进制全部取反
* @param src
* @param dest
*/
public static void Encryption(String src, String dest) {

InputStream is = null;
OutputStream os = null;

try {
is = new FileInputStream(src);
os = new FileOutputStream(dest);

int temp = -1;
while((temp = is.read()) != -1){

os.write(temp^0xff);// 取反操作
}
os.flush();

} catch (Exception e) {

e.printStackTrace();
}finally{

if(is != null){

try {
is.close();
} catch (IOException e) {

e.printStackTrace();
}
}

if(os != null){

try {
os.close();
} catch (IOException e) {

e.printStackTrace();
}
}
}

}
}

加密类加载器:
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
* 与加密类加载器相对应的解密类加载器
* @author CHJ
*
*/
public class DeEncryptonClassLoader extends ClassLoader {

// 加载路径。如:F:/New 中的  com.chen.Base_Points.First.class
private String rootDir;

public DeEncryptonClassLoader(String rootDir) {

this.rootDir = rootDir;
}

//重写方法
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {

Class<?> c = findLoadedClass(name);

if(c != null) {

return c;
}else{

// 这里为了简单不使用双亲委托模式
byte[] classData = getClassData(name);
if(classData == null) {

throw new ClassNotFoundException();
}else{

c = defineClass(name, classData, 0, classData.length);// defineClass为ClassLoader中的方法
}
}

return c;
}

/**
* 将制定的.class文件写入字节数组中
* @param name
* @return
*/
private byte[] getClassData(String name) {

// 拼出.class文件的完整路径
String path = rootDir + "/" + name.replace('.', '/') + ".class";
InputStream is = null;
ByteArrayOutputStream bos = null;
try {

is = new FileInputStream(path);
bos = new
4000
ByteArrayOutputStream();

/*
byte[] buffer = new byte[1024];
int len = 0;
while((len = is.read(buffer)) != -1){

bos.write(buffer, 0, len);
}
bos.flush();

return bos.toByteArray();
*/

int temp = -1;
while((temp = is.read()) != -1) {

bos.write(temp^0xff);// 取反
}
bos.flush();

return bos.toByteArray();
} catch (Exception e) {

e.printStackTrace();
return null;
}finally{
try{
if(is != null) {

is.close();
}

if(is != null) {

bos.close();
}
} catch (IOException e) {

e.printStackTrace();
}

}

}

}
</pre><pre name="code" class="java">

public class Test {

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

EncryptionUtil.Encryption("F:/New/HelloWorld.class", "F:/New/temp/HelloWorld.class");
System.out.println("加密成功");

// 用原来的类加载器加载加密的.class文件会报ClassFormatError
//FileSystemClassLoader loader = new FileSystemClassLoader("F:/New/temp");
//Class<?> c = loader.loadClass("HelloWorld");

// 下面使用解密的类加载器进行加载

// 注意:这里的.class文件是我用记事本写的,不导入任何包。如果加载的.class文件中有import..,注意导入需要的包,还要注意路径
DeEncryptonClassLoader loader = new DeEncryptonClassLoader("F:/New/temp");
Class<?> c = loader.loadClass("HelloWorld");
System.out.println(c.getClassLoader());
}
}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: