远方蔚蓝
一刹那情真,相逢不如不见

文章数量 126

访问次数 199887

运行天数 1437

最近活跃 2024-10-04 23:36:48

进入后台管理系统

类的加载器-动态加载指定目录下的jar包


1、读取jar包中的MANIFEST.MF文件的属性
// 取到JarFile
JarFile jarFile = new JarFile("jar的路径");
// 获取Manifest
Manifest mf = jarFile.getManifest();
// 获取到属性集合
Attributes attrs = mf.getMainAttributes();
// 读取实现类
String attr = attrs.getValue("需要读取的属性");
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
 * jar包加载器
 * @author wst 2021318日 下午4:18:30
 *
 */
public class JarLoader {
	
	// 资源
	public static List<URLClassLoader> cachedJarFiles = new ArrayList<URLClassLoader>();
	// 加载的类
	public static Map<String, Class<?>> clazzMap = new HashMap<>(16);
    public JarLoader() {
        
    }
    /**
     * 扫描一个文件夹下面的所有jar,不包含子文件夹和子jar
     * @author wst 2021318日 下午4:18:46
     * @param directoryPath
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws IOException
     */
    public static Map<String, Class<?>> loadAllJarFromAbsolute(String directoryPath) throws
            NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException {
    	clazzMap.clear();
        File directory = new File(directoryPath);
        // 判断是否为文件夹,如果是文件,直接用单个jar解析的方法去解析
        if (!directory.isDirectory()) {
            // 添加jar扫描路径
            addUrl(directory);
            return loadJarFromAbsolute(directoryPath);
        }
        // 如果是文件夹,则需要循环加载当前文件夹下面的所有jar
        File[] jars = directory.listFiles();
        if (jars != null && jars.length > 0) {
            List<String> jarPath = new LinkedList<>();
            for (File file : jars) {
                String fPath = file.getPath();
                // 只加载jar
                if (fPath.endsWith(".jar")) {
                    addUrl(file);
                    jarPath.add(fPath);
                }
            }
            if (jarPath.size() > 0) {
                for (String path : jarPath) {
                    clazzMap.putAll(loadJarFromAbsolute(path));
                }
            }
        }
        return clazzMap;
    }
    /**
     * 功能描述: 从绝对路径中加载jar包中的类
     * 扫描指定jar包前需要将这个jar的地址加入了系统类加载器的扫描列表中
     * 注意,这里只支持单个jar的加载,如果这个jar还引入了其他jar依赖,会加载失败
     * 所以只能用来加载对其他jar包没有依赖的简单对象类信息
     *
     * @author wst 2021318日 下午4:19:12
     * @param path jar包路径加载地址
     * @return
     * @throws IOException
     */
    public static Map<String, Class<?>> loadJarFromAbsolute(String path) throws IOException {
        @SuppressWarnings("resource")
		JarFile jar = new JarFile(path);
        Enumeration<JarEntry> entryEnumeration = jar.entries();
        while (entryEnumeration.hasMoreElements()) {
            JarEntry entry = entryEnumeration.nextElement();
            // 先获取类的名称,符合条件之后再做处理,避免处理不符合条件的类
            String clazzName = entry.getName();
            if (clazzName.endsWith(".class")) {
                // 去掉文件名的后缀
                clazzName = clazzName.substring(0, clazzName.length() - 6);
                // 替换分隔符
                clazzName = clazzName.replace("/", ".");
                // 加载类,如果失败直接跳过
                try {
                    Class<?> clazz = Class.forName(clazzName);
                    // 将类名称作为键,类Class对象作为值存入mao
                    // 因为类名存在重复的可能,所以这里的类名是带包名的
                    clazzMap.put(clazzName, clazz);
                } catch (Throwable e) {
                    // 这里可能出现有些类是依赖不全的,直接跳过,不做处理,也没法做处理
                }
            }
        }
        return clazzMap;
    }
    /**
     * 添加需要扫描的jar包
     * @author wst 2021318日 下午4:19:28
     * @param jarPath
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws MalformedURLException
     */
    public static void addUrl(File jarPath) throws NoSuchMethodException, InvocationTargetException,
            IllegalAccessException, MalformedURLException {
        URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        // 反射获取类加载器中的addURL方法,并将需要加载类的jar路径
        Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
        if (!method.isAccessible()) {
            method.setAccessible(true);
        }
        URL url = jarPath.toURI().toURL();
        // 把当前jar的路径加入到类加载器需要扫描的路径
        method.invoke(classLoader, url);
    }
    
    /**
     * 关闭资源
     * @author wst 2021318日 下午4:19:35
     */
    public static void close() {
		for (URLClassLoader conn : cachedJarFiles) {
			try {
				conn.close(); // 关闭资源
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		cachedJarFiles.clear(); // 清空资源
		clazzMap.clear(); // 加载的类
	}
}
public boolean connect(String uid, String ip, String port) {
		Notification notification = new Notification();
    	try {
    		final IcJarFolder jar = icJarFolderService.get("id", "402897817843ea71017843ecd1820000");
      
    		// 加载jar包
    		Map<String, Class<?>> allJar = JarLoader.loadAllJarFromAbsolute(jar.getFolder());
      
    		// 找到需要实例的类
			Class<?> IABCDevice = allJar.get(jar.getClassName());
                   // 实例类
			Object instance = IABCDevice.newInstance();
   
                   // 找到实例类的方法
			Method method = IABCDevice.getMethod("connect", String.class, String.class, String.class);
//			String[] param = new String[] {uid, ip, port};
                   //执行方法
			Object ada = method.invoke(instance, uid, ip, port);
			logger.info("jar执行结果: {}", JSONObject.toJSONString(ada));
			JarLoader.close();
			notification.setTipMessage("jar执行完成");
			notification.setSuccess(true);
		} catch (Exception e) {
			JarLoader.close();
			e.printStackTrace();
			notification.setTipMessage("jar执行出错");
			notification.setSuccess(false);
		}
		return true;
	}