spring boot整合Hadoop

zzzzMing發表於2019-02-19

最近需要用spring boot + mybatis整合hadoop,其中也有碰到一些坑,記錄下來方便後面的人少走些彎路。

背景呢是因為需要在 web 中上傳檔案到 hdfs ,所以需要在spring boot中加入hadoop相關的jar包。在加入的過程中容易出一些錯誤,主要是包衝突這一類的問題,解決了之後就好了,在這裡順便記錄一下此次解決問題的思路,有需要的朋友可以看看。

一. Spring boot整合Hadoop依賴

先給出答案吧,要整合hadoop,比如在 web 中對Hdfs 進行一些處理什麼的,直接在pom.xml 中加入以下依賴就行。對了,記得要改成你對應的版本。

        <!-- hadoop 依賴 -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>2.7.4</version>
            <exclusions>
                <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId></exclusion>
                <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion>
                <exclusion> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </exclusion>
            </exclusions>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.7.4</version>
            <exclusions>
                <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId></exclusion>
                <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion>
                <exclusion> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>2.7.4</version>
            <exclusions>
                <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId></exclusion>
                <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion>
                <exclusion> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </exclusion>
            </exclusions>
        </dependency>

把這段程式碼放到pom.xml 裡面應該就沒問題了,這裡主要是需要用 來排除掉一些hadoop的依賴包,不知道 標籤的請自行百度。hadoop和 spring boot 衝突的主要有兩個,一個是slf4j的日誌包,一個是和tomcat衝突的 servlet-api 包,去掉 hadoop這兩個依賴就可以成功執行 spring boot 了。

二. 發現問題的思路

剛開始加入hadoop包的時候,出現了這樣的錯誤

Caused by: java.lang.IllegalStateException: Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError. See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details.

我就明白是因為日誌包log4j這些衝突了,於是就新增排除了這些包,但又有出現了新的錯誤。


java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[]]
    at java.util.concurrent.FutureTask.report(FutureTask.java:122) [na:1.8.0_151]
    at java.util.concurrent.FutureTask.get(FutureTask.java:192) [na:1.8.0_151]
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:941) ~[tomcat-embed-core-8.5.31.jar:8.5.31]
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:872) [tomcat-embed-core-8.5.31.jar:8.5.31]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [tomcat-embed-core-8.5.31.jar:8.5.31]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1421) [tomcat-embed-core-8.5.31.jar:8.5.31]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1411) [tomcat-embed-core-8.5.31.jar:8.5.31]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_151]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_151]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_151]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_151]

這個問題在網上搜了會都沒法解決,於是去 stackoverflod 找了找,直接給出解決方案的倒是沒有,不過看到了這個資訊:

Don't know if your problem is resolved. I had similar issues and found out that one of the dependencies is built with an older version of servlet-api. Springboot doesn't want you to include the servlet-api, but if the dependency is built with an older version, then you will see this error.

意思就是說這個錯誤是因為依賴中有其他版本的 servlet-api ,於是就會出現上面那個錯誤。看到這我再去 maven 裡面看了看 hadoop-common 的依賴,果然發現了個寶貝!

hadoop common中發現servlet包

然後就很簡單啦,把這玩意也給排除了,萬事大吉!!

相關文章