天天看點

SpringBoot學習 @SpringBootApplication和熱部署

接上篇文章,今天繼續學習Spring Boot文檔,

禁用具體的自動配置的類

在前面的文章中寫道

spring boot

是可以在項目啟動的時候,根據

pom.xml

中的

spring boot

依賴進行繼承,相關的依賴會自動配置,那麼如何來禁用其中某個自動配置的類,下面來說一下方法:

可以看一下

@EnableAutoConfiguration

注解的源碼:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * 排除指定的自動配置類,這樣它們就永遠不會被執行
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * 如果要排除的類不在目前路勁中,可以使用該方法
	 * 排除,需要指定那些類的名字的全限定的類的名字,
	 * 這樣它們就永遠不會被執行
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}
           

比如可以這樣寫:

@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
           

最後,還可以使用

spring.autoconfigure.exclude

屬性控制要排除的自動配置類的清單。

舉例:

@ComponentScan

注解可以掃描到它的包及子包下的所有

bean

,比如下面這個例子:

package com.example.demo;

import com.example.demo.sub.ExtralClass;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        ExtralClass extra =  context.getBean(ExtralClass.class);
        System.out.println(extra);
    }
}
           
package com.example.demo.sub;

import org.springframework.stereotype.Component;

@Component
public class ExtralClass {
}
           

從代碼可以看出來

ExtraClass

Application.java

的子包的類,我們通過在

application.java

中列印,發現執行了,而且列印出了如下的資訊,說明該

ExtralClass.java

也被納入到容器中進行管理。

SpringBoot學習 @SpringBootApplication和熱部署

當我們使用

@SpringBootApplication

注解中的屬性對于指定的類進行排除,那麼我們在啟動項目的時候會看到一場資訊,比如添加了

exclude

屬性來禁用,讓掃描不到

ExtraClass

package com.example.demo;

import com.example.demo.sub.ExtralClass;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication(exclude = ExtralClass.class)
public class Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        ExtralClass extra =  context.getBean(ExtralClass.class);
        System.out.println(extra);
    }
}
           

運作異常資訊如下:

SpringBoot學習 @SpringBootApplication和熱部署

從異常資訊中可以看出,這裡說了,

ExtralClass.java

不是一個自動配置類,無法排除掉。

同樣也可以使用

@SpringBootApplication(excludeName = "com.example.demo.sub.ExtralClass")

,效果和上圖的錯誤資訊提示一緻。

Spring Bean和依賴注入

在我們的日常開發中,我們經常使用

@ComponentScan

注解來尋找你的

Bean

,通過使用

@Autowired

注解來進行構造器注入。

如果你在你的包的根目錄中的

application.class

,你可以添加

@ComponentScan

注解(可以不寫任何參數),你的應用的所有元件(

@Component

,

@Service

,

@Repository

,

@Controller

等等)會被自動的注冊為

Spring

的容器。

下面的這個例子是使用了

@Service

注解,進行構造器注入來擷取一個

RiskAssessor

Bean。

package com.example.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DatabaseAccountService implements AccountService {
	private final RiskAssessor riskAssessor;
	@Autowired
	public DatabaseAccountService(RiskAssessor riskAssessor) {
		this.riskAssessor = riskAssessor;
	}
}
           

Bean的注入方式:

關于

Bean

的注入我們有三種方式:

(1)構造器注入

(2)

setter

注入

(3)接口注入

其中我們最常用的第二種

Setter

注入的方式。

@SpringBootApplication注解

一般我們在

spring boot

項目中會使用

@SpringBootApplication

注解,因為它可以做到自動配置,元件類掃描和定義額外的配置類,也就是說一個注解可以達到三種效果,而這三種效果又相當于三個注解的作用,這三個等價注解分别是:

(1)

@EnableAutoConfiguration

:自動裝配依賴

(2)

@ComponentScan

:在應用程式所在的包上啟用@component 的掃描

(3)

@Configuration

:允許在上下文中注冊額外的

Bean

,或者引入額外的配置類

是以

@SpringBootApplication

注解相當于

@EnableAutoConfiguration

@ComponentScan

@Configuration

注解的綜合效果。

其實,在2.1.5版本中可以看到

@SpringBootApplication

注解中沒有明确寫

@Configuration

注解,但是存在一個

@SpringBootConfiguration

注解,在該注解中包含一個

@Configuration

注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//該注解中存在@Configuration注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM,
				classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
           
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}
           

