文章目录
0、前置思考
0.1、类的唯一性
在Java中,对于任意一个类,都需要由加载它的类加载器对象和这个类本身一同确立其在Java虚拟机中的唯一性。
比如 tomcat 两个web应用互相不影响,就可以用两个不用的类加载器分别加载两个应用的class文件。
这里需要着重说3点
- Java 中类的唯一性需要由 类加载器对象+class文件(包路径+名称) 唯一确定
- 类加载器也可以认为是一个类,Java自带的三个 启动类加载器、扩展类加载器、应用程序类加载器的初始化由JVM保证,是全局唯一的,此时只需保证 class 的包路径唯一即可保证加载的是同一个类
- 自定义类加载器也是一个类,先初始化这个类,然后再用这个类去加载指定目录下的类。此时需要自己决定实例化几个自定以类加载器。比如tomcat,每一个web应用、每一个jsp页面使用一个类加载器对象,这样实现了同路经类的其实不同,进而实现了web应用的相互隔离、Jsp页面的热部署。
- 同一个唯一的类,不允许重复加载,要确保全局唯一。按照双亲委派模型不会有这个问题,自定义的话,要注意先从已加载类中获取,没有的话,再走自定义加载器的逻辑为好。
0.2、类加载器加载的是 .class 文件
默认的启动类加载器、扩展类加载器、应用系统类加载器各有默认的加载目录。
自定义类加载类可以指定自定义的目录。
0.2.1、获取class文件的方法
- IDEA 编译、运行就会自动生成
- 可以使用Java命令
javac Hello.java 得到 Hello.class
- 可以直接识别 jar包,包路径会转化为文件夹结构
比如 import com.alibaba.fastjson.JSON 对应
com\alibaba\fastjson\JSON.class
0.3、需要考虑用户自定义加载类不影响Jdk基础类,否则会造成混乱
1、JVM 类加载机制
1.1、BootstrpLoader (启动类加载器)
1.1.1、实现类:BootstrpLoader是C++编写的,逻辑上看没有实现类
Bootstrp loader是C++编写的,所以如果在Java语言中获取这个类加载器,会获得null,即逻辑上并不存在BootstrapLoader的类实体。
Jdk底层会自己处理,它是在Java虚拟机启动后初始化的
1.1.2、BootstrpLoader 作用范围
- 加载%JAVA_HOME%/jre/lib 目录下的类,
并且
被虚拟机识别(仅按照文件名) - -Xbootclasspath 参数指定的路径 ,
并且
被虚拟机识别(仅按照文件名)
1.1.3、直接使用 BootstrpLoader
直接把类加载器赋值为 null,但是考虑到 BootstrpLoader 专门用于加载 jdk 底层的一些类库,又有路径和名称限制,这种使用场景基本可以忽略。
ClassLoader cl = null;
1.2、ExtClassLoader(扩展类加载器)
1.2.1、实现类:sun.misc.Launcher$ExtClassLoader
1.2.2、ExtClassLoader作用范围
- 加载%JAVA_HOME%/lib/ext 目录下的类
- java.ext.dirs 参数指定的路径
1.2.3、直接使用 ExtClassLoader
可以直接使用ExtClassLoader,获取方式是,系统类加载器的父加载器。
//获取Test类的类加载器 sun.misc.Launcher$AppClassLoader@4dc63996
ClassLoader c = ClassLoader.getSystemClassLoader();
//获取c这个类加载器的父类加载器 sun.misc.Launcher$ExtClassLoader@28a418fc
ClassLoader c1 = c.getParent();
1.3、ApplicationClassLoader(应用程序类加载器/系统类加载器)
1.3.1、实现类:sun.misc.Launcher$AppClassLoader
1.3.2、ApplicationClassLoader 作用范围
- 用户路径(ClassPath)上所指定的类库,比如 /WEB-INF/classes
1.3.3、直接使用 ExtClassLoader
- 获取
ClassLoader cl = ClassLoader.getSystemClassLoader();
- 一般而言也是默认的,即在没有指定自定义类加载器时,一般类都是由 ApplicationClassLoader 加载的
ClassLoader c = Test.class.getClassLoader();
1.4、查看一个普通类的类加载器、父“类加载器”
/**
* 获取类加载器的测试方法
*/
@Test
public void test2() {
//获取Test类的类加载器 sun.misc.Launcher$AppClassLoader@4dc63996
ClassLoader c = Test.class.getClassLoader();
System.out.println(c);
//获取c这个类加载器的父类加载器 sun.misc.Launcher$ExtClassLoader@28a418fc
ClassLoader c1 = c.getParent();
System.out.println(c1);
// getClassLoader() returning null indicates the bootstrap ClassLoader
//获取c1这个类加载器的父类加载器 ,null,因为Bootstrp loader是C++编写的,依java的观点来看,逻辑上并不存在Bootstrap Loader的类实体
//根装载器:Bootstrp loader
//用C++语言写的,它是在Java虚拟机启动后初始化的,主要负责加载%JAVA_HOME%/jre/lib,
//* -Xbootclasspath参数指定的路径
ClassLoader c2 = c1.getParent();
System.out.println(c2);
//获取系统默认的ClassLoader sun.misc.Launcher$AppClassLoader@4dc63996
ClassLoader c3=ClassLoader.getSystemClassLoader();
System.out.println(c3);
//获取创建当前线程的类加载器
ClassLoader c4= Thread.currentThread().getContextClassLoader();
System.out.println(c4);
}
2、 双亲委派模型
简单说就是,先由自己的父类加载需要的类,一直向上传递,如果没有再由自己加载
类加载器可以重写,但是核心类是不允许使用自己的类加载器加载的,比如 jdk 核心包 java.lang.String ,只允许 bootstrap ClassLoader 进行加载
类加载器 | 加载目录 | 功能 | 举例 |
---|---|---|---|
BootStrap Class Loader | jre/lib/ | 称为启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等 | |
Extension Class Loader | jre/lib/ext/ | 称为扩展类加载器,负责加载Java的扩展类库 | |
App Class Loader | classpath目录下或者 -classpath 参数指定的包 | 称为系统类加载器 | Tomcat Bootstrap 类即由 System Class Loarder 加载 |
2.1、Mac 查看 JDK 安装目录
举例 /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home
/usr/libexec/java_home -V
3、自定义类加载器(自定义类指定目录,className包含package)
自定义类指定目录,className包含package
3.1、 extends ClassLoader
自定义类加载器的原则:组合而非继承
这里类加载器之间的父子关系一般不会以继承的关系来实现,而是都使用组合关系来复用父加载器的代码。
这意味着,当你在自定义类加载器时,也应该先委托父加载器即App ClassLoader进行加载。
那么问题来了,既然双亲委派模型只是一个规范,那我可以直接使用自定义加载器加载 String 类吗?答案是:不可以。因为JVM会检测,即使你不遵守双亲委派模型,你也无法加载核心类库的类,JVM自己会检测。
3.2、自定义类加载器
我们只需要继承 ClassLoader 然后覆盖其中的 findClass(name) 方法即可
3.2.1、不再建议覆盖重写 loadClass
loadClass 内部预留了 findClass 方法,应该在findClass中实现自定义逻辑
loadClass 内部,已经遵循了下面的逻辑
是否已加载(缓存)
-未加载
-父加载器为null
-是,使用 BootstrpLoader 加载
-否,使用父类加载器加载
-父类加载器加载完毕后,class还是空?
-c=findClass(name); 即本加载器扩展的 findClass 逻辑
3.2.2、自定义类加载器
自定义类指定目录,className包含package
import java.io.FileInputStream;
import java.lang.reflect.Method;
/**
* @Title:自定义类加载器
* @Description:
* @Analysis:
* @Copyright: Copyright(c)2022
* @Company: bestcxx
* @Author: jie.wu
* @Updatedby:
*/
public class MyClassLoader extends ClassLoader{
/**自定义类指定目录,className包含package*/
private String classpath;
public MyClassLoader(String classpath) {
this.classpath = classpath;
}
/**
* 直接调用该方法,可以违反双亲委派模型
* 若遵循双亲委派模型,则应调用自定义类的 loadClass方法
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
//如果已经加载过,则不需要从新加载
Class<?> LoadedClass = findLoadedClass(name);
if(Objects.nonNull(LoadedClass)){
return LoadedClass;
}
byte[] data = getData(name);
return defineClass(name,data,0,data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}
private byte[] getData(String name) throws Exception{
name = name.replaceAll("\\.", "/");
FileInputStream fis = new FileInputStream(classpath+"/"+name+".class");
int len = fis.available();
byte[] data = new byte[len];
fis.read(data);
fis.close();
return data;
}
3.2.3、自定义类加载器的使用
3.2.3.1、遵循双亲委派模型(调用自定义类加载器的 loadClass 方法)
loadClass 内部按照下面顺序:
0、缓存
1、启动类加载器加载
2、拓展类加载器加载
3、应用系统类加载器加载(classpath目录)
4、findClass 方法(指定目录下的class文件)
- 如果 classpath下存在 Del 类,输出结果为
sun.misc.Launcher$AppClassLoader
你调用了方法 method()
- 如果 classpath下不存在 Del 类,输出结果为
MyClassLoader
你调用了方法 method()
- 代码(调用自定义类加载器的 loadClass 方法)
import java.io.FileInputStream;
import java.lang.reflect.Method;
/**
* @Title:自定义类加载器
* @Description:
* @Analysis:
* @Copyright: Copyright(c)2022
* @Company: bestcxx
* @Author: jie.wu
* @Updatedby:
*/
public class MyClassLoader extends ClassLoader{
/**自定义类指定目录,className包含package*/
private String classpath;
public MyClassLoader(String classpath) {
this.classpath = classpath;
}
/**
* 直接调用该方法,可以违反双亲委派模型
* 若遵循双亲委派模型,则应调用自定义类的 loadClass方法
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
//如果已经加载过,则不需要从新加载
Class<?> LoadedClass = findLoadedClass(name);
if(Objects.nonNull(LoadedClass)){
return LoadedClass;
}
byte[] data = getData(name);
return defineClass(name,data,0,data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}
private byte[] getData(String name) throws Exception{
name = name.replaceAll("\\.", "/");
FileInputStream fis = new FileInputStream(classpath+"/"+name+".class");
int len = fis.available();
byte[] data = new byte[len];
fis.read(data);
fis.close();
return data;
}
public static void main(String[] args) throws Exception {
String classpath = "E:\\";
MyClassLoader myClassLoader = new MyClassLoader(classpath);
Class<?> cl = myClassLoader.loadClass("com.Del");
System.out.println(cl.getClassLoader().getClass().getName());
Object o = cl.newInstance();
Method method=cl.getMethod("method", null);
method.invoke(o, null);
}
}
3.2.3.2、违反双亲委派模型(直接调用 findClass 方法)
findClass 内部直接按照指定目录去加载目标类了,因此加载器必然为自定义类加载器。
但是,需要注意的是,如果已经加载了一个唯一的类,再次直接用findClass 会报错
- 代码(调用自定义类加载器的 findClass方法)
import java.io.FileInputStream;
import java.lang.reflect.Method;
/**
* @Title:自定义类加载器
* @Description:
* @Analysis:
* @Copyright: Copyright(c)2022
* @Company: bestcxx
* @Author: jie.wu
* @Updatedby:
*/
public class MyClassLoader extends ClassLoader{
/**自定义类指定目录,className包含package*/
private String classpath;
public MyClassLoader(String classpath) {
this.classpath = classpath;
}
/**
* 直接调用该方法,可以违反双亲委派模型
* 若遵循双亲委派模型,则应调用自定义类的 loadClass方法
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
//如果已经加载过,则不需要从新加载
Class<?> LoadedClass = findLoadedClass(name);
if(Objects.nonNull(LoadedClass)){
return LoadedClass;
}
byte[] data = getData(name);
return defineClass(name,data,0,data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}
private byte[] getData(String name) throws Exception{
name = name.replaceAll("\\.", "/");
FileInputStream fis = new FileInputStream(classpath+"/"+name+".class");
int len = fis.available();
byte[] data = new byte[len];
fis.read(data);
fis.close();
return data;
}
public static void main(String[] args) throws Exception {
String classpath = "E:\\";
MyClassLoader myClassLoader = new MyClassLoader(classpath);
//遵循双亲委派模型-找不到采用自定义类加载器加载
//Class<?> cl = myClassLoader.loadClass("com.Del");
//直接使用自定义类加载器加载
Class<?> cl = myClassLoader.findClass("com.Del");
System.out.println(cl.getClassLoader().getClass().getName());
Object o = cl.newInstance();
Method method=cl.getMethod("method", null);
method.invoke(o, null);
}
}
3.2.4、类加载器与类的唯一性验证
验证3点
1、双亲委派模型下,通过 自定义类加载器的 loadClass 方法加载 的类 的类加载器未必是自定义类加载器-这个上面已经验证
2、自定义类加载了类(不是由父类加载器加载,不是情况1),不同的自定义类加载器加载的类的是不同的类。
3、同一个类加载器实例化的两个类加载器对象,加载同一个类(不是由父类加载器加载的,不是情况11),被加载的类是不同的类
- 代码(建造两个自定义类加载器,直接使用 findClass 加载同一个测试class文件,比较二者是不是一个类,验证结果为否)
-比较类
import java.io.FileInputStream;
import java.util.Objects;
/**
* @Title:自定义类加载器 标胶类
* @Description:
* @Analysis:
* @Copyright: Copyright(c)2022
* @Company: bestcxx
* @Author: jie.wu
* @Updatedby:
*/
public class My2ClassLoader extends ClassLoader{
/**自定义类指定目录,className包含package*/
private String classpath;
public My2ClassLoader(String classpath) {
this.classpath = classpath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
//如果已经加载过,则不需要从新加载
Class<?> LoadedClass = findLoadedClass(name);
if(Objects.nonNull(LoadedClass)){
return LoadedClass;
}
byte[] data = getData(name);
return defineClass(name,data,0,data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}
private byte[] getData(String name) throws Exception{
name = name.replaceAll("\\.", "/");
FileInputStream fis = new FileInputStream(classpath+"/"+name+".class");
int len = fis.available();
byte[] data = new byte[len];
fis.read(data);
fis.close();
return data;
}
}
import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.util.Objects;
/**
* @Title:自定义类加载器
* @Description:
* @Analysis:
* @Copyright: Copyright(c)2022
* @Company: bestcxx
* @Author: jie.wu
* @Updatedby:
*/
public class MyClassLoader extends ClassLoader{
/**自定义类指定目录,className包含package*/
private String classpath;
public MyClassLoader(String classpath) {
this.classpath = classpath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
//如果已经加载过,则不需要从新加载
Class<?> LoadedClass = findLoadedClass(name);
if(Objects.nonNull(LoadedClass)){
return LoadedClass;
}
byte[] data = getData(name);
return defineClass(name,data,0,data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}
private byte[] getData(String name) throws Exception{
name = name.replaceAll("\\.", "/");
FileInputStream fis = new FileInputStream(classpath+"/"+name+".class");
int len = fis.available();
byte[] data = new byte[len];
fis.read(data);
fis.close();
return data;
}
public static void main(String[] args) throws Exception {
String classpath = "E:\\";
MyClassLoader myClassLoader = new MyClassLoader(classpath);
Class<?> cl = myClassLoader.findClass("com.Del");
My2ClassLoader myClassLoader2 = new My2ClassLoader(classpath);
Class<?> cl2 = myClassLoader2.findClass("com.Del");
System.out.println(cl==cl2);//false
//System.out.println(cl.getClassLoader().getClass().getName());
Object o = cl.newInstance();
Method method=cl.getMethod("method", null);
method.invoke(o, null);
}
}
- 代码(使用一个自定义类加载器,声明俩对象,分别加载同一个测试class文件,比较二者是不是一个类,验证结果为否)
import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.util.Objects;
/**
* @Title:自定义类加载器
* @Description:
* @Analysis:
* @Copyright: Copyright(c)2022
* @Company: bestcxx
* @Author: jie.wu
* @Updatedby:
*/
public class MyClassLoader extends ClassLoader{
/**自定义类指定目录,className包含package*/
private String classpath;
public MyClassLoader(String classpath) {
this.classpath = classpath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
//如果已经加载过,则不需要从新加载
Class<?> LoadedClass = findLoadedClass(name);
if(Objects.nonNull(LoadedClass)){
return LoadedClass;
}
byte[] data = getData(name);
return defineClass(name,data,0,data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}
private byte[] getData(String name) throws Exception{
name = name.replaceAll("\\.", "/");
FileInputStream fis = new FileInputStream(classpath+"/"+name+".class");
int len = fis.available();
byte[] data = new byte[len];
fis.read(data);
fis.close();
return data;
}
public static void main(String[] args) throws Exception {
String classpath = "E:\\";
MyClassLoader myClassLoader = new MyClassLoader(classpath);
Class<?> cl = myClassLoader.findClass("com.Del");
MyClassLoader myClassLoader2 = new MyClassLoader(classpath);
Class<?> cl2 = myClassLoader2.findClass("com.Del");
System.out.println(cl==cl2);//false
//System.out.println(cl.getClassLoader().getClass().getName());
Object o = cl.newInstance();
Method method=cl.getMethod("method", null);
method.invoke(o, null);
}
}
- 代码(使用一个自定义类加载器,声明一个对象,加载同一个测试class文件两次,比较二者是不是一个类,验证结果为是)
import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.util.Objects;
/**
* @Title:自定义类加载器
* @Description:
* @Analysis:
* @Copyright: Copyright(c)2022
* @Company: bestcxx
* @Author: jie.wu
* @Updatedby:
*/
public class MyClassLoader extends ClassLoader{
/**自定义类指定目录,className包含package*/
private String classpath;
public MyClassLoader(String classpath) {
this.classpath = classpath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
//如果已经加载过,则不需要从新加载
Class<?> LoadedClass = findLoadedClass(name);
if(Objects.nonNull(LoadedClass)){
return LoadedClass;
}
byte[] data = getData(name);
return defineClass(name,data,0,data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}
private byte[] getData(String name) throws Exception{
name = name.replaceAll("\\.", "/");
FileInputStream fis = new FileInputStream(classpath+"/"+name+".class");
int len = fis.available();
byte[] data = new byte[len];
fis.read(data);
fis.close();
return data;
}
public static void main(String[] args) throws Exception {
String classpath = "E:\\";
MyClassLoader myClassLoader = new MyClassLoader(classpath);
//Class<?> cl = myClassLoader.loadClass("com.Del");
Class<?> cl = myClassLoader.findClass("com.Del");
Class<?> cl2 = myClassLoader.findClass("com.Del");
System.out.println(cl==cl2);
//System.out.println(cl.getClassLoader().getClass().getName());
Object o = cl.newInstance();
Method method=cl.getMethod("method", null);
method.invoke(o, null);
}
}
4、使用自定义类加载器加载 jar/.class 文件
上面的内容都是围绕 .class 文件进行加载的,这里提供一个更加贴近实战的方法,即从 jar 文件中加载。
4.1、准备
-
扫描的文件结构为
E:\myclassloader
lib\fastjson-1.2.78.jar
classes\com\Del.class -
测试用 jar
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
</dependencies>
4.2、自定义类加载器——扫描Jar文件 +.class 文件
import java.io.*;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* @Title:自定义类加载器-扫描 jar
* @Description:
* lib = classpath + "lib/ 放 jar 文件";
* classes = classpath + "classes/ 放 .class 文件";
* @Analysis:
* @Copyright: Copyright(c)2022
* @Company: bestcxx
* @Author: jie.wu
* @Updatedby:
*/
public class MyClassLoader extends ClassLoader {
/**
* lib:表示加载的文件在jar包中
* 类似tomcat就是{PROJECT}/WEB-INF/lib/
*/
private String lib;
/**
* classes:表示加载的文件是单纯的class文件
* 类似tomcat就是{PROJECT}/WEB-INF/classes/
*/
private String classes;
/**
* 采取将所有的jar包中的class读取到内存中
* 然后如果需要读取的时候,再从map中查找
*/
private Map<String, byte[]> map;
public MyClassLoader(String classpath) {
lib = classpath + "lib/";
classes = classpath + "classes/";
map = new HashMap<String, byte[]>(64);
preReadJarFile();
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
//如果已经加载过,则不需要从新加载
Class<?> LoadedClass = findLoadedClass(name);
if (Objects.nonNull(LoadedClass)) {
return LoadedClass;
}
byte[] data = getClassFromFileOrMap(name);
return defineClass(name, data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}
/**
* 从指定的classes文件夹下找到文件
*
* @param name
* @return
*/
private byte[] getClassFromFileOrMap(String name) {
String classPath = classes + name.replace('.', File.separatorChar) + ".class";
File file = new File(classPath);
if (file.exists()) {
InputStream input = null;
try {
input = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int bytesNumRead = 0;
while ((bytesNumRead = input.read(buffer)) != -1) {
baos.write(buffer, 0, bytesNumRead);
}
return baos.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} else {
if (map.containsKey(name)) {
//去除map中的引用,避免GC无法回收无用的class文件
return map.remove(name);
}
}
return null;
}
/**
* 预读lib下面的包
*/
private void preReadJarFile() {
List<File> list = scanDir();
for (File f : list) {
JarFile jar;
try {
jar = new JarFile(f);
readJAR(jar);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 读取一个jar包内的class文件,并存在当前加载器的map中
*
* @param jar
* @throws IOException
*/
private void readJAR(JarFile jar) throws IOException {
Enumeration<JarEntry> en = jar.entries();
while (en.hasMoreElements()) {
JarEntry je = en.nextElement();
String name = je.getName();
if (name.endsWith(".class")) {
String clss = name.replace(".class", "").replaceAll("/", ".");
if (this.findLoadedClass(clss) != null) {
continue;
}
InputStream input = jar.getInputStream(je);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int bytesNumRead = 0;
while ((bytesNumRead = input.read(buffer)) != -1) {
baos.write(buffer, 0, bytesNumRead);
}
byte[] cc = baos.toByteArray();
input.close();
map.put(clss, cc);//暂时保存下来
}
}
}
/**
* 扫描lib下面的所有jar包
*
* @return
*/
private List<File> scanDir() {
List<File> list = new ArrayList<File>();
File[] files = new File(lib).listFiles();
for (File f : files) {
if (f.isFile() && f.getName().endsWith(".jar"))
list.add(f);
}
return list;
}
/**
* 添加一个jar包到加载器中去。
*
* @param jarPath
* @throws IOException
*/
public void addJar(String jarPath) throws IOException {
File file = new File(jarPath);
if (file.exists()) {
JarFile jar = new JarFile(file);
readJAR(jar);
}
}
public static void main(String[] args) throws Exception {
String classpath = "E:\\myclassloader\\";
MyClassLoader myClassLoader = new MyClassLoader(classpath);
Class<?> cl = myClassLoader.findClass("com.alibaba.fastjson.JSON");
Class<?> c2 = myClassLoader.findClass("com.Del");
System.out.println(cl.getClassLoader().getClass().getName());
System.out.println(c2.getClassLoader().getClass().getName());
}
}