这里使用Java SPI的方式来实现插件化,而开发的插件是一般的java Project。至于更丰富的SpringBoot插件,不一定适用。
- 在STS新建一个java project,然后,稍微改下.classpath的文件,将文件目录改成通常的形式:
然后新建一个Interface:
public interface TestInterface {
String sayHello(String name);
}
然后新建一个实现类:
public class HellToInsky implements TestInterface {
@Override
public String sayHello(String name) {
return "Insky say hello to " + name;
}
}
在srcmainresourcesmeta-INFservices目录下新建一个包含interface包名和类名的文件,例如com.qb.report.TestInterface,然后在内容中添加实现类的完整名称:
com.qb.report.HellToInsky
然后导出为java jar,放在硬盘某个位置:
2. 将interface类拷贝到我们的Springboot工程中,然后添加如下代码:
@GetMapping("/testJar")
public void testJar(HttpServletRequest request, HttpServletResponse response) throws IOException {
log.info("classLoader={}", this.getClass().getClassLoader());
ClassLoader cl = new URLClassLoader(new URL[] {new URL("file:" + "D:/test.jar")}, this.getClass().getClassLoader()) ;
ServiceLoader tests = ServiceLoader.load(TestInterface.class, cl);
Iterator it = tests.iterator();
if (it.hasNext()) {
TestInterface test = it.next();
String ret = test.sayHello(this.getClass().getSimpleName());
log.info("ret={}", ret);
response.getWriter().append(ret);
}
}
输出结果:
classLoader=jdk.internal.loader.ClassLoaders$AppClassLoader@7382f612
ret=Insky say hello to JasperController
3.环境
STS4.10.0
java 1.8
- 网上的差别
public static void defaultClassLoader() throws MalformedURLException, ClassNotFoundException {
ClassLoader serviceCL = new URLClassLoader(new URL[] { new URL("file:" + "D:/HelloService.jar"),
new URL("file:" + "D:/Dog.jar"), new URL("file:" + "D:/Sheep.jar") },
TestServiceLoader.class.getClassLoader().getParent());
ServiceLoader helloServices = ServiceLoader
.load(((Class) (serviceCL.loadClass("com.test.loader.HelloService"))));
Iterator it = helloServices.iterator();
while (it.hasNext()) {
HelloService service = it.next();
service.sayHello();
}
}
这里多了个getParent,会提示:
java.util.ServiceConfigurationError: no a subtype
的错误,而statckoverfloat上说,要加上getParent,我这测试是加上才出错。可能是不同版本的原因。
public static void loadJarFile(File path) throws Exception {
URL url = path.toURI().toURL();
// 可以获取到AppClassLoader,可以提到前面,不用每次都获取一次
URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
// 加载
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(classLoader, url);
}
这个会提示:
java.lang.ClassCastException: class jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to class java.net.URLClassLoader
的错误,主要是版本问题,我这个版本AppClassLoader 不再继承自URLClassLoader。