@SpringBootApplication

也提供别名來定制這兩個屬性

@EnableAutoConfiguration

@ComponentScan

.

比如,你不想使用

@ComponentScan

注解來掃描自動将

bean

納入容器,你可以選擇使用

@Import

注解自己手動寫好需要納入容器的類:

package com.example.myapplication;

import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@EnableAutoConfiguration
@Import({ MyConfig.class, MyAnotherConfig.class })
public class Application {
	public static void main(String[] args) {
			SpringApplication.run(Application.class, args);
	}

}
           

如何來運作你的spring boot 的可執行jar

如果你将你的項目打包成為一個可執行的Jar,通過使用指令你可以運作你可執行的jar檔案,你打包好的jar檔案一般在你的target目錄下面,如果要運作可以參考如下指令:

$ java -jar target/myapplication-0.0.1-SNAPSHOT.jar
           

還可以在啟用遠端調試支援的情況下運作打包應用程式。這樣做可以将調試器附加到打包的應用程式,如下面的示例所示:

$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \
       -jar target/myapplication-0.0.1-SNAPSHOT.jar
           

使用Maven Plugin

Spring boot

項目有

maven plugin

,其中包含了一個

run

的全局指令,它可以很快的編譯并運作你的應用。下面是一個典型的例子:

$ mvn spring-boot:run
           

特别需要注意的是:當你的maven項目過大的時候,啟動項目可能會抛出溢出的異常資訊,此時,我們就需要設定一下maven的JVM參數,如下所示:

$ export MAVEN_OPTS=-Xmx1024m
           

使用Gradle插件

使用如下的指令:

$ gradle bootRun
           

如果項目啟動的時候出現溢出,那麼可以進行如下的作業系統設定:

$ export JAVA_OPTS=-Xmx1024m
           

總結:當出現溢出的時候,因為項目過大,此時我們就需要調整JVM參數,來調整一下堆的大小。

熱部署

可以采用JRebel插件。

spring boot

也提供了

spring-boot-devtools

子產品支援快速重新開機應用程式。

pom.xml

檔案中,你可以添加如下的依賴:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-devtools</artifactId>
	<optional>true</optional>
</dependency>
           

如果是在

gradle

中,可以添加如下的依賴:

configurations {
	developmentOnly
	runtimeClasspath {
		extendsFrom developmentOnly
	}
}
dependencies {
	developmentOnly("org.springframework.boot:spring-boot-devtools")
}
           

當你運作一個完整的包應用的時候,開發工具是被自動禁止的。如果你的應用是通過

java -jar

指令來運作或者是從一個特殊的加載器啟動,那麼該應用就會被認為是一個“生産應用”。如果不适用于你,那麼你就應該考慮排除掉

devtools

或者在系統屬性中進行如下的設定

-Dspring.devtools.restart.enable=false

預設情況下,重新打包的存檔不包含

devtools

。如果要使用某個遠端

devtools

功能,則需要禁用

excludedevtools build

屬性來包含它。

Maven

Gradle

插件都支援該屬性。

預設的屬性

SpringBoot

支援的幾個庫使用緩存來提高性能。例如,模闆引擎緩存已編譯的模闆,以避免重複解析模闆檔案。此外,

SpringMVC

還可以在服務靜态資源時向響應添加HTTP緩存頭。

雖然緩存在生産中非常有益,但在開發過程中它可能會适得其反,進而阻止您看到剛剛在應用程式中所做的更改。是以,

Spring-boot-devtools

預設禁用緩存。

緩存選項通常在

application.properties

檔案中進行設定。例如,

thymeleaf

提供

spring.thymeleaf.cache

屬性。

Springbootdevtools

子產品不需要手動設定這些屬性,而是自動應用合理的開發時間配置。

因為在開發

SpringMVC

SpringWebFlux

應用程式時需要更多關于

Web

請求的資訊,開發人員工具将為

Web

日志記錄組啟用

DEBUG

日志記錄。這将為您提供有關傳入請求、哪個處理程式正在處理它、響應結果等的資訊。如果您希望記錄所有請求詳細資訊(包括潛在的敏感資訊),可以打開

spring.http.log-request-details

配置屬性。

如果你不希望使用預設的屬性,那麼你可以在

application.properties

中設定

spring.devtools.add-properties=false

可以去這個類

DevToolsPropertyDefaultsPostProcessor

