序:在開發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.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包打進來。