一、理论知识
- Java的类加载是双亲委派模型,同一个类(即全类名相同),默认情况下是只会被一个类加载器加载一次的。
- Java的类加载器分别有:
bootstrap:主要加载rt.jar
ext classloader:主要加载jre/ext/*.jar
app classloader:主要加载应用的classpath下面的jar、class文件 - 不同的类加载器所加载的类是存放在方法区的不同的内存区域,相互隔离。
- 应用自定义的classloader在逻辑上的双亲类加载器都是app classloader。
二、如何在应用中加载全类名相同的类两次呢
利用不同的classloader加载的类相互隔离,来实现同时加载全类名相同的类两次。
实验步骤
1.准备主应用
有一个待实现的接口:
测试类:
package org.example;
import org.example.service.HelloService;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.ServiceLoader;
public class Main {
public static void main(String[] args) throws MalformedURLException {
version1();
System.out.println("==============");
version2();
}
private static void version1() throws MalformedURLException {
URL url = new URL(
"file:C:\\Users\\shaocheng\\.m2\\repository\\com\\test\\helloServiceImpl1\\1.0-SNAPSHOT\\helloServiceImpl1-1.0-SNAPSHOT.jar");
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
doHelloService(urlClassLoader);
}
private static void version2() throws MalformedURLException {
URL url = new URL(
"file:C:\\Users\\shaocheng\\.m2\\repository\\com\\test\\helloServiceImpl1\\1.1-SNAPSHOT\\helloServiceImpl1-1.1-SNAPSHOT.jar");
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
doHelloService(urlClassLoader);
}
private static void doHelloService(ClassLoader classLoader) {
ServiceLoader<HelloService> helloServiceLoader = ServiceLoader.load(HelloService.class, classLoader);
Iterator<HelloService> iterator = helloServiceLoader.iterator();
while(iterator.hasNext()) {
HelloService helloService = iterator.next();
helloService.sayHello();
}
}
}
2.准备HelloService的第一个实现版本(实现类名均为com.test.service.HelloServiceImpl)
文件META-INF\services\org.example.service.HelloService的内容为com.test.service.HelloServiceImpl
3.准备HelloService的第二个实现版本(实现类名均为com.test.service.HelloServiceImpl)
文件META-INF\services\org.example.service.HelloService的内容为com.test.service.HelloServiceImpl
4.测试结果
三、总结
以上利用了JDK自带的SPI特性实现了自动加载接口的实现类。也可以自己加载实现类,比如测试类的doHelloService方法改写为:
private static void doHelloService(ClassLoader classLoader) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class<?> aClass = classLoader.loadClass("com.test.service.HelloServiceImpl");
HelloService aObj = (HelloService) aClass.newInstance();
aObj.sayHello();
}