双亲委派机制原则在loadclass方法中。
只需要绕开loadclass方法中即可。
1.自定义类加载器 ,重写loadclass方法
2, SPI机制绕开loadclass 方法。当前线程设定关联类加载器。
什么是SPI 机制
Spi 机制加载第三方扩展的jar包类初始化。
mysql, dubbo rpc
SPi机制的原理:
java SPI全称Service Provider Interface 。是java 提供的一套用来被第三方实现的API,他可以用来启用框架扩展和替换组件。实际上是基于接口编程+策略模式+配置文件 组合实现的动态加载机制。
自己写SPi 机制
命名规范:
文件夹命名:
名称规范:包名+类名组成。
F:\works\2020\mayiketang\7\jvm\jvm1\src\main\resources
META-INF.services
package com.taotao.jvm03.service;
/**
*@author tom
*Date 2020/8/8 0008 9:49
*
*/
public interface MayiktService {
String addOrder();
}
package com.taotao.jvm03.service.impl;
import com.taotao.jvm03.service.MayiktService;
/**
*@author tom
*Date 2020/8/8 0008 9:49
*
*/
public class MayiktService01 implements MayiktService {
@Override
public String addOrder() {
return "01";
}
}
package com.taotao.jvm03.service.impl;
import com.taotao.jvm03.service.MayiktService;
/**
*@author tom
*Date 2020/8/8 0008 9:50
*
*/
public class MayiktService02 implements MayiktService {
@Override
public String addOrder() {
return "02";
}
}
package com.taotao.jvm03;
import com.taotao.jvm03.service.MayiktService;
import java.util.ServiceLoader;
/**
*@author tom
*Date 2020/8/9 0009 7:21
*SPI机制
*/
public class Test002 {
public static void main(String[] args) {
ServiceLoader<MayiktService> load = ServiceLoader.load(MayiktService.class);
load.forEach((t) -> {
System.out.println(t);
});
}
}
classLoader 源码解读
launcher 设定类加载器的依赖关系:
如何破坏双亲委派机制:
package com.taotao.jvm03;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.ServiceLoader;
/**
* @ClassName Test003
* @Author 蚂蚁课堂余胜军 QQ644064779 www.mayikt.com
* @Version V1.0
**/
public class Test003 {
public static void main(String[] args) throws SQLException {
// Thread.currentThread().setContextClassLoader(Test003.class.getClassLoader().getParent());
Connection root =
DriverManager
.getConnection
(
"jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=true",
"root", "root");
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
loadedDrivers.forEach(t -> {
System.out.println(t);
});
}
}
spi绕开loadclass 方法: 核心是先找到当前类加载器目录下是否有Spi机制对应的配置文件。如果没有的情况下,则不会初始化该类。会报错。
什么是自定义类加载器:
什么情况下 会使用自定义类加载器:
需要自己定义class文件夹目录:
网络方式。
硬盘方式。
手写自定义热部署当前我们项目class 文件如果发生变化的情况下,不需要重启我们的服务器。
package com.taotao.jvm03;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
/**
*@author tom
*Date 2020/8/9 0009 9:07
*自定义热部署
*/
public class MayiktClassLoader extends ClassLoader {
private File fileObject;
public void setFileObject(File fileObject) {
this.fileObject = fileObject;
}
public File getFileObject() {
return fileObject;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] data = getClassFileBytes(this.fileObject);
return defineClass(name, data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 从文件中读取去class文件
*
* @throws Exception
*/
private byte[] getClassFileBytes(File file) throws Exception {
//采用NIO读取
FileInputStream fis = new FileInputStream(file);
FileChannel fileC = fis.getChannel();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
WritableByteChannel outC = Channels.newChannel(baos);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
while (true) {
int i = fileC.read(buffer);
if (i == 0 || i == -1) {
break;
}
buffer.flip();
outC.write(buffer);
buffer.clear();
}
fis.close();
return baos.toByteArray();
}
}
package com.taotao.jvm03;
import com.taotao.jvm03.service.OrderService;
import java.io.File;
/**
*@author tom
*Date 2020/8/9 0009 9:17
*
*/
public class Test004 {
private static long startTime;
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
MayiktClassLoader mayiktClassLoader = new MayiktClassLoader();
mayiktClassLoader.setFileObject(new File("D:\\code\\OrderServiceImpl.class"));
Class<?> aClass = mayiktClassLoader.findClass("com.taotao.jvm03.service.impl.OrderServiceImpl");
OrderService orderService = (OrderService) aClass.newInstance();
System.out.println("读取class成功:" + orderService.Order());
File fileObject = mayiktClassLoader.getFileObject();
startTime = fileObject.lastModified();
new Thread(() -> {
while (true) {
try {
Thread.sleep(2000);
} catch (Exception e) {
}
long endTime = fileObject.lastModified();
if (endTime != startTime) {
System.out.println("class文件发生了变化,需要重新读取");
try {
MayiktClassLoader newMayiktClassLoader = new MayiktClassLoader();
newMayiktClassLoader.setFileObject(new File("D:\\code\\OrderServiceImpl.class"));
Class<?> newClass = newMayiktClassLoader.findClass("com.taotao.jvm03.service.impl.OrderServiceImpl");
OrderService newOrderService = (OrderService) newClass.newInstance();
System.out.println("读取class成功:" + newOrderService.Order());
} catch (Exception e) {
e.printStackTrace();
}
startTime = endTime;
}
}
}).start();
}
}
package com.taotao.jvm03.service;
/**
*@author tom
*Date 2020/8/9 0009 9:44
*
*/
public interface OrderService {
String Order();
}
package com.taotao.jvm03.service.impl;
import com.taotao.jvm03.service.OrderService;
/**
*@author tom
*Date 2020/8/9 0009 9:44
*
*/
public class OrderServiceImpl implements OrderService {
@Override
public String Order() {
return "5555";
}
}