jar文件解析,加载,卸载的简单实现

在项目开发时,由于需求的更变,需要实现对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);
				}
			}
		}

说明

MyURLClassLoader类主要是实现了jar文件的加载和卸载(由于原有的URLClassLoader类对jar文件的卸载功能不支持,所以需要早我实现一个MyURLClassLoader类).在使用时,通过一个管理类CustonFunctionJarManager来使用,而管理类通过工厂获得,并保证全局唯一,以控制线程安全.使用情况是在项目的启动时,需要到指定位置读取指定jar包,并解析jar包中在某一包下的所以类的类名,同时存储对于的class文件的MD5值在全局.之后从数据库中查出所以在数据库中的类名.将在jar中存在的,数据库中不存在的进行批量新增,将数据库中存在的,jar中不存在的,进行批量删除.之后在对jar包的上传更新时,可以从全局中取到jar包的MD5值,来判断是否需要更新,而表达式class文件的MD5值的作用是,在jar需要更新时,判断数据库中对应的表达式名是否需要更新(表达式名即为jar包中固定包下的类名).

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值