中檢視完整的

devtools

中包含的屬性:

static {
		Map<String, Object> properties = new HashMap<>();
		properties.put("spring.thymeleaf.cache", "false");
		properties.put("spring.freemarker.cache", "false");
		properties.put("spring.groovy.template.cache", "false");
		properties.put("spring.mustache.cache", "false");
		properties.put("server.servlet.session.persistent", "true");
		properties.put("spring.h2.console.enabled", "true");
		properties.put("spring.resources.cache.period", "0");
		properties.put("spring.resources.chain.cache", "false");
		properties.put("spring.template.provider.cache", "false");
		properties.put("spring.mvc.log-resolved-exception", "true");
		properties.put("server.error.include-stacktrace", "ALWAYS");
		properties.put("server.servlet.jsp.init-parameters.development", "true");
		properties.put("spring.reactor.stacktrace-mode.enabled", "true");
		PROPERTIES = Collections.unmodifiableMap(properties);
	}

           

自動重新開機

當你的應用中不管什麼時間,有檔案變動的時候,應用使用

spring-boot-devtools

自動重新開機。在你使用IDE的時候這個最有助于開發,避免你手動啟動項目,目前在我們項目中,我的IDEA中舊裝了

JRebel

插件,當你的檔案有改動的時候,項目就會自動編譯改動過的檔案。對于靜态的資源是不需要重新啟動應用的。

觸發重新啟動

由于devtools監視類路徑資源,觸發重新啟動的唯一方法是更新類路徑。導緻類路徑更新的方式取決于您使用的IDE。在Eclipse中,儲存修改過的檔案會導緻類路徑更新并觸發重新啟動。在intellij思想中,建構項目(build->build project)具有相同的效果。

DevTools

是依賴于應用上下文關閉

hook

的,如果你進行了如下的設定

SpringApplication springApplication = new SpringApplication(); springApplication.setRegisterShutdownHook(false);

那麼它目前就不可以正常工作。

當确定類路徑上的條目在更改時是否應觸發重新啟動時,devtools會自動忽略名為:

spring-boot, spring-boot-devtools

,

spring-boot-autoconfigure

,

spring-boot-actuator

, 和

spring-boot-starter

.

devtools

需要自定義

applicationContext

使用的

resourceloader

。如果您的應用程式已經提供了一個,那麼它将被包裝。不支援直接重寫

ApplicationContext

上的

getResource

方法。

重新啟動與重新加載

SpringBoot

提供的重新開機技術通過使用兩個類加載器來工作。不更改的類(例如,來自第三方

JAR

的類)被加載到基本類加載器中。您正在積極開發的類将加載到重新啟動的類加載器中。重新啟動應用程式時,會丢棄重新啟動類加載器并建立新的類加載器。這種方法意味着應用程式的重新啟動通常比“冷啟動”快得多,因為基本類加載器已經可用并已填充。

如果您發現重新開機對于您的應用程式來說不夠快,或者遇到了類加載問題,那麼您可以考慮重新加載技術,如

jrebel from zeroturnary

。這些方法是在加載類時重寫類,以使它們更易于重新加載。

總結:是以說,我們使用

JRebel

是對你修改過的類檔案進行重新加載,然後利用,而不是重新啟動項目,來加載所有的類檔案。

記錄條件評估中的更改

預設情況下,每次重新啟動應用程式時,都會記錄一個顯示條件評估增量的報告。當您進行諸如添加或删除bean以及設定配置屬性等更改時,報告将顯示對應用程式自動配置的更改。

要禁用報告的日志記錄,請設定以下屬性:

spring.devtools.restart.log-condition-evaluation-delta=false
           

資源排除

當某些資源發生變動的時候是不需要重新啟動的。比如

Thymeleaf

模闆可以被及時的編輯。預設的,改變這些下面的資源的時候,不會觸發項目重新啟動,但是會觸發一個

live reload

/META-INF/maven, /META-INF/resources, /resources, /static, /public, 或者 /templates

。如果你想定制這些排除,你可以使用

spring.devtools.restart.exclude

屬性,例如,排除掉

/static

/public

下改動的資源:

