类加载器分层
1.引导类加载器,使用C++实现,位于rt.jar
2.扩展类加载器
3.应用类加载器
使用双亲委派机制,保证java核心库的安全
例如用户自定义一个java.lang.String类,该类在被加载的时候,会交由应用类加载器,应用类加载器再交由扩展类加载器,扩展类加载器交由引导类加载器,引导类加载器发现java核心库中已存在java.lang.String类,故不会加载用户自定义的java.lang.String类,从而保证了java核心库的安全
1.初识类加载器
public class Demo02 {
public static void main(String[] args) {
System.out.println(ClassLoader.getSystemClassLoader()); // 应用类加载器
System.out.println(ClassLoader.getSystemClassLoader().getParent()); //扩展类加载器
System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent()); // 引导类加载器,C++实现,此处无法获取,位于rt.jar
System.out.println(System.getProperty("java.class.path"));
System.out.println("====================================================");
// StringBak a = "gaogao";
// 根据双亲委派机制(代理模式的一种(自己的事交给别人来做)),用户自定义的String 在引导类加载器中已存在,故不会加载用户自定义的String,以抱着呢个java核心库的安全
// System.out.println(a.getClass().getClassLoader()); // null,即不会被加载
// System.out.println(a);
}
}
2.自定义文件系统类加载器
package com.bjsxt.test;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 自定义文件系统类加载器
* @author WL20180732
*
*/
public class FileSystemClassLoader extends ClassLoader {
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 {
ClassLoader parent = this.getParent();
try {
c = parent.loadClass(name); // 委派给父类加载器
} catch (Exception e) {
}
if (c != null) {
return c;
} else {
byte[] classData = getClassData(name);
if (classData == null) {
throw new ClassNotFoundException();
} else {
c = defineClass(name, classData, 0, classData.length);
return c;
}
}
}
}
private byte[] getClassData(String name) {
String path = rootDir + "/" + name.replace(".", "/") +".class";
InputStream is = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
is = new FileInputStream(path);
byte[] buffer = new byte[1024];
int len = 0;
while((len = is.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
return bos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
/**
* 测试自定义的FileSystemClassLoader
* @author WL20180732
*
*/
public class Demo03 {
public static void main(String[] args) throws ClassNotFoundException {
FileSystemClassLoader loader = new FileSystemClassLoader("E:/mycode");
FileSystemClassLoader loader2 = new FileSystemClassLoader("E:/mycode");
Class<?> c = loader.loadClass("Welcome");
Class<?> c2 = loader.loadClass("Welcome");
Class<?> c3 = loader2.loadClass("Welcome"); // 不同的类加载器加载同一个类文件,创建的是不同的类
Class<?> c4 = loader2.loadClass("java.lang.String");
Class<?> c5 = loader2.loadClass("com.bjsxt.test.Demo01");
System.out.println(c.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode()); // 同一个类,被不同的加载器加载,JVM也认为是不同的类
System.out.println(c3.getClassLoader()); // 自定义类加载器
System.out.println(c4.getClassLoader()); // 引导类加载器加载,返回 null
System.out.println(c5.getClassLoader()); // AppClassLoader加载
}
}
3.自定义网络类加载器
package com.bjsxt.test;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
/**
* 自定义网络类加载器
* @author WL20180732
*
*/
public class NetClassLoader extends ClassLoader {
private String rootUrl;
public NetClassLoader(String rootUrl) {
this.rootUrl = rootUrl;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> c = findLoadedClass(name);
// 应该要先查询有没有加载过这个类。如果已经加载,则直接返回。如果没有,则加载新类
if (c != null) {
return c;
} else {
ClassLoader parent = this.getParent();
try {
c = parent.loadClass(name); // 委派给父类加载器
} catch (Exception e) {
}
if (c != null) {
return c;
} else {
byte[] classData = getClassData(name);
if (classData == null) {
throw new ClassNotFoundException();
} else {
c = defineClass(name, classData, 0, classData.length);
return c;
}
}
}
}
private byte[] getClassData(String name) {
String path = rootUrl + "/" + name.replace(".", "/") +".class";
InputStream is = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
URL url = new URL(path);
is = url.openStream();
byte[] buffer = new byte[1024];
int len = 0;
while((len = is.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
return bos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
4.自定义加解密类加载器
package com.bjsxt.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 加密工具类
* @author WL20180732
*
*/
public class EncryptUtil {
public static void main(String[] args) {
encrypt(new File("E:/mycode/Welcome.class"), new File("E:/mycode/temp/Welcome.class"));
}
public static void encrypt(String src, String dest) {
encrypt(new File(src), new File(dest));
}
public static void encrypt(File src, File dest) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(src);
fos = new FileOutputStream(dest);
int temp = -1;
while((temp = fis.read()) != -1) {
fos.write(temp^0xff); //取反,加密
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
```java
package com.bjsxt.test;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 加载文件系统中加密后的字节码文件的类加载器
* @author WL20180732
*
*/
public class DecryptClassLoader extends ClassLoader {
private String rootDir;
public DecryptClassLoader(String rootDir) {
this.rootDir = rootDir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> c = findLoadedClass(name);
// 应该要先查询有没有加载过这个类。如果已经加载,则直接返回。如果没有,则加载新类
if (c != null) {
return c;
} else {
ClassLoader parent = this.getParent();
try {
c = parent.loadClass(name); // 委派给父类加载器
} catch (Exception e) {
}
if (c != null) {
return c;
} else {
byte[] classData = getClassData(name);
if (classData == null) {
throw new ClassNotFoundException();
} else {
c = defineClass(name, classData, 0, classData.length);
return c;
}
}
}
}
private byte[] getClassData(String name) {
String path = rootDir + "/" + name.replace(".", "/") +".class";
InputStream is = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
is = new FileInputStream(path);
int temp = -1;
while((temp = is.read()) != -1) {
bos.write(temp^0xff); //取反,解密
}
return bos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
package com.bjsxt.test;
/**
* 测试简单的加密解密(取反)操作
* @author WL20180732
*
*/
public class Demo04 {
public static void main(String[] args) throws ClassNotFoundException {
// 测试取反操作
// int a = 3; //011
// System.out.println(Integer.toBinaryString(a^0xff)); // 取反
// 加密后的class文件,正常的类加载器无法加载,报ClassFormatError
// FileSystemClassLoader loader = new FileSystemClassLoader("E:/mycode/temp");
// Class<?> c = loader.loadClass("Welcome");
// System.out.println(c);
//
DecryptClassLoader loader2 = new DecryptClassLoader("E:/mycode/temp");
Class<?> c2 = loader2.loadClass("Welcome");
System.out.println(c2);
}
}
```