两个jar包中,有相同资源,如何加载。

本文介绍了一种在Java环境中动态加载不同Jar包中同名资源文件的方法,通过使用类加载器获取所有匹配的资源,实现了灵活扩展的功能。此外,还讨论了另一种方案,即通过加载特定名称的类来实现动态替换。

两个jar包中,有相同资源,如何加载。

现在有AAA.jar和BBB.jar, 每个jar中有一个test.properties的文件,下面代码实现如何进行加载这两个同名文件。


效果,可以实现jar的可随意加载和拆卸

如:实现一个功能框架,对数据库每一种数据的一种处理方式,现在又一个新的类型的数据,我只需要新写个jar,里面放上这么一个文件。

框架每次启动时,都会读指定名称的资源配置文件,通过这个资源文件找到这个jar包的入库类。一般这个类需要实现一个指定接口,便于框架调用。

这样增加一个全新的实现,框架不修改任何代码和配置,新jar包安装标准默认方式,就可以参与运行。

public static void main(String[] args) {

        try {
            Enumeration<URL> ps = Thread.currentThread().getContextClassLoader().getResources("test.properties");

            while (ps.hasMoreElements()) {
                InputStream in = null;
                try {
                    in = ps.nextElement().openStream();
                    Properties p = new Properties();
                    p.load(in);
                    System.out.println(p.getProperty("config.dir"));
                }
                finally {
                    if (in != null) {
                        try {
                            in.close();
                        }
                        catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

        }
        catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

    }


其实实现这个功能,还有一个方式,就是框架类加载一个指定名称的类,这个类在客户化jar包中实现。这样可以动态更换实现类,

这种方式的缺点是,每次执行有一种处理方式被加载到内存中。


第一种方式,性能是个问题点。

第二种方式,处理多类型数据上存在缺陷。


其实目的就是动态扩展

实际项目中可以通过Spring(applicationContext.getBeansOfType(class))取的指定实现某个类的一批bean来加载扩展类,实现动态扩展


在Java中,类路径冲突是一个常见问题,尤其是在项目依赖多个库时。当不同JAR含同名的类时,类加载器可能会加载错误的类版本,从而导致程序行为异常或抛出异常。 ### 类路径冲突的原因 类路径冲突通常由以下几种情况引起: - 多个依赖库引入了相同类的不同版本。 - 系统类加载器(如`Bootstrap ClassLoader`)与应用程序类加载器之间存在类定义的重叠。 - 不同模块或组件使用了相同命名空间下的类,但实现不同。 ### 如何解决类路径冲突 #### 1. **调整类路径顺序** Java类加载器按照类路径(`CLASSPATH`)的顺序来查找和加载类。因此,将优先使用的JAR放在类路径的前面可以确保其类被优先加载。例如,在命令行中使用`-cp`参数时,可以这样指定: ```bash java -cp my-preferred.jar:other-libraries.jar com.example.Main ``` 在这种情况下,`my-preferred.jar`中的类将优先于`other-libraries.jar`中的类被加载[^2]。 #### 2. **使用`-jar`参数时的注意事项** 如果使用`-jar`参数运行一个JAR文件,则所有其他类路径设置都会被忽略,只有该JAR文件中的类会被加载。因此,若需要加载外部JAR中的类,应避免使用`-jar`参数,而改用`-cp`显式指定路径[^2]。 #### 3. **扩展类加载器(Extension ClassLoader)** 可以通过将特定的JAR文件放置在`JAVA_HOME/jre/lib/ext`目录下,使它们通过扩展类加载加载。这种方式可以让这些JAR中的类优先于普通类路径中的类被加载。然而,这种方法可能导致与其他JAR中的类产生冲突,因为它们可能也依赖于相同的类名[^3]。 #### 4. **自定义类加载器** 对于复杂的类加载需求,尤其是需要隔离不同版本的相同类时,可以使用自定义类加载器。例如,创建一个工具类,使用`URLClassLoader`动态加载特定JAR文件中的类,并通过反射调用其方法。以下是一个示例实现: ```java import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; public class CustomClassLoader { public static void main(String[] args) throws Exception { // 指定加载JAR文件 URL jarUrl = new URL("file:/path/to/your/jarfile.jar"); // 创建自定义类加载器 URLClassLoader classLoader = new URLClassLoader(new URL[]{jarUrl}); // 加载类 Class<?> clazz = classLoader.loadClass("com.example.MyClass"); // 获取方法并调用 Method method = clazz.getMethod("myMethod", String.class); Object result = method.invoke(null, "Hello World"); System.out.println(result); } } ``` 此方法允许在同一应用中同时使用不同版本的相同类,每个类由不同的类加载加载,从而避免冲突[^4]。 #### 5. **使用构建工具管理依赖** 现代Java项目通常使用Maven或Gradle等构建工具来管理依赖。这些工具提供了强大的依赖管理功能,括排除传递性依赖、指定依赖版本等。例如,在Maven的`pom.xml`中,可以使用`<exclusion>`标签排除不需要的依赖: ```xml <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> <exclusions> <exclusion> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> </exclusion> </exclusions> </dependency> ``` 通过这种方式,可以有效控制项目中使用的具体类版本,减少类路径冲突的可能性。 #### 6. **使用模块化(Java 9+)** 从Java 9开始,引入了模块系统(JPMS),允许开发者将代码组织为模块,并明确声明模块之间的依赖关系。这有助于避免类路径冲突,因为每个模块都可以明确指定它导出的及其依赖项。例如,定义一个模块: ```java module com.example.mymodule { exports com.example.api; requires java.base; requires some.other.module; } ``` 模块系统提供了一种更结构化的方式来管理类和资源,减少了传统类路径机制中的不确定性[^5]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值