Java运行时动态加载类之ClassLoader加载class及其依赖jar包

2023-10-26

需求场景是:通过ClassLoader动态加载外部class文件,class文件又依赖某个具体jar包,需要动态加载jar包,采用URLClassLoader。

1、xml配置文件

<?xml version="1.0" encoding="ISO-8859-1"?>
<classes>

 <class name="User"> 
 <jar>ETLEnc.jar</jar>
 <method>say</method> 
 </class> 

</classes>

放在D:\\tmp\\目录下;

2、User.class文件放在D:\\tmp\\目录下,依赖ETLEnc.jar也放在D:\\tmp\\目录下,User代码如下:

package cn.fjs;

import com.gddx.enc.ETLEncode;

public class User {
	
	public void say(String name){
		ETLEncode ete=new ETLEncode();
		try {
			System.out.println(ete.encrypt(name));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	} 
}

其中com.gddx.enc.ETLEncode是ETLEnc.jar包中的类。

3、xml文件解析类代码:

package cn.fjs;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element; 
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
 
//解析xml文件,获取类和方法
public class DynamicDom {
	private static DocumentBuilderFactory dbFactory = null;  
    private static DocumentBuilder db = null;  
    private static Document document = null;  
    
    static{  
        try {  
            dbFactory = DocumentBuilderFactory.newInstance();  
            db = dbFactory.newDocumentBuilder();  
        } catch (ParserConfigurationException e) {  
            e.printStackTrace();  
        }  
    }  
    
   
    public Map<String,List<String>> getMethods(String fileName) throws SAXException, IOException{  
    	Map<String,List<String>> classes = new HashMap<String, List<String>>();
    	document = db.parse(fileName);  
    	NodeList nList = document.getElementsByTagName("class");
    	for(int i = 0 ; i<nList.getLength();i++){ 
    		Node node = nList.item(i); 
    		Element ele = (Element)node; 
    		if(node.getNodeType() == Element.ELEMENT_NODE){
    		  String clazz = ele.getAttribute("name"); 
    		  List<String> methods = new ArrayList<String>();
    		  String method = ele.getElementsByTagName("method").item(0).getTextContent();
    		  methods.add(method);
    		  classes.put(clazz, methods); 		  
    		}
    	}
    	return classes;
    } 
    
    public Map<String,List<String>> getJars(String fileName) throws SAXException, IOException{  
    	Map<String,List<String>> classes = new HashMap<String, List<String>>();
    	document = db.parse(fileName);  
    	NodeList nList = document.getElementsByTagName("class");
    	for(int i = 0 ; i<nList.getLength();i++){ 
    		Node node = nList.item(i); 
    		Element ele = (Element)node; 
    		if(node.getNodeType() == Element.ELEMENT_NODE){
    		  String clazz = ele.getAttribute("name"); 
    		  List<String> jars = new ArrayList<String>();
    		  String jar = ele.getElementsByTagName("jar").item(0).getTextContent();
    		  jars.add(jar);
    		  classes.put(clazz, jars); 		  
    		}
    	}
    	return classes;
    } 
}

4、动态加载jar包工具类:

package cn.fjs;

import java.io.File;  
import java.lang.reflect.Method;  
import java.net.URL;  
import java.net.URLClassLoader;  
import java.util.ArrayList;  
import java.util.List;

public final class JarLoaderUtil {
	/** URLClassLoader的addURL方法 */  
    private static Method addURL = initAddMethod();  
      
