精华内容
下载资源
问答
  • 问题描述应用稍复杂一点之后,往往要引入多种不同的中间件,各种第三方jar,这就导致我们往往会遇到jar包冲突的问题,如果冲突的jar包是兼容的,我们需要选择合适的版本,把不合适的版本排除掉,虽然过程复杂点,...

    问题描述
    应用稍复杂一点之后,往往要引入多种不同的中间件,各种第三方jar,这就导致我们往往会遇到jar包冲突的问题,如果冲突的jar包是兼容的,我们需要选择合适的版本,把不合适的版本排除掉,虽然过程复杂了点,但是如果冲突的jar包之间不兼容,那么不管选择哪个版本,都会出问题。
    我们可以使用类似于OSGI这样的重框架来解决这类问题,但是这类框架太重太复杂,难以掌握,实际上我们可以利用类加载器来解决这类问题,当不兼容的情况不是很复杂时,这种方案能高效解决问题,否则需要一种插件机制来解决问题。
    基本思路
    类加载器双亲委派机制
    这里先简单的介绍一下类加载器的双亲委派机制。JVM在加载类时默认采用的是双亲委派机制。就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;父类加载器无法完成此加载任务时,才自己去加载。我们可以看一下ClassLoader类中相关的代码:

    10759253da9f99b99465c0d0aacc36d8.png


    解决问题思路
    · 通过单独的类加载器加载依赖了不兼容的jar及中间件相关的jar,使用不同的中间件时,统一入口,用不同的类加载器加载相关的类并创建对象
    · 需要打破类加载器的双亲委派机制,单独创建出的类加载器要优先自己加载,加载不到则再委派给parent加载
    · 被独立的classloader所托管的jar包,不能再被原来的应用类加载器加载,否则会出现类型不匹配的异常,因为jvm判断类相同的依据是类名相同并且加载类的类加载器也相同,而被单独托管后的jar已经不是原来原始的应用类加载器了
    解决方案
    类的加载
    从URLClassLoader派生,定义一个名为ChildFirstClassLoader的类加载器,用于加载被托管的jar,代码如下:

    22d8719a14371e56071af23ef23d4d91.png


    有了此类加载器后,我们需要在使用此类加载器前,找到指定的jar包在系统中的路径,如何找到此路径呢,有几种方法:
    1. 通过System.getProperty("java.class.path")可以拿到classpath下所有的jar路径,是一个String,不同的jar通过分号分割
    2. 通过类加载器,拿到URLClassLoader中的ucp,从ucp中可以拿到当前类加载器所托管的所有jar(适用于springboot)
    拿到了所有jar的路径后,即可以得到某个jar包与其在系统中的路径的对应关系,然后通过此对应关系与jar包名创建出独立的类加载器(ChildFirstClassLoader),这里以使用System.getProperty("java.class.path")为例子:

    bad8b9d7a98496fc30f650aac7433686.png


    有了此类之后,我们就解决了类的加载问题,加载类的方式如下(为了说明问题,jar名随意取,实际应用中的jar不方便写出来):
    private final ClassContainer container = new ClassContainer(getClass().getClassLoader(), "rocketmq-client-1.1.jar", "protobuf.jar");
    在创建相关对象中,使用container.getClass(className).newInstance()的方法创建对象即可
    解决类型不匹配的问题
    前文提到:被独立的classloader所托管的jar包,不能再被原来的应用类加载器加载,否则会出现类型不匹配的异常,因为jvm判断类相同的依据是类名相同并且加载类的类加载器也相同,而被单独托管后的jar已经不是原来原始的应用类加载器了
    为了解决这个问题,我人先解释一个概念:
    · 导出类:表示ClassContainer.getClass获取的类,且希望能让原始的应用类加载器加载到的类
    而解决此问题有两种思路:
    1. 的方式则是利用类加载器的双亲委派机制,在双亲委派机制中插入一环,无始的类加载器的parent变成新的类加载器,新的类加载器的parent设置成原来的类加载器的parent,伪代码如下:
    ClassLoader cl = getClass().getClassLoader();
    ExportClassLoader ecl = new ExportClassLoader(cl.getParent());
    setParent(cl, ecl);//将cl的parent设置成ecl
    原始的应用类加载器(cl)在加载类时,先委派给parent加载,当委派到我们人为插入的一环时(ecl),判断是否是导出类,如果是则通过ClassContainer.getClass获取,否则继续双亲委派
    2. 替换掉当前的URLClassLoader,用新的类加载器替代原有的应用类加载器
    在jdk1.6时,ClassLoader中的parent字段没有定义成final字段,因此第一种思路行得通,只需要在原来的应用类加载器和它的parent之间插入一个类加载器即可,如同思路1的伪代码
    但从jdk1.7开始,ClassLoader的final字段被定义成了final,此时我们只能通过代理的方式解决问题,同样创建新的类加载器ExportDelegateClassLoader,整体结构如下图:
    · AppClassLoader是原始的应用类加载器
    · parent表示AppClassLoader的父加载器
    · ExportDelegateClassLoader是新的类加载器,用于替换原始的应用类加载器AppClassLoader,ExportDelegateClassLoader与AppClassLoader的parent相同,且classpath也相同
    · ClassContainer前文描述过,不再描述

    fb12dc5b1a084404b4d3797238996fa3.png


    代码如下图,在加载类时,先判断是否是导出类,如果是则使用对应的ClassContainer获取类,否则加载类,具体逻辑见loadClass方法。同样,此代码只是为了说明问题,并不是实际应用的代码:

    d0c51b6894d1733265fead5d7e82e7fc.png


    最后,在系统入口处用新的ExportDelegateClassLoader加载应用的入口类,以main方法为例:

    529585d4059d9af54fec36c0b8f6ba1c.png
    展开全文
  • 这里我们使用maven deploy方式,将通用模块打成jar包,发布到nexus,让其他项目来引用,以更简洁高效方式来实现复用和管理。发布至nexus1、配置settings.xml在mavensettings.xml文件中设置标签,如: my-...
    c2c8d153f3930ad6bd29ca76d8f828bd.png

    简介

    在编码过程中,有些通用的代码模块,有时候我们不想通过复制拷贝来粗暴地复用,因为这样不仅体现不了变化,也不利于统一管理。这里我们使用maven deploy的方式,将通用的模块打成jar包,发布到nexus,让其他的项目来引用,以更简洁高效的方式来实现复用和管理。

    发布至nexus

    1、配置settings.xml

    在maven的settings.xml文件中设置标签,如:

     my-nexusadminadmin123

    2、配置项目中的pom.xml文件

    在项目的pom.xml文件中配置标签,如:

    my-nexushttp://192.168.1.33:8081/nexus/content/repositories/releases/my-nexushttp://192.168.1.33:8081/nexus/content/repositories/snapshots/

    注意:这里的id必须与setting.xml中的id一致,url为nexus相应仓库的链接地址。

    3、发布命令

    mvn deploy

    需要注意的是:maven会判断版本号后面是否带了-SNAPSHOT,如果带了则发布到snapshots仓库,否则发布到release仓库 如:

    com.testmy-testjar${project.release.version}1.81.0-SNAPSHOTproduct1.0

    默认使用打包的是-SNAPSHOT,如果要发布product环境的包至release仓库,则需使用mvn clean deploy -Pproduct命令。并且如果已经发布了就不要重复发布了,因为,nexus不会覆盖原来已发布的jar包,如需发布可以更改版本号。

    展开全文
  • 最近在学习 OSGi,其实就是这两天。很久以前我曾经是一个 Java ...OSGi(Open Service Gateway Initiative)技术是面向Java动态模型系统。这个框架实现一个优雅、完整和动态地组价模型。应用程序(称为 bundle )...

    最近在学习 OSGi,其实就是这两天。很久以前我曾经是一个 Java 开发工程师,后来做了测试就再也没有碰过 Java 了。重新开始学习服务端,还是很有意思。OSGi 是什么呢?
    百度提供了一个搜索功能,一搜一大把。
    OSGi(Open Service Gateway Initiative)技术是面向Java的动态模型系统。这个框架实现了一个优雅、完整和动态地组价模型。应用程序(称为 bundle )无序重新引导可以被远程安装、启动、升级和卸载。
    OSGi 服务平台提供在多种网络设备上无需重启的动态改变构造的功能。为了最小化耦合度和促使这些耦合度可管理,OSGi 技术提供一种面向服务的架构,它能使这些组件动态地发现对方。
    OSGi 联盟已经开发了例如像 HTTP服务器、配置、日志、安全、用户管理、XML 等很多公共功能标准组件接口。这些组件的兼容性插件实现可以从进行了不同优化和使用代价的不同计算机服务提供商得到。然而,服务接口能够基于专有权基础上开发。
    OSGi 的主要职责就是为了让开发者能够创建动态化、模块化的 Java 系统。
    这篇文章讲的比较好:https://www.cnblogs.com/jingmoxukong/p/4546947.html。不过感觉没有长时间写过 Java 企业开发的同学,理解 OSGI 还是比较困难的,反正我还是一知半解。OSGi 的框架
    OSGi 的框架有很多,Equinox 看上去资料比较多,而且工作中也会有关系,所以就选择了 Equinox 来入门。Equinox 项目是 Eclipse 开源组织提供的 OSGi 框架的实现。Equinox 项目包括 OSGi R4 版本规范核心框架的实现,一系列 OSGi 标准服务 Bundle 及运行基于 OSGi 的系统的一些基础构件。用户可以直接访问该项目在 Eclipse 的网址 Equinox 获取概括性的信息。目前,关于Equinox的进展大部分资料及项目进展存在于Eclipse Wiki上。
    目前,Equinox 项目包括 OSGi 核心框架的实现,OSGi 标准服务 Bundle 实现,OSGi 的服务器端(J2EE 实现)应用,Equinox 部署更新框架及一些研究方向(未成熟发布的构想如JMX管理,安全管理,面向方面的设计与应用等)。IntelliJ IDEA + Equinox
    概念太难懂,不如直接实操。我的环境是:

    1. IntelliJ IDEA ULTIMATE 2019.1
    2. jdk 9
    3. equinox-SDK-4.11

    首先创建一个空的 OSGi 项目, Library 这里先选择 Set up library later

    23246503c8e7b143a3831cfc431fb9e6.png


    在 ide 的设置里,配置 Equinox

    b2f06fe47d0a1a09379548b9a7eeebae.png


    在你的空项目里添加 Equinox 的依赖

    a5fa77f7875e649ab4d693453b9b34bd.png


    接下来我们创建一个 HelloWorldActivator.java,package com.hengwen.osgi;import org.osgi.framework.BundleActivator;import org.osgi.framework.BundleContext;public class HelloWorldActivator implements BundleActivator {
    @Overridepublic void start(BundleContext context) throws Exception {
    System.out.println("Hello, World!");
    }
    @Overridepublic void stop(BundleContext context) throws Exception {
    System.out.println("Goodbye, World!");
    }
    }
    这里会提示 Bundle activator is not registered in manifest。我们在 Module Setting 里设置下Manifest。一般来说应该会把Manifest文件放在项目里编辑,不过 idea 可以通过ide设置,然后会打到 Jar 包中去。

    b158f8e592e35a8cf36ed55a3c99bc4f.png


    然后,添加一个自定义运行:

    e13b7b7d5f902a2e824aeaf4c914bf85.png

    30b6441fb5dccaddf09998df4023f5cd.png


    运行之后,会在终端输出信息,可以看到我start 209 stop 209。209 是我们这个 HelloWorld bundle 的序号。到这里一个简单的 HelloWorld 模块就完成了。接下来,我们再添加一个新的 Bundle,给前面这个 Bundle 使用。在项目目录上右击添加新的module。

    104aaecbd6c41ba408a1caae8018f0b9.png


    我们创建一个接口 HelloService,一个实现类 HelloServiceImpl,目录结构就如下:

    b129829680554ddf3d2854dda5099d99.png

    package com.hengwen.osgi.service;public interface HelloService {public String sayHello();
    }package com.hengwen.osgi.service.impl;import com.hengwen.osgi.service.HelloService;public class HelloServiceImpl implements HelloService {
    @Overridepublic String sayHello() {
    System.out.println("Inside HelloServiceImple.sayHello()");return "Say Hello";
    }
    }
    现在,我们为它配置 Manifest,因为目前它没有 activator,所以就简单配置下。

    3b4830236ac21097379138ff470525e3.png


    注意这里配置了一个:Export-Package: com.hengwen.osgi.service,是为了其他的 bundle 能调用它,否则下面的代码就会报 HelloService not exported

    1b1863cc0fe80af8a7db15935b0231ba.png


    到目前为止,代码还是无法运行,虽然编译都正常(因为可见性已经解决),但是在 OSGi 的容器中,HelloServiceImpl 不能直接使用。我们需要注册服务,使用服务。我们再创建一个 activator

    e96b38cce1f401da5d1cdfd76bf01954.png

    package com.hengwen.osgi.service.impl;import com.hengwen.osgi.service.HelloService;import org.osgi.framework.BundleActivator;import org.osgi.framework.BundleContext;import org.osgi.framework.ServiceRegistration;public class HelloServiceActivator implements BundleActivator {
    ServiceRegistration helloServiceRegistration;
    @Overridepublic void start(BundleContext context) throws Exception {
    HelloService helloService = new HelloServiceImpl();
    helloServiceRegistration =context.registerService(HelloService.class.getName(), helloService, null);
    }
    @Overridepublic void stop(BundleContext context) throws Exception {
    helloServiceRegistration.unregister();
    }
    }
    我们把 HelloServiceActivator 配置到 Manifest 里

    ee7e43f26f9fc864d8bf70bdbb8372d1.png


    这样服务就注册好了。我们接下来就使用服务,修改前面那个 bundle 的 HelloWorldActivator,package com.hengwen.osgi;import com.hengwen.osgi.service.HelloService;import org.osgi.framework.BundleActivator;import org.osgi.framework.BundleContext;import org.osgi.framework.ServiceReference;public class HelloWorldActivator implements BundleActivator {
    ServiceReference helloServiceReference;
    @Overridepublic void start(BundleContext context) throws Exception {
    System.out.println("Hello World!!");
    helloServiceReference= context.getServiceReference(HelloService.class.getName());
    HelloService helloService =(HelloService)context.getService(helloServiceReference);
    System.out.println(helloService.sayHello());
    }
    @Overridepublic void stop(BundleContext context) throws Exception {
    System.out.println("Goodbye World!!");
    context.ungetService(helloServiceReference);
    }
    }
    现在我们再来运行一次,需要把新的这个bundle 加到 osgi 的运行配置中去。

    4b9753c55ace7ae7659d96589ec10ba6.png

    36d7d7c15dec04a1cdea2090d4e5d923.png


    调用就成功了。这样差不多一个简单的 Hello, IntelliJ IDEA + OSGi + Equinox 就完成了。大家有兴趣可以自己试试看。参考文档

    1. https://www.javaworld.com/article/2077837/java-se-hello-osgi-part-1-bundles-for-beginners.html —— Hello, OSGi, Part 1: Bundles for beginners
    2. https://www.cnblogs.com/garfieldcgf/p/6378443.html —— 深入理解OSGI:Java模块化之路
    3. https://blog.csdn.net/afandaafandaafanda/article/details/43083957 —— Equinox 和 OSGI 介绍
    4. http://osgi.com.cn/article/7289219
    5. https://www.jianshu.com/p/2c0c8091e3de


    作者: Lihuazhang (恒温)

    原文链接:https://testerhome.com/topics/19214

    转载文章时务必注明原作者及原始链接,并注明「发表于 TesterHome 」,并不得对作品进行修改。

    展开全文
  • 今天突然发现web项目打包后的exe居然有200M+,心想不应该有这么大的啊,于是检查一番发现引用的jar有130+个,仔细一瞅发现好多同名的但是不同版本的jar,比如说有commons-httpclient就有两个,3.0和3.1版本的。...

    今天突然发现web项目打包后的exe居然有200M+了,心想不应该有这么大的啊,于是检查了一番发现引用的jar有130+个,仔细一瞅发现好多同名的但是不同版本的jar,比如说有commons-httpclient就有两个,3.0和3.1版本的。这样直接导致了lib下有很多重复的jar,安装程序体积自然就上去了。

         打开POM.xml,运行了一下mvn dependency:tree 命令,查看依赖关系树形结构发现有两个jar都是依赖了commons-httpclient这个jar,但是这两个依赖的版本是不一样的,所以maven就把两个版本的都添加进来了。

         解决办法就是通过exclusions配置dependency中要排除的jar文件。 示例如下:

    <dependency>
        <groupId>org.codehaus.xfire </groupId>
        <artifactId>xfire-all </artifactId>
        <version>1.2.6 </version>
        <exclusions>
            <exclusion>
                <groupId>org.springframework </groupId>
                <artifactId>spring </artifactId>
            </exclusion>
        </exclusions>
    </dependency>

     

    这样就排除了xfire中的spring依赖。同理,根据maven依赖树可以看到哪些jar是重复依赖的,然后通过exclusions排除掉重复的项就可以了。

    转载于:https://www.cnblogs.com/lslvxy/p/3516933.html

    展开全文
  • 2. 删除libs文件夹下android-support-v4.jar; 3. 右击项目, 选择Properties-->Android-->点击Library选项框中Add...按钮-->添加需要Library-->然后会发现自动生成Android Private Libraries, 观察androi
  • Eclipse隐藏引用的jar

    2017-12-05 17:00:32
    有时候,Eclipse左侧的源码或jar包管理框会列出每一个引用的jar包,如果引用的多,看起来会很烦或者不舒服,下面记录如何隐藏这些jar包。 Eclipse不同的版本左侧默认的东西不一样,例如J2EE重量级版本的可能就...
  • 不同的模块,会各自应用自己需要的jar包依赖,就会导致不同的模块引用了不同版本的jar包依赖,从而出现兼容性问题。还有为了方便版本的统一升级维护,防止部分模块的依赖升级,导致项目中的多个版本的同名jar。基于...
  • IDEA| 如何解决Maven的Jar版本冲突问题

    千次阅读 2019-09-03 19:15:42
    在实际项目开发过程中,会引用很多依赖,由于依赖本身也有依赖,如果使用了不同的版本,就会很容易遇到jar包冲突问题,因此,解决jar包冲突问题就显得尤为重要。 二.模拟依赖冲突 这里给大家模拟出一个Jar包冲突...
  • JAVA -- 项目引用jar

    2018-03-01 15:28:06
    如果想用jar包的内容,必须把jar包的内容加到classpath中在ecplise中要用jar包的内容,必须把jar包放到...但是有可能不同版本之间的jar互相冲突,从而导致整个项目无法使用,所以最好的就是放在各个项目的classpath...
  • 当项目中引用版本类库时,可能导致线程down,由于线上(1.6)线下(1.8)jdk版本不同,引入的jar包,所以试着排查新jar包的类版本。 排查过程 1.解压jar包 jar -xvf kafka-clients-0.10.0.0.jar 会有一...
  • 同一个项目中多个module存在多个相同命名的jar,且版本不同时易造成引入jar包但找不到相关的类。
  • 举例:将传统本地 javassit-3.17.1-GA.jar包 改成maven引用,pom中 ---Add 输入javassit 搜索      这时候会搜索出超级多 Artifact Id相同 但Group Id不同 包来(很多第三方);【这里前提是你先建远程...
  • 其中一个依赖里面是 ...又开始我直接删除第一个依赖的jar引用那一行,报错,找不到依赖,折腾一会,我在自己的moudle里面添加implementation 'com.king.zxing:zxing-lite:1.1.1',报错消失。 ...
  • Android Jar包冲突及解决方法

    千次阅读 2017-03-20 02:36:13
    Jar冲突产生: 情况一:在libs文件jar中与compile“gradle路径”形式... 情况三:(compile“gradle路径”形式引用)主程序与module以compile形式引用了同一jar包,但是他们的版本不同。 》Jar包冲突报错#Error:Ex
  • maven详解-(7)继承

    2017-10-25 14:46:20
    多个项目都要引用jar包,可能每个项目都引用了不同版本的jar包造成混乱,比如有的模块使用的是spring3.0,有的模块使用的是spring4.0,那么就会很混乱。2.案例分析案例逻辑跟上一篇介绍的maven的聚合类似,都是由一...
  • 解决Gradle中jar冲突

    千次阅读 2018-04-27 10:51:22
    如果有两个依赖引用了相同jar包的不同版本时,默认情况下gradle会采用最新版本的jar包,此时可以通过排除选项来排除。首先,看一下依赖一个库时的格式,name也就是module compile group:'com.android.support',name:...
  • 现在有个类需要引用外部jar包,但是版本比EAR中的那个版本要高,可是这个jar中的结构变,所以需求是要2个不同版本的jar都要引用。但因为是tomcat部署,所以本来是不应该考虑EAR问题的,问题是Ecl...
  • 在cmd环境下,输入如下命令:mvndependency:tree,根据jar包的依赖树,我们可以查找上面发生冲突 的jar包(jar包的版本不一样),查看同一个包是否引用了不同路径下的同名jar包。如果是,可以用e
  • 出现两个不同的版本,导致不同的问题。 例如:工程 A 添加 rxandroid:2.0.1 和adapter-rxjava 两个libs. 而adapter-rxjava中使用rxandroid:1.1.5 这样在工程中就会出现两个不同的类库。 引用的
  • MyEclipse关于查看Jar引入问题

    千次阅读 2016-12-19 14:09:53
    此方法有一个缺点:如果一个项目中有好几个相同名字但是版本不同的Jar,比如POI3.10.jar和POI3.14.jar,这样我们就不知道此类引用了哪个Jar包,于是产生第二种方法。  2、在程序中写入如下代码,输出Jar的绝对路径...
  • 1、由于整合组件多了,很容易存在不同组件引用同一个jar不同版本,比如netty-all这个包: ...2、三个包引用了不同版本,所以在父pom文件中指定netty-all引用版本: <dependency> <groupI...
  • maven工具使用技巧

    2018-08-20 16:31:25
    1、svn如何编辑冲突:在eclipse中冲突文件右击选择team--&gt;编辑冲突,然后对两个文件进行合并,以左边那个为准,合并...2、maven中两个jar A,B同时引用了不同版本的jar C1,C2,然后程序调用的时候是调用哪个...
  • 一、何为依赖冲突 Maven的依赖机制会导致Jar包的冲突...这时候,Maven会将这1.0的C和2.0的C都下载到你的项目中,这样你的项目中就存在了不同版本的C,可能会出现两种情况: 1.A和B引用的C版本相同,这时按照pom定义...
  • jackson 完整Jar

    2018-11-16 15:09:26
    他们是Jackson的两大分支、也是两个版本的不同包名。Jackson从2.0开始改用新的包名fasterxml;1.x版本的包名是codehaus。除了包名不同,他们的Maven artifact id也不同。1.x版本现在只提供bug-fix,而2.x版本还在...
  • 记一次jar包冲突

    2016-06-02 10:29:00
    题记:永远不要在同一个项目中,引用不同版本的两个jar包,否则,这可能就是一个大坑。 在做网校项目的时候,帮助中心要使用lucene,所以就引入lucene-5.5.1的包,删掉原先存在于项目中的lucene-3.0.0的包, ...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 122
精华内容 48
关键字:

引用了不同版本的jar