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