提交Spring-boot-fat-jar时触发ClassNotFound

时间:2018-07-06 09:15:13

标签: apache-spark

当我使用spring-boot建造一个胖子罐时,它的名字是 sparker4m-0.0.1.jar

然后我将其“火花提交”以产生星团。

./bin/spark-submit --deploy-mode client --class org.springframework.boot.loader.JarLauncher ~/Desktop/sparker4m-0.0.1.jar --spark.master=spark://172.16.179.52:7077 --source_path=file:///usr/local/spark-2.3.1-bin-hadoop2.7/hdfs_mock/1530842877616 --out_path=file:///usr/local/spark-2.3.1-bin-hadoop2.7/hdfs_mock/153084287761_out --hadoop.home.dir=/usr/local/hadoop

您可以看到我使用了“ --class org.springframework.boot.loader.JarLauncher”,因为它是Spring-boot-jar的主要类,而实际的主要类是test.sparker4m.Sparker4mApplication

这是我的代码:

@SpringBootApplication
public class Sparker4mApplication {
    public static void main(String[] args) throws Exception{
       ApplicationContext ctx = 
       SpringApplication.run(Sparker4mApplication.class, args);

       SparkConf conf = new SparkConf().setAppName("Test")
                    .setMaster(happyDay.getVal("spark.master"))
                    .set("spark.driver.host", Inet4Address.getLocalHost().getHostAddress());
       JavaSparkContext sc = new JavaSparkContext(conf);

       .........


       JavaPairRDD<String, String> transformed = rdd.mapToPair(new PairFunction<Tuple2<String, PortableDataStream>, String, String>() {
            @Override
            public Tuple2<String, String> call(Tuple2<String, PortableDataStream> tuple2) throws Exception {
                String fname = tuple2._1();
                PortableDataStream content = tuple2._2();
                byte[] bytes = content.toArray();
                String result = YUVSimpleTrans.transform(bytes);
                return new Tuple2<>(fname, result);
            }
        });

        ..........

        .........
    }
}

一切正常,但是,当 Excecutor 运行时,会引发异常:

Caused by: java.lang.ClassNotFoundException: test.sparker4m.Sparker4mApplication$1
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)

test.sparker4m.Sparker4mApplication $ 1是test.sparker4m.Sparker4mApplication使用的内部类,它应该是“ new PairFunction ,String,String>()”。

我认为,spark的Executor进程使用单个URLClassLoader加载类,但是我的(sprint-boot-fat-jar's)类都在 sparker4m-0.0.1.jar / BOOT-INF / classes < / strong>,并且我的依赖项jar都在 sparker4m-0.0.1.jar / BOOT-INF / lib 中,因此URLClassLoader无法加载该类。

对此有什么好主意吗?需要帮助!

1 个答案:

答案 0 :(得分:1)

最后,找到解决方案。

密钥是:

  • 1。它应将uber-jar与所有类和资源一起使用,而不应在“ jar lib”中使用
  • 2。必须了解“ JarLaucher”的工作原理。 JarLaucher由“ spring-boot-tools”提供,用于/ BOOT-INF / *(spring-boot 2.x)中的“ createArchive”和URLLoadClass并启动真正的Main类。

因此,如果完成“ 1”,则不需要“ 2”,因为我们不再需要/ BOOT-INF / *中的URLLoadClass。

解决方案是:使用 maven-shade-plugin (不带spring-boot-maven-plugin)来构建uber-jar,并定义您的真正的主类 >(而非JarLaucher)在此插件中使用org.apache.maven.plugins.shade.resource.ManifestResourceTransformer。

完成所有操作后,我发现一个问题Submitting spring boot application jar to spark-submit已经解决了,但是答案并没有明确指出您应该使用$ {start-class}( JarLaucher),但真正的主班