java 依赖包冲突
问题描述
程序中同时使用了hadoop工具包与ElasticSearch工具导致jar包。
程序报错:
java.lang.NoSuchMethodError: com.google.common.util.concurrent.MoreExecutors.directExecutor()Ljava/util/concurrent/Executor;
内容如下:
-
java.lang.NoSuchMethodError: com.google.common.util.concurrent.MoreExecutors.directExecutor()Ljava/util/concurrent/Executor;
-
at org.elasticsearch.threadpool.ThreadPool.(ThreadPool.java:190)
-
原因分析
通过对上述错误进行google可以判断是由于Elasticsearch引用的guava包版本不正确而导致。程序中hadoop依赖的guava包版本为11版本,而ES所需要的版本为18以上。因此我们首先在maven中将guava的版本强制指定为18版本,但是将程序打包后上传到linux生成环境程序仍然无法正常运行。
解决方案
根据[官网博客][3]说明,我们将ElasticSearch以及它的相关依赖包以shade的打包成一个独立的jar包,对应ElasticSearch相关类的使用均从此jar包引用。
1、shade Elasticsearch包
- 首先创建新的maven工程,pom.xml文件如下:
-
<groupId>my.elasticsearch
</groupId>
-
<artifactId>es-shaded
</artifactId>
-
<version>1.0-SNAPSHOT
</version>
-
<properties>
-
<elasticsearch.version>2.1.2
</elasticsearch.version>
-
</properties>
-
<dependencies>
-
<dependency>
-
<groupId>org.elasticsearch
</groupId>
-
<artifactId>elasticsearch
</artifactId>
-
<version>${elasticsearch.version}
</version>
-
</dependency>
-
<dependency>
-
<groupId>com.google.guava
</groupId>
-
<artifactId>guava
</artifactId>
-
<version>18.0
</version>
-
</dependency>
-
</dependencies>
-
<build>
-
<plugins>
-
<plugin>
-
<groupId>org.apache.maven.plugins
</groupId>
-
<artifactId>maven-shade-plugin
</artifactId>
-
<version>2.4.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>org.elasticsearch
</pattern>
-
<shadedPattern>my.elasticsearch
</shadedPattern>
-
</relocation>
-
</relocations>
-
<transformers>
-
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer" />
-
</transformers>
-
</configuration>
-
</execution>
-
</executions>
-
</plugin>
-
</plugins>
-
</build>
在pom.xml中我们指定了该项目依赖org.elasticsearch包,且版本为2.1.2,并强制指定了guava的版本为18(此处若不指定应该也会自行依赖18以上的包,但并未进行测试)。然后在build标签中可以看出,我们利用maven的shade工具完成打包情况如下:
- org.joda映射为my.elasticsearch.joda
- com.google.guava映射为my.elasticsearch.guava
- com.google.common映射为my.elasticsearch.common
- org.elasticsearch映射为my.elasticsearch
然后利用mvn clean install命令进行打包得到es-shaded-1.0-SNAPSHOT.jar,创建一个属于你自己版本的Elasticsearch包。之后将该包上传到私服maven镜像。
2、在工程中使用自己的Elasticsearch包
完成上数对Elasticsearch的打包之后,在自己工程中的pom.xml中,我们引用此包方式如下:
-
<dependencies>
-
...
-
<dependency>
-
<groupId>org.apache.hadoop
</groupId>
-
<artifactId>hadoop-client
</artifactId>
-
<version>${hadoop.version}
</version>
-
</dependency>
-
<dependency>
-
<groupId>org.apache.hive
</groupId>
-
<artifactId>hive-exec
</artifactId>
-
<version>${hive.version}
</version>
-
</dependency>
-
<dependency>
-
<groupId>org.antlr
</groupId>
-
<artifactId>ST4
</artifactId>
-
<version>4.0.8
</version>
-
<scope>compile
</scope>
-
</dependency>
-
<dependency>
-
<groupId>my.elasticsearch
</groupId>
-
<artifactId>es-shaded
</artifactId>
-
<version>1.0-SNAPSHOT
</version>
-
</dependency>
-
</dependencies>
在使用上述方式引用了Elasticsearch包之后,在程序中我们可以这样对Elasticsearch包进行引用
代码如下:
-
import my.elasticsearch.ElasticsearchException;
-
import my.elasticsearch.action.bulk.BulkItemResponse;
-
import my.elasticsearch.action.bulk.BulkRequestBuilder;
-
import my.elasticsearch.action.bulk.BulkResponse;
-
import my.elasticsearch.action.index.IndexRequest;
-
import my.elasticsearch.client.transport.NoNodeAvailableException;
-
这样确保了我们使用的elasticsearch包是我们之前创建的。对Elasticsearch所依赖版本的 joda相关包的引用方式也是类似:
-
import my.elasticsearch.joda.time.DateTime;
-
这样就不会出现Elasticsearch依赖包不正确的情况。
- 使用JDBC从Hive中抽取数据,所以maven项目中有hive依赖库;
- 数据导入Elasticsearch,版本2.3.1其中guava库为18以上的版本
- hive与ES的guava版本冲突
- 现象:java.lang.NoSuchMethodError: com.google.common.util.concurrent.MoreExecutors.directExecutor()Ljava/util/concurrent/Executor;
解决方法
- 将Elasticsearch中冲突库,进行改名,重新打包;
- 在新项目中引入新打包的ES库
方法一:Shade and relocate
简介
- 为了避免ES中库与其他依赖库的冲突,可以选择将ES依赖的冲突库relocate,并映射到新的名词,避免库覆盖。
- 因为hadoop生产环境的更新并不方便,通过maven的shade插件,重新映射库版本更靠谱
Shade Elasticsearch
这一步将所依赖的ES库进行shade,创建一个新的maven项目,将依赖的Elasticsearch库依赖加入,并将冲突的库relocate,编译成新的jar
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>my.elasticsearch</groupId> <artifactId>es-shaded</artifactId> <version>1.0-SNAPSHOT</version> <properties> <elasticsearch.version>2.3.1</elasticsearch.version> </properties> <dependencies> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>${elasticsearch.version}</version> </dependency> <dependency> <groupId>org.elasticsearch.plugin</groupId> <artifactId>shield</artifactId> <version>${elasticsearch.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.4.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> <repositories> <repository> <id>elasticsearch-releases</id> <url>http://maven.elasticsearch.org/releases</url> <releases> <enabled>true</enabled> <updatePolicy>daily</updatePolicy> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> </project>
引入shade ES jar
在新的项目中引入上一步编译好的ES包
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>${guava.version}</version> </dependency> <dependency> <groupId>my.elasticsearch</groupId> <artifactId>es-shaded</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
参考:https://www.elastic.co/blog/to-shade-or-not-to-shade
方法二:修改集群job库加载策略(未实验)
-
<property>
-
<name>mapreduce.job.user.classpath.first</name>
-
<value>true</value>
-
</property>
-
-
参考文献
[1] https://www.elastic.co/blog/to-shade-or-not-to-shade [2] http://www.cnblogs.com/bigbigtree/p/6668542.html [3]:https://www.elastic.co/blog/to-shade-or-not-to-shade