dengzedong
2024-10-10 a8f2f4e6f1a9173d7eb9779c7879674015c8cda0
提交 | 用户 | 时间
912a1e 1 package com.iailab.module.model.mpk.common.utils;
D 2
a8f2f4 3 import cn.hutool.core.io.FileUtil;
c12dae 4 import com.iailab.module.model.mpk.common.MdkConstant;
912a1e 5 import lombok.extern.slf4j.Slf4j;
D 6 import org.apache.commons.lang3.StringUtils;
7
8 import java.io.File;
9 import java.lang.reflect.Field;
10 import java.lang.reflect.Method;
11 import java.net.URL;
12 import java.net.URLClassLoader;
c12dae 13 import java.util.HashMap;
912a1e 14 import java.util.Iterator;
D 15 import java.util.Vector;
16
17 @Slf4j
18 public class DllUtils {
c12dae 19
D 20     private static HashMap<String, URLClassLoader> classLoaderCache = new HashMap<>();
912a1e 21
D 22     /**
23      * @description: 加载dll到指定class下
24      * @author: dzd
25      * @date: 2024/9/30 14:27
26      **/
27     public static void loadDll(Class<?> clazz, String dllPath) {
28         try {
c12dae 29             Method method = Runtime.class.getDeclaredMethod("load0", Class.class, String.class);
912a1e 30             boolean accessible = method.isAccessible();
D 31             method.setAccessible(true);
c12dae 32             method.invoke(Runtime.getRuntime(), clazz, dllPath);
912a1e 33             method.setAccessible(accessible);
c12dae 34             log.info("成功加载dll:" + dllPath);
912a1e 35         } catch (Exception e) {
c12dae 36             throw new RuntimeException("加载dll异常", e);
912a1e 37         }
D 38     }
39
40     /**
41      * @description: 卸载classLoader下全部dll
42      * @author: dzd
43      * @date: 2024/9/30 14:31
44      **/
c12dae 45     public static synchronized void unloadDll(URLClassLoader classLoader) {
912a1e 46         try {
D 47             Field field = ClassLoader.class.getDeclaredField("nativeLibraries");
48             field.setAccessible(true);
49             Vector<Object> libs = (Vector<Object>) field.get(classLoader);
50             Iterator<Object> it = libs.iterator();
51             Object o;
52             while (it.hasNext()) {
53                 o = it.next();
54                 Method method = o.getClass().getDeclaredMethod("finalize");
55                 boolean accessible = method.isAccessible();
56                 method.setAccessible(true);
57                 method.invoke(o);
58                 method.setAccessible(accessible);
59
60                 Field nameDield = o.getClass().getDeclaredField("name");
61                 nameDield.setAccessible(true);
62                 String name = (String) nameDield.get(o);
63
64                 log.info("成功卸载dll:" + name);
65             }
66         } catch (Exception e) {
c12dae 67             throw new RuntimeException("卸载dll异常", e);
912a1e 68         }
D 69     }
70
71     /**
72      * @description: 从classLoader中卸载dll,如果dllName传null,则默认删除全部dll
73      * @author: dzd
74      * @date: 2024/9/30 14:52
75      **/
c12dae 76     public static synchronized void unloadDllName(URLClassLoader classLoader, String dllName) {
912a1e 77         try {
D 78             Field field = ClassLoader.class.getDeclaredField("nativeLibraries");
79             field.setAccessible(true);
80             Vector<Object> libs = (Vector<Object>) field.get(classLoader);
81             Iterator<Object> it = libs.iterator();
82             Object o;
83             while (it.hasNext()) {
84                 o = it.next();
85                 Field nameDield = o.getClass().getDeclaredField("name");
86                 nameDield.setAccessible(true);
87                 String name = (String) nameDield.get(o);
88                 // dllName不为null 并且 不等于name,跳出(dllName为null默认全部删除)
89                 if (StringUtils.isNotEmpty(dllName) && !dllName.equals(name)) {
90                     return;
91                 }
92                 Method method = o.getClass().getDeclaredMethod("finalize");
93                 boolean accessible = method.isAccessible();
94                 method.setAccessible(true);
95                 method.invoke(o);
96                 method.setAccessible(accessible);
97                 log.info("成功卸载dll:" + name);
98             }
99         } catch (Exception e) {
c12dae 100             throw new RuntimeException("卸载dll异常", e);
912a1e 101         }
D 102     }
103
104     /**
105      * @description: 加载jar到特定的URLClassLoader,并返回URLClassLoader
106      * @author: dzd
107      * @date: 2024/9/30 14:20
108      **/
109     public static synchronized URLClassLoader loadJar(String jarPath) {
110         File jarFile = new File(jarPath);
111         if (!jarFile.exists()) {
c12dae 112             throw new RuntimeException("jar沒有找到!"+jarPath);
912a1e 113         } else {
D 114             try {
c12dae 115                 // 设置classloader的patent为null,限制使用双亲委派,防止其他classloader找到class,导致dll加载到其他classloader
D 116                 URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{jarFile.toURI().toURL()},null,null);
117                 log.info("成功加载jar包:" + jarFile.getAbsolutePath());
912a1e 118                 return urlClassLoader;
D 119             } catch (Exception e) {
c12dae 120                 throw new RuntimeException("加载jar异常", e);
912a1e 121             }
D 122         }
123     }
124
c12dae 125     public static synchronized void unloadJar(URLClassLoader urlClassLoader) {
912a1e 126         try {
D 127             urlClassLoader.close();
128             log.info("成功卸载jar包。");
129         } catch (Exception e) {
c12dae 130             throw new RuntimeException("卸载jar异常", e);
912a1e 131         }
D 132     }
c12dae 133
D 134     public static synchronized void addClassLoaderCache(String projectId, URLClassLoader urlClassLoader) {
135         classLoaderCache.put(projectId, urlClassLoader);
136     }
137
138     public static synchronized URLClassLoader getClassLoader(String projectId) {
139         return classLoaderCache.get(projectId);
140     }
141
142     public static synchronized void removeClassLoaderCache(String projectId) {
143         if (classLoaderCache.containsKey(projectId)) {
144             URLClassLoader urlClassLoader = classLoaderCache.get(projectId);
145             unloadDll(urlClassLoader);
146             unloadJar(urlClassLoader);
147             classLoaderCache.remove(projectId);
148         }
149     }
150
151     public static void removeOldFile(String bakPath,String projectId) {
152         File dir = new File(bakPath);
153         if (dir.exists() && dir.isDirectory()) {
154             File[] files = dir.listFiles();
155             if (null != files && files.length > 0) {
156                 for (File file : files) {
157                     if (file.getName().startsWith(projectId)) {
158                         file.delete();
159                     }
160                 }
161             }
162         }
163     }
164
165     /**
166      * @description: 项目启动加载已发布的dll和jar
167      * @author: dzd
168      * @date: 2024/10/10 11:58
169      **/
170     public static void loadProjectPublish(String bakPath) {
171         File dir = new File(bakPath);
172         if (dir.exists() && dir.isDirectory()) {
173             File[] files = dir.listFiles();
174             if (null != files && files.length > 0) {
175                 for (File file : files) {
176                     String fileName = file.getName();
177                     if (fileName.endsWith(".jar")) {
178                         String[] split = fileName.substring(0,fileName.length() - 4).split(MdkConstant.SPLIT);
179                         String projectId = split[0];
180                         String historyId = split[1];
181
182                         String jarFilePath = bakPath + File.separator + projectId + MdkConstant.SPLIT + historyId + ".jar";
183                         String dllFilePath = bakPath + File.separator + projectId + MdkConstant.SPLIT + historyId + ".dll";
184
a8f2f4 185                         if (FileUtil.exist(jarFilePath) && FileUtil.exist(dllFilePath)) {
D 186                             URLClassLoader urlClassLoader = null;
187                             try {
188                                 // 加载新的jar
189                                 urlClassLoader = loadJar(jarFilePath);
190                             } catch (Exception e) {
191                                 throw new RuntimeException("加载jar异常",e);
192                             }
c12dae 193
a8f2f4 194                             try {
D 195                                 // 加载新的dll
196                                 loadDll(urlClassLoader.loadClass("iail.mdk.model.common.Environment"),dllFilePath);
197                             } catch (Exception e) {
198                                 unloadJar(urlClassLoader);
199                                 throw new RuntimeException("加载dll异常",e);
200                             }
201                             // 都加载成功后加入缓存
202                             addClassLoaderCache(projectId,urlClassLoader);
c12dae 203                         }
D 204                     }
205                 }
206             }
207         }
208
209     }
912a1e 210 }