jar檔案解析,載入,解除安裝的簡單實現
阿新 • • 發佈:2019-02-15
在專案開發時,由於需求的更變,需要實現對jar檔案的上傳,解析,載入,解除安裝等功能
1.MyURLClassLoader.java
public class MyURLClassLoader extends URLClassLoader { private List<JarURLConnection> cachedJarFiles = new ArrayList(); public MyURLClassLoader() { super(new URL[] {}, findParentClassLoader()); } /** * 定位基於當前上下文的父類載入器 * @return 返回可用的父類載入器. */ private static ClassLoader findParentClassLoader() { ClassLoader parent = MyURLClassLoader.class.getClassLoader(); if (parent == null) { parent = MyURLClassLoader.class.getClassLoader(); } if (parent == null) { parent = ClassLoader.getSystemClassLoader(); } return parent; } /** * 將指定的檔案url新增到類載入器的classpath中去,並快取jar connection,方便以後解除安裝jar * @param 一個可想類載入器的classpath中新增的檔案url */ public void addURLFile(URL file) { try { // 開啟並快取檔案url連線 URLConnection uc = file.openConnection(); if (uc instanceof JarURLConnection) { uc.setUseCaches(true); ((JarURLConnection) uc).getManifest(); cachedJarFiles.add((JarURLConnection)uc); } } catch (Exception e) { System.err.println("Failed to cache plugin JAR file: " + file.toExternalForm()); } addURL(file); } /** * 解除安裝jar包 */ public void unloadJarFiles() { List<JarURLConnection> tempDel = new ArrayList<>(); for (JarURLConnection url : cachedJarFiles) { try { tempDel.add(url); System.err.println("Unloading plugin JAR file " + url.getJarFile().getName()); url.getJarFile().close(); url=null; } catch (Exception e) { System.err.println("Failed to unload JAR file\n"+e); } } cachedJarFiles.removeAll(tempDel); tempDel = null; } public int getCachedJarCount() { return cachedJarFiles.size(); } }
2.CustomFunctionJarManager.java
public interface CustomFunctionJarManager { public void loadJar(String path,String loaderName); public void unloadJar(String loaderName); // public void tempParse(String path,JarParse jarParse); public byte[] createChecksum(String filename) throws Exception; public byte[] createChecksum(InputStream fis) throws Exception; public String getMD5Checksum(String filename) throws Exception; public String getMD5Checksum(InputStream fis) throws Exception; public Object getLoader(String loaderName); public void init(); public void destroy(); public boolean isloaded(String loaderName); }
3.CustomFunctionJarManagerImpl.java
public class CustomFunctionJarManagerImpl implements CustomFunctionJarManager{ private static Map loaderMap = new HashMap(); public CustomFunctionJarManagerImpl(){ super(); } @Override public synchronized void loadJar(String path,String loaderName){ try { String name = loaderName==null?path:loaderName; unloadJar(name); MyURLClassLoader loader = new MyURLClassLoader(); URL url = new File(path).toURI().toURL(); String jarStr = "jar:" + url.toExternalForm() + "!/"; loader.addURLFile( new URL(jarStr) ); this.loaderMap.put(name, loader); } catch (MalformedURLException e) { e.printStackTrace(); } } @Override public synchronized void unloadJar(String loaderName){ MyURLClassLoader loader = (MyURLClassLoader) this.getLoader(loaderName); if(null != loader) { loader.unloadJarFiles(); this.loaderMap.remove(loaderName); } } // @Override // public synchronized void tempParse(String path,JarParse jarParse) { // try { // URL url = new File(path).toURI().toURL(); // String jarStr = "jar:" + url.toExternalForm() + "!/"; // loader.addURLFile( new URL(jarStr) ); // // jarParse.parseJar(path, loader); // } catch (MalformedURLException e) { // e.printStackTrace(); // } finally { // loader.unloadJarFiles(); // System.gc(); // } // } @Override public synchronized byte[] createChecksum(String filename) throws Exception{ InputStream fis = new FileInputStream(filename); byte[] buffer = new byte[1024]; int len; MessageDigest complete = MessageDigest.getInstance("MD5"); while((len=fis.read(buffer)) > -1) { complete.update(buffer, 0, len); } fis.close(); return complete.digest(); } @Override public synchronized byte[] createChecksum(InputStream fis) throws Exception{ byte[] buffer = new byte[1024]; int len; MessageDigest complete = MessageDigest.getInstance("MD5"); while((len=fis.read(buffer)) > -1) { complete.update(buffer, 0, len); } fis.close(); return complete.digest(); } @Override public synchronized String getMD5Checksum(String filename) throws Exception{ byte[] b = createChecksum(filename); StringBuffer result = new StringBuffer(""); for (int i = 0,len = b.length; i < len; i++) { result.append(Integer.toString((b[i] & 0xff) + 0x100).substring(1)); } return result.toString(); } @Override public synchronized String getMD5Checksum(InputStream fis) throws Exception{ StringBuffer result = new StringBuffer(""); byte[] b = createChecksum(fis); for (int i = 0,len = b.length; i < len; i++) { result.append(Integer.toString((b[i] & 0xff) + 0x100).substring(1)); } return result.toString(); } @Override public Object getLoader(String loaderName) { return this.loaderMap.get(loaderName); } @Override public void init() { } @Override public void destroy() { } @Override public boolean isloaded(String loaderName) { MyURLClassLoader loader = (MyURLClassLoader) getLoader(loaderName); return null!=loader; } }
4.CustomFunctionJarManagerFactory.java
public class CustomFunctionJarManagerFactory {
public static CustomFunctionJarManager manager = null;
public static synchronized CustomFunctionJarManager getCustomFunctionJarManager(String className){
if (null == manager) {
if(null != className && !"".equals(className)){
try {
manager = (CustomFunctionJarManager) Class.forName(className).newInstance();
} catch (Exception e) {
ARE.getLog().error("CustomFunctionJarManager獲取失敗", e);
manager = new CustomFunctionJarManagerImpl();
}
}
else {
manager = new CustomFunctionJarManagerImpl();
}
}
try {
manager.init();
} catch (Exception e) {
ARE.getLog().error("CustomFunctionJarManager初始化失敗", e);
}
return manager;
}
public static synchronized void release() {
if (manager != null) {
try {
manager.destroy();
manager = null;
} catch (Exception e) {
ARE.getLog().error("CustomFunctionJarManager銷燬失敗", e);
}
}
return;
}
}
5.使用情況
ServletContext application = config.getServletContext();
Map<String,String> jarMap = new HashMap<String,String>();
Map<String,String> classMap = new HashMap<String,String>();
application.setAttribute("JarDetails", jarMap); //儲存jar檔案MD5值,表示式名
application.setAttribute("ClassMD5ValueMap", classMap); //儲存表示式class檔案對應MD5值
Connection conn = null;
try {
BizObjectManager bm=JBOFactory.getBizObjectManager("xxxxxxxxxxxxxxxxxxxxxxxxx");
String defaultPath = config.getServletContext().getRealPath("/");//專案工程根目錄
String projectName = config.getServletContext().getContextPath();//專案工程名
final String filePath = "CUSTOM_FUNCTION_UPDOAD_FILE_PATH";
final String jarPath = "CUSTOM_FUNCTION_JAR_NAME";
String rootParse = ARE.getProperty(filePath,defaultPath.substring(0, defaultPath.length() - projectName.length()) + "/cfClasses"); //jar包位置
String jarName = ARE.getProperty(jarPath, "thread.jar");//jar包名
CustomFunctionJarManager manager = CustomFunctionJarManagerFactory.getCustomFunctionJarManager(null);
synchronized(manager) {//執行緒安全
File file = new File(rootParse, jarName);
if(!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
if(!file.exists()){
jarMap.put("MD5Value", "");
jarMap.put("FuncList", "");
bm.createQuery("delete from O");
return;
}
else {
manager.loadJar(file.getAbsolutePath());
jarMap.put("MD5Value", manager.getMD5Checksum(file.getAbsolutePath()));
JarFile jarFile = null;
jarFile = new JarFile(file.getAbsolutePath());
Enumeration<JarEntry> entryList = jarFile.entries();
StringBuffer sbf = new StringBuffer("");
while(entryList.hasMoreElements()) {//在jar檔案中查詢xxx.xxx.xxx包下的所以類檔案class
JarEntry jarEntry = entryList.nextElement();
String tempName = jarEntry.getName();
if(tempName.startsWith("xxx/xxx/xxx/") && tempName.endsWith(".class")) {
Pattern p = Pattern.compile("[^0-9a-zA-Z/.]");//對掉內部類等情況
Matcher m = p.matcher(tempName);
if(!m.find()){
classMap.put(tempName.substring(tempName.lastIndexOf("/") + 1, tempName.lastIndexOf(".")), manager.getMD5Checksum(jarFile.getInputStream(jarEntry)));
sbf.append(tempName.substring(tempName.lastIndexOf("/") + 1, tempName.lastIndexOf(".")));
sbf.append(",");
}
}
}
if(!"".equals(sbf.toString())) {
jarMap.put("FuncList", sbf.substring(0, sbf.length() - 1));
}
else {
jarMap.put("FuncList", "");
return;
}
List<BizObject> funcNames = bm.createQuery("select funcName from O").getResultList(false);
StringBuffer funcNamesBuffer = new StringBuffer(",");
for (BizObject bizObject : funcNames) {
funcNamesBuffer.append(bizObject.getAttribute("funcName").getString());
funcNamesBuffer.append(",");
}
String funcNamesStr = funcNamesBuffer.toString();
String[] sbfArr = sbf.substring(0, sbf.length() - 1).split(",");
MyURLClassLoader loader = (MyURLClassLoader) manager.getLoader();
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "craw", "craw");
conn.setAutoCommit(false);
String sql = "INSERT INTO xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx VALUES(?,?,?,?,?)";
String sql2 = "DELETE FROM xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx WHERE funcName=?";
PreparedStatement prest = conn.prepareStatement(sql);
PreparedStatement prest2 = conn.prepareStatement(sql2);
for (int i = 0; i < sbfArr.length; i++) {//jar檔案中的表示式類名與資料庫比較,jar中存在,資料庫中不存在的,批量新增
if(!funcNamesStr.contains(","+sbfArr[i]+",")){
boolean existFlag = false;
Class cls = loader.loadClass("com.thread.lock."+sbfArr[i]);
Method[] methods = cls.getMethods();
String templateName = sbfArr[i] +"(";
for (Method method : methods) {
if("action".equals(method.getName())) {
existFlag = true;
int argsCount = method.getGenericParameterTypes().length;
for (int n = 1; n < argsCount; n++) {
templateName += "${" + n + "},";
}
if (argsCount > 1) {
templateName = templateName.substring(0, templateName.length() - 1);
}
templateName += ")";
prest.setString(1, sbfArr[i]);;
prest.setString(2, templateName);
prest.setString(3, "1");
prest.setString(4, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
prest.setString(5, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
prest.addBatch();
}
}
if(!existFlag) {
classMap.remove(sbfArr[i]);
}
cls = null;
templateName = "";
}
else {
funcNamesStr.replace(","+sbfArr[i]+",", ",");
}
}
loader = null;
prest.executeBatch();
if(funcNamesStr.length() > 1) {//jar中不存在,資料庫中存在的,批量刪除
String[] noExistArr = funcNamesStr.substring(1, funcNamesStr.length() - 1).split(",");
for (int i = 0; i < noExistArr.length; i++) {
prest2.setString(1, noExistArr[i]);
prest2.addBatch();
}
prest2.executeBatch();
}
conn.commit();
conn.close();
Set set = classMap.keySet();
for (Object object : set) {
System.out.print(object + " : ");
System.out.println(classMap.get(object));
}
}
}
} catch (Exception e) {
ARE.getLog().error("初始化儲存jarDetails資訊出錯!", e);
} finally {
if(null != conn) {
try {
conn.close();
} catch (SQLException e) {
ARE.getLog().error("資料庫連線關閉失敗", e);
}
}
}