    /** 初始化方法 */  
    private static final Method initAddMethod() {  
        try {  
            Method add = URLClassLoader.class  
                .getDeclaredMethod("addURL", new Class[] { URL.class });  
            add.setAccessible(true);  
            return add;  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return null;  
    }  
  
    private static URLClassLoader system = (URLClassLoader) ClassLoader.getSystemClassLoader();  
  
    /** 
     * 循环遍历目录,找出所有的JAR包 
     */  
    private static final void loopFiles(File file, List<File> files) {  
        if (file.isDirectory()) {  
            File[] tmps = file.listFiles();  
            for (File tmp : tmps) {  
                loopFiles(tmp, files);  
            }  
        } else {  
            if (file.getAbsolutePath().endsWith(".jar") || file.getAbsolutePath().endsWith(".zip")) {  
                files.add(file);  
            }  
        }  
    }  
  
    /** 
     * <pre> 
     * 加载JAR文件 
     * </pre> 
     * 
     * @param file 
     */  
    public static final void loadJarFile(File file) {  
        try {  
            addURL.invoke(system, new Object[] { file.toURI().toURL() });  
            //System.out.println("加载JAR包:" + file.getAbsolutePath());  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
  
    /** 
     * <pre> 
     * 从一个目录加载所有JAR文件 
     * </pre> 
     * 
     * @param path 
     */  
    public static final void loadJarPath(String path) {  
        List<File> files = new ArrayList<File>();  
        File lib = new File(path);  
        loopFiles(lib, files);  
        for (File file : files) {  
            loadJarFile(file);  
        }  
    }  
}

参考:http://blog.csdn.net/fjssharpsword/article/details/64905874

URLClassLoader也可以动态加载jar包的类并执行具体方法。


5、测试类:

package cn.fjs;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.Map;
import cn.fjs.DynamicClassLoader;
import cn.fjs.DynamicDom;

public class DynamicClassLoaderTest {
	public static String FilePath="D:\\tmp\\";
	public static void main(String[] args) {
		DynamicDom dmo = new DynamicDom();//xml文件解析类
		Map<String, List<String>> classes;
		Map<String, List<String>> jars;
		try {
			//动态记载依赖包
			jars = dmo.getJars(FilePath+"a.xml");
			for(String key:jars.keySet()){
				for(String jar : jars.get(key)){
					JarLoaderUtil.loadJarFile(new File(FilePath+jar));
				}
			}		
			//动态加载类
			DynamicClassLoader loader = new DynamicClassLoader(new String[]{FilePath});
			classes = dmo.getMethods(FilePath+"a.xml");
			for(String key:classes.keySet()){ 
				for(String clazz : classes.get(key)){ 
					Class<?> c =loader.findClass(key);//类名字
					//c.getMethod(clazz).invoke(c.newInstance());//方法名字
					c.getMethod(clazz,String.class).invoke(c.newInstance(),"fjs");//带参数
				}
			} 
		}catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java运行时动态加载类之ClassLoader加载class及其依赖jar包 的相关文章

  • Spring 配置:无法找到 Spring NamespaceHandler

    配置问题 无法找到 XML 模式名称空间的 Spring NamespaceHandler http www springframework org schema tx http www springframework org schema
  • 检查 Java servlet 的 HTTP POST 请求的内容类型

    我编写了一个简单的 servlet 它接受 HTTP POST 请求并发回一个简短的响应 这是 servlet 的代码 import java io BufferedInputStream import java io ByteArrayI
  • 如何使用Gson序列化Optional类?

    我有一个具有以下属性的对象 private final String messageBundle private final List
  • App Engine 日志中的 /_ah/queue/__deferred__

    我有一个使用 Google Cloud SQL 的 App Engine 应用程序 并且从我的应用程序的页面中我正在执行一些数据库操作 每当访问此页面时 它都无法执行所有数据库操作 当我进入控制台时 我看到的只是 ah queue defe
  • 与Java混淆覆盖访问级别[重复]

    这个问题在这里已经有答案了 可能的重复 为什么不能降低java子类中方法的可见性 https stackoverflow com questions 1600667 why cant you reduce the visibility of
  • 我们如何使用 StringBuilder 在字符串前面添加字符串?

    我知道我们可以使用附加字符串StringBuilder 有没有一种方法可以使用前置字符串 即在字符串前面添加字符串 StringBuilder这样我们就可以保持性能优势StringBuilder offers 使用位置参数设置为 0 的 i
  • Android:Json 无法从 mysql 数据库检索任何文件,它是空的

    我是 android 新手 我正在使用 mysql 数据库 其中我链接 php 文件进行连接 工作正常 但我的代码没有显示任何内容 它只显示背景色黑色 而不是显示数据库中的数据 public class HomeFragment exten
  • Hibernate - 一对多关系和孤儿删除级联

    我有一个基本的一对多关系父 子关系 就像 Hibernate 参考书第 21 章中一样 级联仅从子级到父级 保留级联只是因为我不想在删除子级时删除父级 当我向父级添加一个子级并保存该子级时 出现 TransientObjectExcepti
  • 使用 google app-engine 跨浏览器/服务器重新启动会话持久性

    如何使会话在浏览器 服务器重新启动后持续存在 我正在使用谷歌应用程序引擎 每次重新启动浏览器和 或服务器时 我都会得到一个新的会话 ID String jSessionId this getThreadLocalRequest getSes
  • 如何使用 poi 获取 java 中单元格的数据验证源?

    I have defined a list of valuses my list in one excel sheet as follow 在另一个 Excel 工作表中 我将某些单元格引用到该列表 以便该列表在单元格中显示为下拉列表 如下
  • 单击 libGDX 中的 Actor

    我的游戏中有一个覆盖层 其中包含屏幕图像和屏幕 上 的一组按钮 截屏 My Screen有一个Stage The Stage有一组Group对象 我将其视为图层 第一组具有背景 中间的组具有游戏元素 最前面的组具有屏幕覆盖 覆盖层由一个Im
  • 如何为 Android 应用实施 Google Play 许可? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话
  • Clojure/Java:用于声音频谱分析的 Java 库? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个可以接受大量音频数据并返回给定频带内随时间变化的平均幅度的库 我已经在 comp dsp
  • 编写无 BOM 的 UTF-8

    这段代码 OutputStream out new FileOutputStream new File C file test txt out write A getBytes 和这个 OutputStream out new FileOu
  • java 对字母数字字符串进行排序

    我有这个数组存储用户添加的一些 URL 的后缀 U2 U3 U1 U5 U8 U4 U7 U6 当我这样做时 for Map
  • java中调用父构造函数

    我有两节课Parent and Child 而Parent有一个需要 3 个参数的构造函数 class Parent public Parent String host String path int port 现在我想要Child构造函数
  • 为什么枚举可以有包私有构造函数?

    既然枚举构造函数只能由其常量调用 为什么允许它是包私有的呢 构造函数实际上不是包私有的 它是隐式的private接口方法的隐式方式public即使您不添加关键字 JLS 的相关部分 8 8 3 http docs oracle com ja
  • Primefaces 中的过滤数据表仅有效一次

    我正在尝试使用 Primefaces 过滤数据表 就像这个例子 http www primefaces org showcase ui datatableFiltering jsf 在网络浏览器中 我输入要过滤的文本 它会工作一次 但是当我
  • Eclipse 中的预构建事件

    我有一个使用 jaxb 进行一些 xml 处理的项目 如何在 eclipse 中设置预构建事件以在构建项目之前执行 xjc 转到项目 gt 属性 gt 构建器 创建您自己的构建器并启用它 并在构建器的配置中启用 自动构建期间 等 如下所示
  • Spring Data JPA 中使用 @Query 进行动态查询?

    我在 Spring Boot 应用程序中使用规范 可以通过不同的过滤器选项过滤结果 但是 我需要使用特殊的过滤器 Query在我的存储库方法中 据我所知 我无法在此查询中构建动态 WHERE 子句 还有 QueryDSL 和 Criteri

随机推荐