序:在開發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劉洋洋哥

Storm 為什麼淘汰_#jar

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工程如下:

Storm 為什麼淘汰_#java_02

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

Storm 為什麼淘汰_#java_03

選擇這個jar包的入口類

Storm 為什麼淘汰_#java_04

把上面代碼打包為A.jar後,eclipse會自動為我們生成下面這個文件位於META-INF:

Storm 為什麼淘汰_#maven_05

MANIFEST.MF文件

Manifest-Version: 1.0

Main-Class: cn.intsmaze.A   這裏指定入口類

Storm 為什麼淘汰_Storm 為什麼淘汰_06

把上面代碼打包為B.jar

Storm 為什麼淘汰_#java_07

MANIFEST.MF文件

Manifest-Version: 1.0

Main-Class: cn.intsmaze.demo  這裏指定入口類

Storm 為什麼淘汰_#java_08

因為這裏引用了工程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的同一級目錄下即可。

Storm 為什麼淘汰_#maven_09

Storm 為什麼淘汰_Storm 為什麼淘汰_10

這裏成功運行了。

注意:

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

Manifest-Version:1.0Main-Class:.TaskClass-Path:/dom4j-1.6.1.jar/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包打進來。