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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 序:在开发storm项目时,提交项目jar包当把依赖的第三方jar包都打进去提交storm集群启动时报了发现多个同名的文件错误由此开始了一段对jar包的深刻理解之路。 java.lang.
序:在开发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包
代码如下:
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
注意:
<1> manifest.mf文件最后一行必须是一个空行。
<2> lib/dom4j-1.6.1.jar和lib/jaxen-1.1-beta-7.jar之间用一个空格隔开。
<3>每个冒号后有一个空格。
 
Maven打包:
代码如下:
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文件中只配置了以下属性时:
 <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。
 <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工程时的问题:
 <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加载进去。
<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集群中,报了如下错误:
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包,在读取配置文件时,发现有一样的文件冲突了导致启动错误。
这个时候我们设置如下:
<dependency>
<groupId>org.apache.storm</groupId>
<artifactId>storm-core</artifactId>
<scope>provided</scope>期望JDK、容器或使用者会提供这个依赖
<version>0.9.5</version>
</dependency>
这个时候不会把依赖的storm的包打进工程中,只会把依赖的mysql包打进来。
 
 
作者: intsmaze(刘洋)
老铁,你的--->推荐,--->关注,--->评论--->是我继续写作的动力。
微信公众号号:Apache技术研究院
由于博主能力有限,文中可能存在描述不正确,欢迎指正、补充!
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
3小时前
|
Java Docker 容器
|
3小时前
|
Java Maven
向 Maven 中央仓库上传一个修改过的基于jeecg的autoPOI的 jar包记录(一)
向 Maven 中央仓库上传一个修改过的基于jeecg的autoPOI的 jar包记录
17 0
|
3小时前
|
JavaScript 前端开发 Java
java项目的打包将vue放到.jar里面部署
java项目的打包将vue放到.jar里面部署
|
3小时前
|
Java Go Maven
向 Maven 中央仓库上传一个修改过的基于jeecg的autoPOI的 jar包记录(二)
向 Maven 中央仓库上传一个修改过的基于jeecg的autoPOI的 jar包记录
10 0
|
3小时前
|
前端开发 Java Linux
宝塔Linux:部署His医疗项目通过jar包的方式
宝塔Linux:部署His医疗项目通过jar包的方式
|
3小时前
|
前端开发 Java 应用服务中间件
在虚拟机的Windows操作系统中:通过Jar方式若依项目,以及在外部的访问!
在虚拟机的Windows操作系统中:通过Jar方式若依项目,以及在外部的访问!
|
3小时前
|
安全 Java Docker
|
3小时前
|
Java
如何解决使用若依前后端分离打包部署到服务器上后主包无法找到从包中的文件的问题?如何在 Java 代码中访问 jar 包中的资源文件?
如何解决使用若依前后端分离打包部署到服务器上后主包无法找到从包中的文件的问题?如何在 Java 代码中访问 jar 包中的资源文件?
51 0
|
3小时前
|
Java Maven
springboot jar包启动提示没有主清单属性
springboot jar包启动提示没有主清单属性
|
3小时前
|
分布式计算 DataWorks Java
DataWorks产品使用合集之阿里云DataWorks专有云环境下,上传MaxCompute的UDF(用户自定义函数)的JAR包的步骤如何解决
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
22 0