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