1、windows调用C++程序实现java虚拟机;
2、创建一个引导类加载器(BootstrapClassloader);
3、引导类加载器创建JVM启动器launcher,由lunacher类创建其他类加载器(扩展类加载器和应用类加载器)
1、加载,根据path找到class文件;
2、验证,校验class内容是否符合规范;
3、准备,静态变量赋默认值,常量直接复赋值;
4、解析,将符号引用转换为直接引用;符号引用可以理解为“public static ”这一类的符号转化为内存中的地址;直接引用就是内存地址的引用;
(1)静态连接:比如static一类的方法,在类加载期间就转换为直接引用了;
(2)动态连接:方法的调用,“dosomething()”,在调用时才转换为直接引用;
5、初始化,为静态变量赋值,执行静态方法
1、引导类加载器:加载rt.jar等核心模块;
2、扩展类加载器:加载扩展包里面的类;
3、应用程序类加载器:加载用户自己变成的文件
4、自定义类加载器:加载用户自定义路径下的类
实例:
package com.company;
import java.net.URL;
import com.sun.crypto.provider.DESedeKeyFactory;
import sun.misc.Launcher;
/**
* @date 2020/7/2
*/
public class TestJdkClassLoader {
public static void main(String[] args) {
System.out.println(String.class.getClassLoader());
System.out.println(DESedeKeyFactory.class.getClassLoader().getClass().getName());
System.out.println(TestJdkClassLoader.class.getClassLoader().getClass().getName());
System.out.println();
ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
ClassLoader extClassLoader = appClassLoader.getParent();
ClassLoader bootStrapLoader = extClassLoader.getParent();
System.out.println("the bootStrapLoader"+bootStrapLoader);
System.out.println("the extClassLoader"+extClassLoader);
System.out.println("the appClassLoader"+appClassLoader);
System.out.println();
System.out.println("bootStrapLoader 加载以下文件");
URL[] urls = Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urls.length; i++) {
System.out.println(urls[i]);
}
System.out.println();
System.out.println("extClassLoader 加载以下文件");
System.out.println(System.getProperty("java.ext.dirs"));
System.out.println();
System.out.println("appclassloader 加载以下文件");
System.out.println(System.getProperty("java.class.path"));
}
}
双亲委派的过程:
简单说一下大致过程:
首先去自定义类加载中查找有没有加载过的类,没有就一直向上委派;直到引导类加载也没找到;那么引导类加载器开始尝试加载,如果成功加载则返回;否则向下尝试;一直到自定义类加载类尝试加载。
源码只要在java.lang.ClassLoader#loadClass(java.lang.String, boolean)这个方法中:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 先查找一下
Class<?> c = findLoadedClass(name);
//如果没找到
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
//扩展加载器中查找
c = parent.loadClass(name, false);
} else {
//引导类加载器中查找
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
//都没找到,尝试开始加载
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
1、安全
jvm的核心类库只能由引导类加载器加载;避免了安全问题;
2、效率
一些共同使用的基础jar包,只会由指定加载器加载一次,然后就都能使用了,避免了重复加载。
继承ClassLoader类,重写findclass方法;
package com.ysy.JVM类加载;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author shanyangyang
* @date 2020/7/2
*/
public class MyClassLoaderTest {
static class MyClassLoader extends ClassLoader {
private String classPath;
public MyClassLoader(String classPath) {
this.classPath = classPath;
}
@Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
return super.loadClass(name, resolve);
}
@Override protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] data = loadByte(name);
//该方法将一个字节数组转换为Class对象,这个字节数组就是最终读取的字节数组
return defineClass(name, data, 0, data.length);
} catch (IOException e) {
e.printStackTrace();
}
return super.findClass(name);
}
private byte[] loadByte(String name) throws IOException {
name.replace("\\.", "/");
FileInputStream fileInputStream = new FileInputStream(classPath + "/" + name + ".class");
int len = fileInputStream.available();
byte[] bytes = new byte[len];
fileInputStream.read(bytes);
fileInputStream.close();
return bytes;
}
public static void main(String[] args)
throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException,
InvocationTargetException {
//父加载器设置为应用程序类加载器
MyClassLoader myClassLoader = new MyClassLoader("/Users/shanyangyang/BaiduNetdiskDownload/java");
Class<?> aClass = myClassLoader.loadClass("com.ysy.");
Object object = aClass.newInstance();
Method method = aClass.getDeclaredMethod("sout", null);
method.invoke(object, null);
}
}
}
继承ClassLoader类,重写laodClass方法
package com.ysy.JVM类加载;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author shanyangyang
* @date 2020/7/2
*/
public class MyClassLoaderTest {
static class MyClassLoader extends ClassLoader {
private String classPath;
public MyClassLoader(String classPath) {
this.classPath = classPath;
}
@Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
//注释掉委托父类加载器的逻辑,但是需要加个判断,只有自己目录下的文件不委托;否则会导致jar包中类无法加载报错
// try {
// if (parent != null) {
// c = parent.loadClass(name, false);
// } else {
// c = findBootstrapClassOrNull(name);
// }
// } catch (ClassNotFoundException e) {
// // ClassNotFoundException thrown if class not found
// // from the non-null parent class loader
// }
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
@Override protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] data = loadByte(name);
//该方法将一个字节数组转换为Class对象,这个字节数组就是最终读取的字节数组
return defineClass(name, data, 0, data.length);
} catch (IOException e) {
e.printStackTrace();
}
return super.findClass(name);
}
private byte[] loadByte(String name) throws IOException {
name.replace("\\.", "/");
FileInputStream fileInputStream = new FileInputStream(classPath + "/" + name + ".class");
int len = fileInputStream.available();
byte[] bytes = new byte[len];
fileInputStream.read(bytes);
fileInputStream.close();
return bytes;
}
public static void main(String[] args)
throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException,
InvocationTargetException {
//父加载器设置为应用程序类加载器
MyClassLoader myClassLoader = new MyClassLoader("/Users/shanyangyang/BaiduNetdiskDownload/java");
Class<?> aClass = myClassLoader.loadClass("com.ysy.");
Object object = aClass.newInstance();
Method method = aClass.getDeclaredMethod("sout", null);
method.invoke(object, null);
}
}
}
通过查看tomcat类加载器模型我们可以得出如下结论:
1、不同的webapps类加载器之间相互隔离,实现了web应用的安全隔离;
2、同时可以通过SharedclassLoader实现类在不同webapp之间的共享;
3、catlinaclassloader下的类又与应用之间的类之间隔离;
4、每个JSP类加载器只加载对应的一个JSP文件;jsp文件热加载的原理,就是tomcat检测到jsp文件发生了变化,就删除旧的jsp类加载器,重新实例化一个JSP类加载器来加载文件。
package com.company.com.threadlocal;
import java.io.FileInputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author
* @date 2020/7/3
*/
public class MyClassLoaderTest {
static class MyClassLoader extends ClassLoader{
String path;
public MyClassLoader(String path) {
this.path = path;
}
@Override
public Class<?> loadClass(String name,boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
if (!name.startsWith("com.company")){
c = this.getParent().loadClass(name);
} else {
c = findClass(name);
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = new byte[0];
try {
data = loadByte(name);
} catch (Exception e) {
e.printStackTrace();
}
return defineClass(name,data,0,data.length);
}
private byte[] loadByte(String name) throws Exception{
name = name.replaceAll("\\.","/");
FileInputStream fis = new FileInputStream(path+"/"+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 ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
MyClassLoader classLoader1 = new MyClassLoader("D:/test");
Class<?> class1 = classLoader1.loadClass("com.company.Test");
Object obj = class1.newInstance();
Method method1 = class1.getDeclaredMethod("sout",null);
method1.invoke(obj,null);
System.out.println(class1.getClassLoader().getClass().getName());
System.out.println("=========================================");
MyClassLoader classLoader2 = new MyClassLoader("D:/test1");
Class<?> class2 = classLoader2.loadClass("com.company.Test");
Object obj1 = class2.newInstance();
Method method2 = class2.getDeclaredMethod("sout",null);
method1.invoke(obj,null);
System.out.println(class2.getClassLoader());
}
}
}