- 浏览: 2188349 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (682)
- 软件思想 (7)
- Lucene(修真篇) (17)
- Lucene(仙界篇) (20)
- Lucene(神界篇) (11)
- Solr (48)
- Hadoop (77)
- Spark (38)
- Hbase (26)
- Hive (19)
- Pig (25)
- ELK (64)
- Zookeeper (12)
- JAVA (119)
- Linux (59)
- 多线程 (8)
- Nutch (5)
- JAVA EE (21)
- Oracle (7)
- Python (32)
- Xml (5)
- Gson (1)
- Cygwin (1)
- JavaScript (4)
- MySQL (9)
- Lucene/Solr(转) (5)
- 缓存 (2)
- Github/Git (1)
- 开源爬虫 (1)
- Hadoop运维 (7)
- shell命令 (9)
- 生活感悟 (42)
- shell编程 (23)
- Scala (11)
- MongoDB (3)
- docker (2)
- Nodejs (3)
- Neo4j (5)
- storm (3)
- opencv (1)
最新评论
-
qindongliang1922:
粟谷_sugu 写道不太理解“分词字段存储docvalue是没 ...
浅谈Lucene中的DocValues -
粟谷_sugu:
不太理解“分词字段存储docvalue是没有意义的”,这句话, ...
浅谈Lucene中的DocValues -
yin_bp:
高性能elasticsearch ORM开发库使用文档http ...
为什么说Elasticsearch搜索是近实时的? -
hackWang:
请问博主,有用solr做电商的搜索项目?
Solr中Group和Facet的用法 -
章司nana:
遇到的问题同楼上 为什么会返回null
Lucene4.3开发之第八步之渡劫初期(八)
如上图所示:
es api组件依赖guava18.0,spark项目由于业务需要写入es所以需要依赖es ,但spark项目的环境又需要依赖guava14.0,如果换成高版本可能会报错,这个决定了你不能都使用统一的低版本或者高版本来规避此问题,因此必须面对现实。
导致异常的原因简单说下:
spark环境首先启动,导致jvm里面已经加载了guava14.0,这个时候jvm不会加载es依赖的guava18.0,而当es初始化的时候,恰巧需要使用guava18.0新版本的api,而这个api在14.0里面却并不存在,这个时候就会发生异常,就是我们常看到的:
``` java.lang.NoSuchMethodException ```
在深入了解一下,为什么会发生这个异常?是因为java里面的类加载器是双亲委派模式,一个类只需要在双亲委派模式下正常加载过(唯一全限定名:包名+类名)一次,就不会重复加载,从而引发了上面的问题。想要解决这种问题,靠重新再写一个类加载器是不现实的,因为重新写一个类加载器,不遵守双亲委派模式,就相当于把环境隔离了,技术上可行,但没法解决问题,如果A加载器加载的类,要调B加载器里面的类,或者B调A,会引发新的依赖问题。
那么如何比较优雅的解决这种进退两难的困境问题呢? maven-shade-plugin的出现,就可以解决这个问题的。它的解决手段也非常简单,前面说明JVM类加载器只会加载某个类一次,是通过全路径的包名+类名来区分做到的,我们要想加载不同版本的同一个类,有两种简单的方式,第一种改类名,第二种改包名。综合考虑来说改包名是最为妥当的一种方式,如果改了类名,那么要修改和替换的地方就要比改包名复杂的多了,不仅类调用的每一个地方都要替换,另外包名导入的地方也需要替换(.*导入除外,现实中不建议用这种方式),而修改包名,只需要把每一个依赖该类的类文件头部导入路径调换成新的即可,文件里面的类无需修改。
通过maven-shade-plugin插件的功能,就可以很容易做到这件事。
解法是:
单独为es的依赖创建一个maven项目,然后pom里面引入依赖的es组件,并对es组件里面依赖的guava的包名和部分组件,进行shade修改,如下:
``` <groupId>es.shade</groupId> <artifactId>es-shade</artifactId> <version>1.0-SNAPSHOT</version> <properties> <elasticsearch.version>2.3.4</elasticsearch.version> </properties> <dependencies> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>${elasticsearch.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.1</version> <configuration> <createDependencyReducedPom>false</createDependencyReducedPom> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <relocations> <relocation> <pattern>com.google.guava</pattern> <shadedPattern>my.elasticsearch.guava</shadedPattern> </relocation> <relocation> <pattern>org.joda</pattern> <shadedPattern>my.elasticsearch.joda</shadedPattern> </relocation> <relocation> <pattern>com.google.common</pattern> <shadedPattern>my.elasticsearch.common</shadedPattern> </relocation> <relocation> <pattern>com.google.thirdparty</pattern> <shadedPattern>my.elasticsearch.thirdparty</shadedPattern> </relocation> </relocations> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer" /> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ```
通过这样修改后再进行打包,那么相当于把所有guava这个改名后的组件和es的依赖在编译后的class文件层进行绑定,将其两者变成一个整体依赖jar,并且这个组件也会自动修改es里面所有导入guava的旧路径为改动后的新路径,看如下从反编译后的jar中,拷贝出来的类文件信息:
改动后的guava的MoreExecutors这个类文件头部,变成了我们修改后的包名:
```java package my.elasticsearch.common.util.concurrent; import my.elasticsearch.common.collect.*; import java.lang.reflect.*; import my.elasticsearch.common.base.*; import my.elasticsearch.common.annotations.*; import java.util.concurrent.locks.*; import java.util.*; import java.util.concurrent.*; public final class MoreExecutors { // 省略主体内容 } ```
注意头部的包名已经变成了my.elasticsearch.common替代了原来的com.google.common。
下面我们再看下es源码里面依赖的guava路径是否变化,打开org.elasticsearch.threadpool.ThreadPool这个类,我们发现其头部已经变成了新的guava路径,如下:
```java package org.elasticsearch.threadpool; import org.elasticsearch.common.component.*; import org.elasticsearch.node.settings.*; import org.apache.lucene.util.*; import my.elasticsearch.common.collect.*; import org.elasticsearch.common.*; import org.elasticsearch.common.util.concurrent.*; import org.elasticsearch.common.unit.*; import org.elasticsearch.common.collect.*; import org.elasticsearch.common.settings.*; import java.util.concurrent.*; import org.elasticsearch.common.logging.*; import my.elasticsearch.common.util.concurrent.*; import java.io.*; import org.elasticsearch.common.io.stream.*; import org.elasticsearch.common.xcontent.*; import org.elasticsearch.cluster.settings.*; import org.elasticsearch.cluster.*; import java.util.*; import java.util.regex.*; public class ThreadPool extends AbstractComponent { // 省略主体内容 } ```
如此已来,这个shade jar里面的es就只对这个版本的guava进行了绑定依赖,这个时候在spark项目中,引入这个es的uber-shade-jar,就不会发生冲突,通过使用不同的包名完美解决了类冲突的问题,这两个类都可以被同一个JVM虚拟机加载,这样以来,spark仍旧可以使用guava14.0版本,而我们的es也可以完美的使用改名后的guava18.0的版本,从而比较优雅的解决了这种不可避免的多版本冲突问题。
https://stackoverflow.com/questions/13620281/what-is-the-maven-shade-plugin-used-for-and-why-would-you-want-to-relocate-java
有什么问题可以扫码关注微信公众号:我是攻城师(woshigcs)
路漫漫其修远兮,吾将上下而求索
发表评论
-
记一次log4j不打印日志的踩坑记
2019-09-22 01:58 1588### 起因 前几天一个跑有java应用的生产集群(200多 ... -
如何轻松理解二叉树的深度遍历策略
2019-07-03 23:33 1148我们知道普通的线性数据结构如链表,数组等,遍历方式单一 ... -
为什么单线程Redis性能也很出色
2019-01-21 18:02 2220高性能的服务器,不一 ... -
如何将编程语言里面的字符串转成数字?
2019-01-11 23:23 2108将字符串转成数字在很 ... -
为什么Java里面String类是不可变的
2019-01-06 18:36 1680在Java里面String类型是不可变对象,这一点毫无疑问,那 ... -
关于Java里面volatile关键字的重排序
2019-01-04 18:49 1082Java里面volatile关键字主 ... -
多个线程如何轮流打印ABC特定的次数?
2018-12-11 20:42 6060之前的一篇文章,我给 ... -
聊聊Java里面的引用传递
2018-11-16 21:21 991长久以来,在Java语言里面一直有一个争论,就是Java语言到 ... -
理解计数排序算法的原理和实现
2018-10-11 10:03 2096计数排序(Counting sort) ... -
理解Java7和8里面HashMap+ConcurrentHashMap的扩容策略
2018-09-06 11:31 3393### 前言 理解HashMap和Con ... -
关于Java里面多线程同步的一些知识
2018-07-18 09:45 1111# 关于Java里面多线程同步的一些知识 对于任何Java开 ... -
Java单例模式之双检锁深入思考
2018-07-08 12:25 3296# Java单例模式之双检锁 ... -
关于Java里面多线程同步的一些知识
2018-07-08 12:23 1122# 关于Java里面多线程同步的一些知识 对于任何Java开 ... -
重新认识同步与异步,阻塞和非阻塞的概念
2018-07-06 14:30 1475# 重新认识同步与异步 ... -
线程的基本知识总结
2018-06-27 16:27 1063### (一)创建线程的方式 (1)实现Runnable接口 ... -
Java里面volatile关键字修饰引用变量的陷阱
2018-06-25 11:42 1389# Java里面volatile关键字修饰引用变量的陷阱 如 ... -
关于Java里面的字符串拼接,你了解多少?
2018-06-25 11:28 1373# 关于Java里面的字符串 ... -
深入理解Java内存模型的语义
2018-06-25 11:39 744### 前言 Java内存模型( ... -
如何证明Java多线程中的成员变量数据是互不可见的
2018-06-21 10:09 1507前面的几篇文章主要介绍了Java的内存模型,进程和线程的定义, ... -
给Java字节码加上”翅膀“的JIT编译器
2018-06-20 10:12 1038# 给Java字节码加上”翅 ...
相关推荐
进退两难.doc
进退两难?对症下药!企业服务器虚拟化应用思辨.pdf
在人生旅途中,我们难免会遇到各种各样的困境,其中最让人感到进退两难的莫过于那些两难的选择,例如亲情与事业、理想与现实、个人自由与社会责任等。如何在这些复杂的选择面前保持冷静和理智,是每个人都需要面对的...
可以尝试寻求心理咨询,学习处理冲突和压力的技巧,同时,与伴侣进行开放、诚实的对话,共同解决存在的问题。 7. 伴侣支持:在婚前焦虑中,伴侣的理解和支持至关重要。如果圆子的男友不能理解她的感受,可能需要两...
标题和描述中的“进退两难,甲醇春检等风来,春耕渐近,尿素整体易涨难跌”这句话,虽然看似简洁,但其实蕴含了丰富的行业信息,主要涉及化工领域的两个重要产品——甲醇和尿素,以及它们在特定季节(春季)的价格...
这份文档是一份关于招商期货研究所能化组谭洋在2021年3月21日发布的关于甲醇市场分析的报告。报告的核心内容包括甲醇市场基本面的回顾、未来行情的研判以及甲醇春检情况的分析。报告指出,由于宏观因素的走弱、新增...
当行业需要其技术解决...研究DSS行业的快速膨胀,可了解由于在指定的市场范围内增加技术应用的种类所引起的进退两难的局面。将DSS应用到不同的环境中后,不仅仅只是扩充其性能;而是必须改变其性能和大量变量的范围。
6. 家国共进退的社会责任:在当前的宏观经济与社会背景下,投资决策还需要考虑企业社会责任,即如何通过投资促进社会公益、环境可持续性,以及如何响应国家在扶贫、教育、医疗等领域的政策引导。 7. 全球化与本土化...
这些方法广泛应用于解决线性和非线性方程组,尤其是在科学计算和工程问题中。 首先,让我们来了解一下"进退法"。这是一种迭代法,通常用于求解线性方程组。进退法(也称为高斯-塞德尔迭代法)是对简单迭代法的改进...
在编程领域,尤其是在解决最优化问题时,"确定搜索区间的进退法"是一种非常重要的算法策略。进退法,也称为二分逼近法或区间裁剪法,是通过不断缩小搜索范围来寻找最优解的一种方法。在C#中,我们可以利用其强大的...
《进退法迭代求解无约束一维极值问题》是探讨如何使用MATLAB软件高效求解无约束一维极值优化问题的论文。一维极值问题是优化领域中的基础问题,在许多科学和工程应用中都有广泛的应用,如参数估计、模型拟合、机器学习...
java web学生成绩后台管理系统,基于mvc设计模式实现,可以做为java毕业设计项目 项目描述 (1)该系统的用户分为教师和学生。...jar包文件 链接:https://pan.baidu.com/s/1CJAQAT74hKD1MlsVwbCdCw 提取码:vuex
在计算机科学和工程领域,尤其是在编程中,如C语言,它常用于解决非线性优化问题。进退法的基本思想是沿着函数增大的方向移动,直到找到一个局部最小值,即函数值不再增加的点。 在Visual Studio 2008这样的开发...
在MATLAB环境中,该方法被广泛应用于解决无约束优化问题,尤其是当函数没有明显的导数或者导数计算复杂时。本文将深入探讨进退法的基本原理、MATLAB实现以及其在实际应用中的优势。 进退法的核心思想是利用两个固定...
进退法和黄金分割法是两种在数值计算和优化问题中常见的寻找极值(最小值或最大值)的方法。在实际应用中,这两种方法都属于迭代算法,通过不断调整参数来逼近目标函数的最优解。 **进退法(Bisection Method)** ...
总之,在市场竞争格局下,现在和未来一段时间内,企业之间,员工之间竞争的胜负,关键取决于“长板”。要想找到“长板”,或者希望自己成为团队中的“长板”,发掘优势比弥补缺陷更重要。
HTTPS协议是HTTP与SSL/TLS的结合,用于解决HTTP通信中的安全问题,包括数据被监听、被篡改以及被伪装的风险。HTTPS通过加密技术保证了通信的安全性,采用共享密钥加密和公开密钥加密相结合的方式,确保了数据的保密...
优化设计学上机实验进退法搜索单峰区间的VB程序,非常棒
本文将详细阐述施工总包在管理措施和配合分包商方面的主要内容。 首先,施工总包管理措施的核心是站在全局视角,以业主的需求为中心,高效地解决问题并推进工程进展。这包括协助业主处理专业分包项目,参与材料和...