1. 程式人生 > >idea 部署SpringBoot專案時打成jar包一些坑的總結

idea 部署SpringBoot專案時打成jar包一些坑的總結

前一段時間,公司分配給我做一些微服務的功能,比如一些分析、一些可以拿出來的模組,所以採用了SpringBoot搭建的微服務專案,至於關於SpringBoot的介紹,這裡就不展開了。今天主要寫的是這兩天我需要把我本地的專案部署到伺服器上,遇到的一個問題。還有我這兩天檢視網上的一些關於SpringBoot部署發現的其他人發現的一些問題,在這裡總結一下,用於以後能夠自己能夠快速檢視解決,當然如果能夠幫助大家就更好了。

SpringBoot部署到伺服器,首先我們需要將專案打成jar包,然後上傳到伺服器上,在執行jar。

spring-boot-maven-plugin

SpringBoot打成jar包我們一般使用spring-boot-maven-plugin這個外掛,當配置了該外掛後,執行“mvn package”進行打包時,會打包成一個可以直接執行的 JAR 檔案,使用“java -jar”命令就可以直接執行。這在很大程度上簡化了應用的部署,只需要安裝了 JRE 就可以執行。該外掛現在最新的版本應該是1.5.9.RELEASE,不過因為我的專案是使用了下面這個配置:
這裡寫圖片描述


所以 我本地的spring-boot-maven-plugin的版本是1.5.9.RELEASE的版本的,當然兩者的區別我就沒有仔細的研究了。

當然該外掛在使用的時候有一個屬性需要知道一下start-class,因為SpringBoot專案的啟動類是一個main方法,所以我們在使用外掛打包的時候需要注意一下,如果不注意可能會報錯,下面會寫。為什麼說需要注意start-class這個屬性呢,是因為spring-boot-maven-plugin在打成jar包時會預設找public static void main(String[] args){***}方法,這時候如果你的專案有多個main方法,這時候就會有問題了,所以你可以刪掉其他的main方法,只留SprngBoot的入口main方法,或者在pom.xml中用上述屬性指定你的專案指定方法,比如:
這裡寫圖片描述


上面的就是我指定的BinggouLogAnalysisApplication這個裡面的啟動類。當然我建議無論你是否有多個main方法,都指定一下,防止以後多一個main方法,到時候報錯,不知道為啥。

SpingBoot專案Tomcat常用配置

SpringBoot整合的web容器有我們常用的tomcat容器或者Jetty容器,具體的由配置決定,當然其預設整合的是tomcat容器,
這也說明了,只要我們打成jar包,理論上該jar在任何一個有JRE的伺服器上即可執行.,不需要再在伺服器上配置tomcat等web容器,這也體現了SpringBoot的微服務的概念。下面是一些tomcat的常用配置:

# tomcat最大執行緒數,預設為200
server.tomcat.max-threads=800
# tomcat的URI編碼
server.tomcat.uri-encoding=UTF-8
# 存放Tomcat的日誌、Dump等檔案的臨時資料夾,預設為系統的tmp資料夾(如:C:\Users\Shanhy\AppData\Local\Temp)
server.tomcat.basedir=H:/springboot-tomcat-tmp
# 開啟Tomcat的Access日誌,並可以設定日誌格式的方法:
#server.tomcat.access-log-enabled=true
#server.tomcat.access-log-pattern=
# accesslog目錄,預設在basedir/logs
#server.tomcat.accesslog.directory=
# 日誌檔案目錄
logging.path=H:/springboot-tomcat-tmp
# 日誌檔名稱,預設為spring.log
logging.file=myapp.log

打jar包的問題

SpringBoot將專案打成jar包,在網上有兩種形式一種是使用idea工具打成jar包這有一個我覺得挺詳細的說明的在IDEA中如何將Spring boot專案打包成可執行的jar包併發布到linux伺服器,還有一種是直接在cmd中切換到專案所在目錄,然後執行mvn package 或者新增一個clean :mvn clean package。當然這種方法你可以使用windows系統的預設的cmd.exe程式,還可以用idea或者eclipse,呼叫cmd的功能。

1.說一下我自己的專案遇到的一個問題,就是我在打jar包的時候,打包失敗,報了一個這個錯誤:

