三大类加载器
package com.classloader;
import sun.net.spi.nameservice.dns.DNSNameService;
/**
* 类加载器:
*编写的 .java文件需要先编译成 .class文件,当程序运行时,
*如果需要用到某个类,JVM 通过 类加载器ClassLoader 把对应的class文件加载到内存中,然后再执行代码
*
* 三大类加载器
* Bootstrap ClassLoader 启动类加载器、引导类加载器
* Extension ClassLoader 扩展类类加载器
* App ClassLoader 系统类加载器,应用类加载器
*/
public class Demo {
public static void main(String[] args) {
/**
* 1.Bootstrap ClassLoader 启动类加载器
* 下例子中输出null,原因: 因为Bootstrap ClassLoader是虚拟机JRE的一部分,不是Java类库中的某个类
* 既然不是一个类,就不能使用引用指向它
* 主要用于加载JDK核心类库,C++语言实现的,加载时的搜索路径是由 sun.boot.class.path 所指定的
* 比如:%JRE_HOME%\jre\lib下的rt.jar、resources.jar、charsets.jar等。
*
* 在运行/调试配置中添加VM选项进行修改
* -Xbootclasspath:路径 指定的路径会完全取代jdk核心的搜索路径 坚决不要用
* -Xbootclasspath/a:路径 指定的路径会在jdk核心类后搜索 可用
* -Xbootclasspath/p:路径 指定的路径会在jdk核心类前搜索 可用,不建议使用
*
*/
//输出null,表示Bootstrap ClassLoader
System.out.println(String.class.getClassLoader());
//获取扫描路径
String paths = System.getProperty("sun.boot.class.path");
String[] arr = paths.split(";"); //window是";",unix是":"
for (String path : arr) {
System.out.println(path);
}
/**
* 2.Extension ClassLoader 扩展类类加载器
* 配置路径:在运行/调试配置中添加VM选项
* 扩展类加载器,加载 -Djava.ext.dirs 选项指定的目录
* 比如: %JRE%\jre\lib\ext目录下的jar包和class文件
*
* 注意: 如果配置自定义路径,或覆盖默认路径
*/
// System.out.println(DNSNameService.class.getClassLoader());
// String paths = System.getProperty("java.ext.dirs");
// String[] arr = paths.split(";");
// for (String path : arr) {
// System.out.println(path);
// }
/**
*3. AppClassLoader 系统类加载器,又叫: 应用类加载器
* 它的搜索路径由java.class.path(CLASSPATH)来指定
* 主要用来加载程序中的类文件,及引用的第三放库
*
* AppClassLoader的父亲是Extension ClassLoader
* 父亲和父类不是同一个概念,父亲的儿子有getParent方法,而子类没有
*/
// System.out.println(Demo.class.getClassLoader());
// System.out.println(Demo.class.getClassLoader().getParent());
// //System.getProperty用于扫描路径
// String paths = System.getProperty("java.class.path");
// String[] arr = paths.split(";");
// for (String path : arr) {
// System.out.println(path);
// }
/**
* sun.misc.Launcher$AppClassLoader@18b4aac2
* sun.misc.Launcher$ExtClassLoader@74a14482
* 从显示的结果来看是Launcher$AppClassLoader类和Launcher$ExtClassLoader
* 这两个对象在哪初始化的呢?
* 搜索Launcher类发现getClassLoader方法也是在Launcher类中,是java应用程序的入口类
* 其实AppClassLoader和ExtClassLoader是Launcher的内部类
*/
}
}
双亲委派模式
package com.classloader;
public class Demo2 {
/**
*双亲委派模式
* 简称: 坑爹模式
* 即:如果一个类加载器要加载某个类,它并不会自己先去加载,而是让父加载器/父亲,则进一步向上委托,一次递归
* 最终将到达顶层的启动类加载器(Bootstrap ClassLoader)
* 如果父加载器可用完成加载任务,就成功返回
* 如果父加载器无法完成此加载任务,子加载器才会自己去加载
*/
/**
* 类的加载是在main方法之前执行的,查看Launcher.class 使用ctrl+n进行所有查询
* 所有类的加载都是要走 174处 loadClass(String var1, boolean var2)这个方法
* 在195处 return super.loadClass(var1, var2);下断点,不只是程序的类进行加载还有系统类要进行加载
* 所以调试时放过系统类加载 也就是恢复程序 F9,一直放过到出现var1="com.classloader.Demo2"
* 然后对loadClass(var1, var2)方法进行追踪(强制步入Alt+Shift+F7),从Launcher.class类跳转到ClassLoader类中
*
* 好处:
* 1.避免类的重复加载
* 2.保证java核心api不会被随意替换
* @param args
*/
public static void main(String[] args) {
System.out.println(Demo2.class.getClassLoader());
}
}
urlclassloader可以指定一串路径,然后在路径下面寻找要加载的类
package com.classloader;
/**
* URLClassLoader
* 是ExtClassLoader和AppClassLoader的父类
*它可以从指定的 jar 文件和目录中加载类和资源
*
* 使用:
* 1.创建对象
* 2.执行loadClass方法
*
* 构造方法:
* URLClassLoader(URL[] urls, ClassLoader parent):使用指定的父加载器创建对象,从指定的urls路径来查询、并加载类。
* URLClassLoader(URL[] urls):使用默认的父加载器(AppClassLoader)创建一个ClassLoader对象,从指定的urls路径来查询、并加载类。
*
* 需求:解析Excel,一般我们用poi,目前模板不确定,而且客户不希望每次改一种模板就重启应用。
* 解决:把解析代码抽出来,打成一个jar包,每次上传模板的时候,就选用指定的jar包运行,因为需要动态加载jar包,所以需要用到类加载器
* 最终利用反射对应的方法,获取结果。
*
*/
import java.io.File;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
/**
* 创建一个项目起名字为untitled7并创建一个com.test软件包
* 创建一个ParseExcel类内容为
* public class ParseExcel {
* public void parse() {
* System.out.println("执行解析Excel方法..........");
* }
* }
* 并将untitled7项目进行打包为 untitled7-1.0-SNAPSHOT.jar
* 路径为 D:\\Java_Code\\untitled7\\target\\untitled7-1.0-SNAPSHOT.jar
* 也可以将 untitled7-1.0-SNAPSHOT.jar 重新放在一个新的目录下
*
*/
public class Demo3 {
public static void main(String[] args) throws Exception {
File file = new File("D:\\Java_Code\\classloader\\untitled7-1.0-SNAPSHOT.jar");
URL[] urls = new URL[]{file.toURI().toURL()};
//这时候myClassLoader跟AppClassLoader是父子关系
URLClassLoader myClassLoader = new URLClassLoader(urls);
Class<?> aClass = myClassLoader.loadClass("com.test.ParseExcel");
//利用反射创建对象,并执行方法
Object obj = aClass.newInstance();
Method parse = aClass.getMethod("parse");
parse.invoke(obj,null);
}
}