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