前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >由提交storm项目jar包引发对jar的原理的探索

由提交storm项目jar包引发对jar的原理的探索

作者头像
intsmaze-刘洋
发布2018-08-29 17:15:42
8350
发布2018-08-29 17:15:42
举报

序:在开发storm项目时,提交项目jar包当把依赖的第三方jar包都打进去提交storm集群启动时报了发现多个同名的文件错误由此开始了一段对jar包的深刻理解之路。

java.lang.RuntimeException: Found multiple defaults.yaml resources.

You're probably bundling the Storm jars with your topology jar.

[jar:file:/home/hadoop/app/storm/lib/storm-core-0.9.6.jar!/defaults.yaml,

jar:file:/home/hadoop/stormApi-wordcount-1.0-SNAPSHOT-jar-with-dependencies.jar!/defaults.yaml]

这里说明stom集群环境中有storm的jar包,我们提交的jar包里面也包含storm的jar包,在读取配置文件时,发现有一样的文件冲突了导致启动错误。

新浪微博:intsmaze刘洋洋哥

eclipse打jar包

代码如下:

代码语言:javascript
复制
package cn.intsmaze;
public class A {
public static void main(String[] args) {
System.out.println(args[0]);
System.out.println("java工程打jar包");
}
}
 
package cn.intsmaze;
import java.util.HashMap;
import java.util.Map;
import redis.clients.jedis.Jedis;
public class demo {
public static void main(String[] args)
{
System.out.println("java工程调用第三方jar包");
Jedis jedis = new Jedis("localhost", 6379);
Map map=new HashMap();
map.put("11", "1");
d.jedis.hmset("33", map);
d.jedis.close();
}
}

上面的代码的java工程如下:

使用eclipse把该工程打包成jar包:

选择这个jar包的入口类

把上面代码打包为A.jar后,eclipse会自动为我们生成下面这个文件位于META-INF:

MANIFEST.MF文件

Manifest-Version: 1.0

Main-Class: cn.intsmaze.A   这里指定入口类

把上面代码打包为B.jar

MANIFEST.MF文件

Manifest-Version: 1.0

Main-Class: cn.intsmaze.demo  这里指定入口类

因为这里引用了工程lib下面第三方的jar包,但是该jar包并不在classpath路径下面,所有就没有找到该类。

在MANIFEST.MF文件增加calsspath值即可。

Manifest-Version: 1.0

Main-Class: cn.intsmaze.demo

Class-Path: lib/jedis-2.8.0.jar 

然后我们把jedis-2.8.0.jar放到我们B.jar的同一级目录下即可。

这里成功运行了。

注意:

manifest.mf文件定义如下所示:

Manifest-Version: 1.0

Main-Class: com.Task

Class-Path: lib/dom4j-1.6.1.jar lib/jaxen-1.1-beta-7.jar

注意:

代码语言:javascript
复制
<1> manifest.mf文件最后一行必须是一个空行。
<2> lib/dom4j-1.6.1.jar和lib/jaxen-1.1-beta-7.jar之间用一个空格隔开。
<3>每个冒号后有一个空格。

Maven打包:

代码如下:

代码语言:javascript
复制
package cn.intsmaze;
public class A {
public static void main(String[] args) {
System.out.println(args[0]);
System.out.println("java工程打jar包");
}
}
 
package cn.intsmaze;
import java.util.HashMap;
import java.util.Map;
import redis.clients.jedis.Jedis;
public class demo {
public static void main(String[] args)
{
System.out.println("java工程调用第三方jar包");
Jedis jedis = new Jedis("localhost", 6379);
Map map=new HashMap();
map.put("11", "1");
d.jedis.hmset("33", map);
d.jedis.close();
}
}

如上代码当他们的pom文件中只配置了以下属性时:

代码语言:javascript
复制
 <dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.3</version>
</dependency>
</dependencies>

这个时候使用maven打包。观察他的目录结构。

这个jar包里面没有包含依赖的jedis的jar包,且manifest.mf文件中也没有指定入口类和Class-Path(该程序到哪里去加载它依赖的jedis.jar包)。

如果要成功运行这个jar包,我们要在manifest.mf设置Main-Class和Class-Path。

方式二:我们可以在pom文件中设置把工程打jar包时把它依赖的jar包也打进来,同时指定Main-Class。

代码语言:javascript
复制
 <build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>cn.intsmaze.demo.RedisDemo</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>

观察他的目录结构。

同时也会打一个没有带依赖的jar包(效果就和没添加插件设置一样)

在打包storm工程时的问题:

代码语言:javascript
复制
 <dependencies>
<dependency>
<groupId>org.apache.storm</groupId>
<artifactId>storm-core</artifactId>
<version>0.9.5</version>
</dependency>
</dependencies>

这个项目只会依赖jdk的jar包和storm的jar包,不依赖其他第三方jar包,我们把这个工程打出jar包,根据上面很明显我们知道jar包中不包含依赖的storm的jar包,且manifest.mf文件中也没有指定Main-Class和Class-Path。

但是把它提交到storm集群中,它是会运行的,这是因为stom集群的Class-Path的路径有jdk和storm的jar包了(我们使用java -jar命令就是jdk什么的。)。关于Class-Path我可以理解的,但是没有指定入口类,它是怎么启动的,我还要慢慢研究。

当上面的storm工程需要依赖第三方的mysql包时,我们必须在pom文件中要求把依赖的jar包打进来,不然我们要在manifest.mf指明它要到哪里去加载依赖的mysql包,同时还要把mysql包上传到我们打的jar包将要运行在那台机器上的指定目录让他可以根据Class-Path加载进去。

代码语言:javascript
复制
<dependencies>
<dependency>
<groupId>org.apache.storm</groupId>
<artifactId>storm-core</artifactId>
<version>0.9.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.27</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>cn.intsmaze.helloworld.WordCountTopologyMain</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>

这里把依赖的第三方jar包都打进去了。

但是我们提交该jar包到storm集群中,报了如下错误:

代码语言:javascript
复制
java.lang.RuntimeException: Found multiple defaults.yaml resources.
You're probably bundling the Storm jars with your topology jar.
[jar:file:/home/hadoop/app/storm/lib/storm-core-0.9.6.jar!/defaults.yaml,
jar:file:/home/hadoop/stormApi-wordcount-1.0-SNAPSHOT-jar-with-dependencies.jar!/defaults.yaml]

这里说明stom集群环境中有storm的jar包,我们提交的jar包里面也包含storm的jar包,在读取配置文件时,发现有一样的文件冲突了导致启动错误。

这个时候我们设置如下:

代码语言:javascript
复制
<dependency>
<groupId>org.apache.storm</groupId>
<artifactId>storm-core</artifactId>
<scope>provided</scope>期望JDK、容器或使用者会提供这个依赖
<version>0.9.5</version>
</dependency>

这个时候不会把依赖的storm的包打进工程中,只会把依赖的mysql包打进来。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-10-25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档