[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.986 s
[INFO] Finished at: 2018-01-26T10:01:04+08:00
[INFO] Final Memory: 34M/278M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.5.7.RELEASE:repackage (default) on project ***: Execution default of goal org.springframework.boot:spring-boot-maven-plugin:1.5.7.RELEASE:
repackage failed: Plugin org.springframework.boot:spring-boot-maven-plugin:1.5.7.RELEASE or one of its dependencies could not be resolved: Could not find artifact org.codehaus.plexus:plexus-interpolation:jar:1.21 in Public Reposi
tories (http://****/nexus/content/groups/public/) -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginResolutionException

當然上面的錯誤是我解決之後,為了演示重現的。
從上面的報錯資訊中我們可以看到:報的是不能執行目標外掛spring-boot-maven-plugin:1.5.7.RELEASE,是因為少了spring-boot-maven-plugin:1.5.7.RELEASE外掛或者少了jar包org.codehaus.plexus:plexus-interpolation:jar:1.21,
當時的報錯資訊不止少了這一個,是少了很多,我當時看到少jar包,我的第一反應是看我的pom.xml對於這些jar的引用,但是沒找到,最後仔細研究了一下報錯資訊發現了這一句:one of its dependencies could not be resolved,它的依賴jar包。這也說明了這個是spring-boot-maven-plugin外掛的依賴,是在外掛的自己的引用,我們這邊沒法改這些依賴jar的版本。
我查了我本地的jar,發現這些jar包的低版本都有,但是沒有報錯的版本,我又看了我們公司的私服,也沒有,所以我就想著把spring-boot-maven-plugin外掛的版本降低一些,但是沒用,它的所有版本的依賴的jar版本都是一樣的。。這樣只能自己從網上找相應的jar然後存在本地的倉庫,並且上傳到公司的私服上去了。bug解決

這裡說一個小常識,就是對於他們提示的org.springframework.boot:spring-boot-maven-plugin:1.5.7.RELEASE這樣的錯誤,我們在查詢我們倉庫的時候怎麼定位到它的路徑呢,其實很簡單它的路徑就是org/springframework/boot/spring-boot-maven-plugin,我想不要我再說什麼了。並且我們可以根據上面的提示直接寫出它在pom.xml的jar包引用:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>1.5.7.RELEASE</version>
        </dependency>

以“:”分割,第一部分是groupId,第二部分是artifactId,第三部分就是版本version了。

2.我在網上檢視資料的時候,發現了有一個bug很多,但是我不明報為什麼又這麼多人會有這個bug,感覺很不可思議的,我感覺只要對SpringBoot有一點研究的,應該都不會出現的:

Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.4.0.RELEASE:repackage (default) on project springBootDemo: Execution default of goal org.springframework.boot:spring-boot-maven-plugin:1.4.0.RELEASE:repackage failed: Unable to find main class -> [Help 1]  

就是這個錯,其主要資訊是“Unable to find main class”,也就是沒有找到main方法,其實我覺的對於SpringBoot專案,它的main方法應該是最重要的把,在它的類上應該需要配置很多的註解的,要不專案也沒法啟動的,demo流程也沒法走通的。
其實上面的錯就是上了main方法,或者main方法的類上面少了@SpringBootApplication註解。因為spring-boot-maven-plugin外掛必須註解@SpringBootApplication重寫main方法。

下面賦一下我的SpringBoot的main方法:

@SpringBootApplication
@RestController
@ServletComponentScan("***.***.***")
@ComponentScan(basePackages={"***.***.***"})
@MapperScan(basePackages={"***.***.***"})//Mapper掃描註解
@EnableScheduling //定時任務註解
public class ***{

	public static void main(String[] args) {
		SpringApplication.run(***.class, args);
	}
}

我在這說一下上面的一些註解:
@SpringBootApplication
這個註解是SpringBoot的一個組合註解,用於組合以前的Spring專案的 @Configuration,@EnableAutoConfiguration,@ComponentScan。
這三個註解也就是說
@SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan

@Configuration的註解類標識這個類可以使用Spring IoC容器作為bean定義的來源。@Bean註解告訴Spring,一個帶有@Bean的註解方法將返回一個物件,該物件應該被註冊為在Spring應用程式上下文中的bean。@EnableAutoConfiguration:能夠自動配置spring的上下文,試圖猜測和配置你想要的bean類,通常會自動根據你的類路徑和你的bean定義自動配置。
@ComponentScan:會自動掃描指定包下的全部標有@Component的類,並註冊成bean,當然包括@Component下的子註解@Service,@Repository,@Controller。

@RestController
這個註解也是SpringBoot的一個組合註解,它相當於@ResponseBody + @Controller。至於這兩個註解的功能就不細說了。

@ServletComponentScan
該註解主要用於當使用Spring boot的嵌入式servlet容器時,可以通過Spring bean或掃描Servlet元件的方式註冊Servlet、Filter和Servlet規範的所有監聽器,後面的路徑就是掃描的路徑,他會掃描改路徑下的包以及所有子包。這裡就要說一下SpringBoot的一個很蛋疼的事情了,我們都知道SpringBoot的Application啟動類,是非常重要的,這時候我們想要寫一個servlet介面,需要用到service和dao以及mapper,但是可能你會發現你寫的@service,@mapper註解,掃描不到,這是因為SpringBoot預設的掃描路徑是你的Application入口類的子包以及它下面的包,如果你的程式碼不在這個範圍,那麼SpringBoot是掃描不到的。

@ComponentScan、@MapperScan

這兩個和上面的類似,都是指定掃描的路徑的,這個路徑你可以配置多個比如:

basePackages={"***.***.***","***.***.***"}

@EnableScheduling

這個註解使用於SpringBoot的定時任務的註解,加上這個註解,SpringBoot就會掃描 有@Scheduled(cron=“0 0 10 * * ?”)的類作為定時任務。詳細的大家可以檢視下其他的資料。

上面是我發現的幾個問題,如果以後還有其他的問題,我會一一新增的。

當然對於SpringBoot的部署是很簡單的,只需要把專案打成的jar上傳的伺服器上切換到相應的目錄,然後執行

java -jar ***.jar 

就可以了

生成jar包名稱沒有帶版本號

在伺服器上生成jar時,生成沒問題,同事發現生成的jar包名沒有帶專案的版本號,但是我的pom檔案的上面的確指定了版本

    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging>
    <groupId>bg_anaytics</groupId>
    <artifactId>bg_anaytics</artifactId>
    <version>1.0.0-SNAPSHOT</version>

後來搜了一下,發現了這樣一個問題,就是我的build裡面加了finalName這個屬性是指定生成的jar包名稱的。遮蔽它就可以了,當然你想指定jar名稱的話,需要配置一下這個finalName。

    <build>
        <finalName>bg_anaytics</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <!--在添加了該外掛之後,當執行“mvn package”進行打包時,會打包成一個可以直接執行的 JAR 檔案,使用“java -jar”命令就可以直接執行。這在很大程度上簡化了應用的部署,只需要安裝了 JRE 就可以執行。-->
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

從網上偶爾看到了一個可能有用的build屬性
這裡寫圖片描述

伺服器後臺執行,以及日誌過多解決
對於SpringBoot打成的jar,我們想要在伺服器上執行,只需要伺服器有jdk即可,因為SpringBoot自帶tomcat。
在伺服器上執行打成的jar包,一般我們只需要執行:java -jar ****.jar 即可。

但是隻是執行上面的jar的話,如果我們關掉了xshell之類的頁面,該程式就會停掉,所以我們可以使用nohup對它進行後臺執行:nohup java -jar ****.jar &即可

當然我們也可以在執行時指定很多引數,比如埠號等等,基本上在配置檔案配置的引數我們都是可以指定的:nohup java -jar ****.jar --server.port=9091 &

上面執行的程式會預設將程式的所有日誌打到jar包所在目錄的nohup.out檔案中,其中的日誌非常詳細,會導致日誌很多,一個定時任務會每天產生上百G的日誌,而我們基本會在程式中列印logger日誌,該處的日誌會顯得比較冗餘,這時候我們不需要該日誌,由於暫時沒有找到nohup命令不打日誌的命令,後來想到可以利用linux的黑洞 也就是/dev/null關於這個,大家可以百度一下。所以如果我們不想要nohup日誌,我們可以直接將日誌打到黑洞裡面:nohup java -jar ***.jar --server.port=9091 >/dev/null 2>&1 &