spring.devtools.restart.exclude=statis/**,public/**
           

如果要保留這些預設值并添加其他排除項,請改用

spring.devtools.restart.additional-exclude

屬性。

類路徑之外的檔案變動

你或許想要你的應用重新啟動或者加載當你改變了一些不在目前類路徑的檔案。此時可以使用

spring.devtools.restart.additional-paths

屬性來配置額外的路徑來關注檔案的變化。您可以使用前面描述的

spring.devtools.restart.exclude

屬性控制附加路徑下的更改是觸發完全重新啟動還是實時重新加載。

禁用重新開機項

在你不想使用重新開機項的時候,你可以使用

spring.devtools.restart.enabled

屬性的設定來禁用重新啟動。在大多數情況下,你可以在

application.properties

檔案中進行設定:

spring.devtools.restart.enabled=false
           

(雖然你禁用了重新啟動的屬性,仍然會初始化重新開機加載器,但是它會忽略檔案的變動)

如果你想完全禁用重新開機項支援(例如,因為它不适用于特定的類庫),在調用

SpringApplication.run(...)

方法之前,你可以設定

spring.devtools.restart.enabled

屬性通過

System

.,例如:

public static void main(String[] args) {
	System.setProperty("spring.devtools.restart.enabled", "false");
	SpringApplication.run(MyApp.class, args);
}
           

使用觸發器檔案

如果您使用的是一個持續編譯更改檔案的IDE,那麼您可能更喜歡隻在特定的時間觸發重新開機。為此,您可以使用“觸發器檔案”,這是一個特殊的檔案,當您想要實際觸發重新啟動檢查時,必須對其進行修改。更改檔案隻會觸發檢查,僅當devtools檢測到必須執行某些操作時才會重新啟動。觸發器檔案可以手動更新,也可以使用IDE插件更新。

要使用觸發器檔案,請将

spring.devtools.restart.trigger-file

屬性設定為觸發器檔案的路徑。

您可能希望将

spring.devtools.restart.trigger-file

設定為全局設定,以便所有項目的行為方式都相同。

自定義重新啟動類加載器

上面讨論過重新啟動和重新加載的差別,重新啟動是需要兩個類加載器,一個是未改變的類的加載器,一個是有改動的類的加載器。對于大多數應用,重新啟動都是管用的。但是,有時候重新啟動會造成一些加載的問題。

預設的,任何開源的項目在IDE中被加載都是通過“重新啟動

restart

"加載器,任何正規的

.jar

檔案被加載都是通過"基本"的類加載器。如果你的項目處于一個多子產品化,并且不是所有的子產品都引入到你的IDE中,那麼你或許需要定制化一些東西,這樣你就需要建立一個

META-INF/spring-devtools.properties

檔案。

這個檔案是幹嘛用的?它裡面包含了一些包含字首為

restart.exclude

restart.include

的屬性。

include

元素是應該是被放入“

restart

”類加載器的類别,

exclude

元素是應該放入“

base

”類加載器的項。屬性的值是應用于類路徑的正規表達式模式,如下例所示:

restart.exclude.companycommonlibs=/mycorp-common-[\\w-]+\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w-]+\.jar
           

所有的屬性的

key

都應該是獨一無二的,而且所有的

key

都應該用

restart.include.

或者

restart.exclude.

開頭。

将加載類路徑中的所有

meta-inf/spring-devtools.properties

。您可以将檔案打包到項目内部或項目使用的庫中。

已知限制

重新啟動功能不适用于使用标準

ObjectInputstream

反序列化的對象。如果需要反序列化資料,可能需要将

Spring

configurableObjectInputstream

thread.currentThread().getContextClassLoader()

結合使用。

不幸的是,一些第三方庫在不考慮上下文類加載器的情況下反序列化。如果你發現這樣一個問題,你需要向原始作者請求修複。

LiveReoload

spring-boot-devtools

子產品包含一個内嵌的

LiveReload

服務,當資源檔案有改動的時候可以被用來觸發浏覽器重新整理。

LiveReload

浏覽器的擴充對于Chrome, Firefox 和Safari來說是可以利用的。

你隻可以一次運作一個

LiveReload

服務。在你啟動你的應用之前,確定沒有其他的

LiveReload

服務正在運作。如果你從你的IDE中啟動多個應用,那麼隻有第一個

LiveReload

是被支援的。

全局設定

可以通過将名為

.spring-boot-devtools.properties

的檔案添加到

$home

檔案夾來配置全局

devtools

設定(請注意,檔案名以

“.”

開頭)。添加到此檔案的任何屬性都将應用于使用

devtools

的計算機上的所有

Spring

引導應用程式。例如,要将

Restart

配置為始終使用觸發器檔案,您需要添加以下屬性:

~/.spring-boot-devtools.properties.

spring.devtools.reload.trigger-file=.reloadtrigger

[注意]

.spring-boot-devtools.properties

中激活的配置檔案不會影響特定配置檔案的加載。

遠端應用

spring boot

開發者工具不僅限于本地的開發,而且當你遠端運作應用的時候還可以使用一些新特性。遠端支援即

opt-in

。你應該確定你的

devtools

被包含在重新打包的存檔中。

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<configuration>
				<excludeDevtools>false</excludeDevtools>
			</configuration>
		</plugin>
	</plugins>
</build>
           

你應該設定

spring.devtools.remote.secret=mysecret

,在遠端應用上面啟動

spring-boot-devtools

是存在安全風險的。建議不要在遠端應用中開啟這個支援。

遠端

devtools

支援分為兩部分:接受連接配接的伺服器端端點和在

IDE

中運作的用戶端應用程式。設定

spring.devtools.remote.secret

屬性時,将自動啟用伺服器元件。必須手動啟動用戶端元件。

運作遠端用戶端應用程式

遠端用戶端應用程式設計為從您的IDE中運作。您需要使用與所連接配接的遠端項目相同的類路徑運作。

org.springframework.boot.devtools.RemoteSpringApplication

。應用程式的單個必需參數是它所連接配接的遠端URL。

例如,如果你正在使用

Eclipse

或者

STS

,并且你的項目名字叫做

my-app

,你要把該項目部署到雲端,那麼你将做下面的事情:

(1)選擇

Run Configurations...

Run

菜單中

(2)建立一個新的Java應用程式來運作配置

(3)使用

org.springframework.boot.devtools.RemoteSpringApplication

作為

main

(4)将

https://myapp.cfapps.io

添加到

Program arguments

(或任何遠端URL)。

一個運作的遠端用戶端或許像下面顯示的這樣:

.   ____          _                                              __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _          ___               _      \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` |        | _ \___ _ __  ___| |_ ___ \ \ \ \
 \\/  ___)| |_)| | | | | || (_| []::::::[]   / -_) '  \/ _ \  _/ -_) ) ) ) )
  '  |____| .__|_| |_|_| |_\__, |        |_|_\___|_|_|_\___/\__\___|/ / / /
 =========|_|==============|___/===================================/_/_/_/
 :: Spring Boot Remote :: 2.1.5.RELEASE

2015-06-10 18:25:06.632  INFO 14938 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Starting RemoteSpringApplication on pwmbp with PID 14938 (/Users/pwebb/projects/spring-boot/code/spring-boot-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code/spring-boot-samples/spring-boot-sample-devtools)
2015-06-10 18:25:06.671  INFO 14938 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.spring[email protected]2a17b7b6: startup date [Wed Jun 10 18:25:06 PDT 2015]; root of context hierarchy
2015-06-10 18:25:07.043  WARN 14938 --- [           main] o.s.b.d.r.c.RemoteClientConfiguration    : The connection to http://localhost:8080 is insecure. You should use a URL starting with 'https://'.
2015-06-10 18:25:07.074  INFO 14938 --- [           main] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2015-06-10 18:25:07.130  INFO 14938 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Started RemoteSpringApplication in 0.74 seconds (JVM running for 1.105)
           

因為遠端用戶端應用使用的是與實際應用程式相同的類路徑,是以它可以直接讀取應用程式屬性。這是如何讀取

spring.devtools.remote.secret

屬性并将其傳遞給伺服器進行身份驗證。

建議将

https://

作為連接配接協定,以便在傳遞的過程中加密,密碼不會被攔截。

如果你想使用一個代理來通路遠端應用,配置一下下面兩個屬性:

spring.devtools.remote.proxy.host
spring.devtools.remote.proxy.port
           

遠端更新

遠端用戶端以與本地重新啟動相同的方式監視應用程式類路徑的更改。任何更新的資源都被推送到遠端應用程式,并且(如果需要)觸發重新啟動。如果您疊代一個使用本地沒有的雲服務的功能,這将很有幫助。通常,遠端更新和重新啟動要比完全重建和部署周期快得多。

隻有在遠端用戶端運作時才監視檔案。如果在啟動遠端用戶端之前更改了檔案,則不會将其推送到遠端伺服器。

SpringBoot學習 @SpringBootApplication和熱部署