需求描述:
提供springboot项目使用maven打的jar包,然后通过程序反射调用启动jar包
重写一个类加载器:
import java.io.*;
import java.net.MalformedURLException;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class MyWebAppLoader extends ClassLoader{
/**
* lib:表示加载的文件在jar包中
* 类似tomcat就是{PROJECT}/WEB-INF/lib/
*/
private String lib;
/**
* classes:表示加载的文件是单纯的class文件
* 类似tomcat就是{PROJECT}/WEB-INF/classes/
*/
private String classes;
/**
* 采取将所有的jar包中的class读取到内存中
* 然后如果需要读取的时候,再从map中查找
*/
private Map map;
/**
* 只需要指定项目路径就好
* 默认jar加载路径是目录下{PROJECT}/WEB-INF/lib/
* 默认class加载路径是目录下{PROJECT}/WEB-INF/classes/
* @param webPath
* @throws MalformedURLException
* @throws SecurityException
* @throws NoSuchMethodException
*/
public MyWebAppLoader(String webPath) throws NoSuchMethodException, SecurityException, MalformedURLException {
lib = webPath + "BOOT-INF/lib/";
classes = webPath + "BOOT-INF/classes/";
map = new HashMap(64);
preReadJarFile();
}
/**
* 按照父类的机制,如果在父类中没有找到的类
* 才会调用这个findClass来加载
* 这样只会加载放在自己目录下的文件
* 而系统自带需要的class并不是由这个加载
*/
@Override
protected Class> findClass(String name){
try {
byte[] result = getClassFromFileOrMap(name);
if(result == null){
throw new FileNotFoundException();
}else{
return defineClass(name, result, 0, result.length);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 从指定的classes文件夹下找到文件
* @param name
* @return
*/
private byte[] getClassFromFileOrMap(String name){
String classPath = classes + name.replace('.', File.separatorChar) + ".class";
File file = new File(classPath);
if(file.exists()){
InputStream input = null;
try {
input = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int bytesNumRead = 0;
while ((bytesNumRead = input.read(buffer)) != -1) {
baos.write(buffer, 0, bytesNumRead);
}
return baos.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(input != null){
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}else{
if(map.containsKey(name)) {
//去除map中的引用,避免GC无法回收无用的class文件
return map.remove(name);
}
}
return null;
}
/**
* 预读lib下面的包
*/
private void preReadJarFile(){
List list = scanDir();
for(File f : list){
JarFile jar;
try {
jar = new JarFile(f);
readJAR(jar);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 读取一个jar包内的class文件,并存在当前加载器的map中
* @param jar
* @throws IOException
*/
private void readJAR(JarFile jar) throws IOException{
Enumeration en = jar.entries();
while (en.hasMoreElements()){
JarEntry je = en.nextElement();
String name = je.getName();
if (name.endsWith(".class")){
String clss = name.replace(".class", "").replaceAll("/", ".");
if(this.findLoadedClass(clss) != null) continue;
InputStream input = jar.getInputStream(je);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int bytesNumRead = 0;
while ((bytesNumRead = input.read(buffer)) != -1) {
baos.write(buffer, 0, bytesNumRead);
}
byte[] cc = baos.toByteArray();
input.close();
map.put(clss, cc);//暂时保存下来
}
}
}
/**
* 扫描lib下面的所有jar包
* @return
*/
private List scanDir() {
List list = new ArrayList();
File[] files = new File(lib).listFiles();
for (File f : files) {
if (f.isFile() && f.getName().endsWith(".jar"))
list.add(f);
}
return list;
}
/**
* 添加一个jar包到加载器中去。
* @param jarPath
* @throws IOException
*/
public void addJar(String jarPath) throws IOException{
File file = new File(jarPath);
if(file.exists()){
JarFile jar = new JarFile(file);
readJAR(jar);
}
}
}
这里我们将jar文件进行了解压
程序调用
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class TestInvoke {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, MalformedURLException {
// Method mainMethod = Class.forName("com.example.demo.DemoApplication").getMethod("main", String[].class);
// mainMethod.invoke(null, (Object)new String[]{"a", "b", "c"});
//
//
// Method mainMethod2 = Class.forName("com.example.demo2.DemoApplication2").getMethod("main", String[].class);
// mainMethod2.invoke(null, (Object)new String[]{"a", "b"});
// URL url = new URL("file:///D:/Project/demo2/target/demo2-0.0.1-SNAPSHOT.jar");
// URLClassLoader myClassLoader = new URLClassLoader(new URL[] {url});
// Method mainMethod2 = myClassLoader.loadClass("com.example.demo2.DemoApplication2").getMethod("main", String[].class);
// mainMethod2.invoke(null, (Object)new String[]{"a", "b"});
MyWebAppLoader myClassLoader2 = new MyWebAppLoader("D:/Project/demo2/target/demo2-0.0.1-SNAPSHOT1111/");
Method mainMethod2 = myClassLoader2.loadClass("com.example.demo2.DemoApplication2").getMethod("main", String[].class);
mainMethod2.invoke(null, (Object)new String[]{"a", "b"});
MyWebAppLoader myClassLoader = new MyWebAppLoader("D:/Project/demo/target/demo-0.0.1-SNAPSHOT/");
Method mainMethod = myClassLoader.loadClass("com.example.demo.DemoApplication").getMethod("main", String[].class);
mainMethod.invoke(null, (Object)new String[]{"a", "b"});
}
}