第5章 Spring Boot 功能


Spring Boot 功能

      本節將會介紹Spring Boot的一些細節。 在這里,您可以了解您將要使用和自定義的主要功能。 如果還沒有准備好,您可能需要閱讀第二部分“入門指南”和第三部分“使用 Spring Boot”部分,以使您有基礎的良好基礎。

23. SpringApplication

SpringApplication類提供了一種方便的方法來引導將從main()方法啟動的Spring應用程序。 在許多情況下,您只需委派靜態SpringApplication.run()方法:

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

當您的應用程序啟動時,您應該看到類似於以下內容:

  .   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v1.5.2.RELEASE

2013-07-31 00:08:16.117 INFO 56603 --- [ main] o.s.b.s.app.SampleApplication : Starting SampleApplication v0.1.0 on mycomputer with PID 56603 (/apps/myapp.jar started by pwebb)
2013-07-31 00:08:16.166 INFO 56603 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy
2014-03-04 13:09:54.912 INFO 41370 --- [ main] .t.TomcatEmbeddedServletContainerFactory : Server initialized with port: 8080
2014-03-04 13:09:56.501 INFO 41370 --- [ main] o.s.b.s.app.SampleApplication : Started SampleApplication in 2.992 seconds (JVM running for 3.658)

默認情況下,將顯示INFO 級別log消息,包括用戶啟動應用程序一些相關的啟動細節。

23.1 啟動失敗

如果您的應用程序無法啟動,則注冊的FailureAnalyzers會提供專門的錯誤消息和具體操作來解決問題。 例如,如果您在端口8080上啟動Web應用程序,並且該端口已在使用中,則應該會看到類似於以下內容的內容:

***************************
APPLICATION FAILED TO START
***************************

Description:

Embedded servlet container failed to start. Port 8080 was already in use.

Action:

Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.

Spring Boot提供了眾多的FailureAnalyzer實現,您可以非常容易地添加自己的實現

如果沒有故障分析器(analyzers)能夠處理異常,您仍然可以顯示完整的自動配置報告,以更好地了解出現的問題。 為此,您需要啟用debug屬性或啟用org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer的DEBUG日志

例如,如果使用java -jar運行應用程序,則可以按如下方式啟用 debug:

$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug

23.2 自定義Banner

可以通過在您的類路徑中添加一個 banner.txt 文件,或者將banner.location設置到banner文件的位置來更改啟動時打印的banner。 如果文件有一些不常用的編碼,你可以設置banner.charset(默認為UTF-8)。除了文本文件,您還可以將banner.gif,banner.jpg或banner.png圖像文件添加到您的類路徑中,或者設置一個banner.image.location屬性。 圖像將被轉換成ASCII藝術表現,並打印在任何文字banner上方。

您可以在banner.txt文件中使用以下占位符:

表23.1. banner變量

變量名 描述
${application.version} 在MANIFEST.MF中聲明的應用程序的版本號。例如, Implementation-Version: 1.0 被打印為 1.0.
${application.formatted-version} 在MANIFEST.MF中聲明的應用程序版本號的格式化顯示(用括號括起來,以v為前綴)。 例如 (v1.0)。
${spring-boot.version} 您正在使用的Spring Boot版本。 例如1.5.2.RELEASE。
${spring-boot.formatted-version} 您正在使用格式化顯示的Spring Boot版本(用括號括起來,以v為前綴)。 例如(v1.5.2.RELEASE)。
Ansi.NAME(or

{AnsiColor.NAME}, AnsiBackground.NAME,

{AnsiStyle.NAME}) 其中NAME是ANSI轉義碼的名稱。 有關詳細信息,請參閱 AnsiPropertySource
${application.title} 您的應用程序的標題在MANIFEST.MF中聲明。 例如Implementation-Title:MyApp打印為MyApp。

如果要以編程方式生成banner,則可以使用SpringApplication.setBanner()方法。 使用org.springframework.boot.Banner 如接口,並實現自己的printBanner() 方法。

您還可以使用spring.main.banner-mode屬性來決定是否必須在System.out(控制台)上打印banner,使用配置的logger(log)或不打印(off)。

23.3 定制SpringApplication

如果SpringApplication默認值不符合您的想法,您可以創建本地實例並進行自定義。 例如,關閉banner:

public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}

傳遞給SpringApplication的構造函數參數是spring bean的配置源。 在大多數情況下,這些將引用@Configuration類,但它們也可以引用XML配置或應掃描的包。

也可以使用application.properties文件配置SpringApplication。 有關詳細信息,請參見第24章“外部配置”

有關配置選項的完整列表,請參閱SpringApplication Javadoc

23.4 流式構建 API

如果您需要構建一個ApplicationContext層次結構(具有父/子關系的多個上下文),或者如果您只想使用“流式(fluent)”構建器API,則可以使用SpringApplicationBuilder。

SpringApplicationBuilder允許您鏈式調用多個方法,並包括允許您創建層次結構的父和子方法。

例如:

new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);

創建ApplicationContext層次結構時有一些限制,例如 Web組件必須包含在子上下文中,並且相同的環境將用於父和子上下文。 有關詳細信息,請參閱SpringApplicationBuilder Javadoc

23.5 Application events and listeners

除了常見的Spring Framework事件(如 ContextRefreshedEvent)之外,SpringApplication還會發送一些其他應用程序事件。

在創建ApplicationContext之前,實際上觸發了一些事件,因此您不能在@Bean上注冊一個監聽器。 您可以通過SpringApplication.addListeners(…) 或SpringApplicationBuilder.listeners(…)方法注冊它們。

如果您希望自動注冊這些偵聽器,無論創建應用程序的方式如何,都可以將META-INF / spring.factories文件添加到項目中,並使用org.springframework.context.ApplicationListener引用您的偵聽器。
org.springframework.context.ApplicationListener=com.example.project.MyListener

當您的應用程序運行時,事件按照以下順序發送:

  1. ApplicationStartingEvent在運行開始時發送,但在注冊偵聽器和注冊初始化器之后。
  2. 當已經知道要使用的上下文(context)環境,並在context創建之前,將發送ApplicationEnvironmentPreparedEvent。
  3. ApplicationPreparedEvent在啟動刷新(refresh)之前發送,但在加載了bean定義之后。
  4. ApplicationReadyEvent在刷新之后被發送,並且處理了任何相關的回調以指示應用程序准備好服務請求。
  5. 如果啟動時發生異常,則發送ApplicationFailedEvent。

一般您不需要使用應用程序事件,但可以方便地知道它們存在。 在內部,Spring Boot使用事件來處理各種任務。

23.6 Web 環境

SpringApplication將嘗試代表您創建正確類型的ApplicationContext。 默認情況下,將使用AnnotationConfigApplicationContext或AnnotationConfigEmbeddedWebApplicationContext,具體取決於您是否正在開發Web應用程序。

用於確定“Web環境”的算法是相當簡單的(基於幾個類的存在)。 如果需要覆蓋默認值,可以使用setWebEnvironment(boolean webEnvironment)。

也可以通過調用setApplicationContextClass() 對ApplicationContext完全控制。

在JUnit測試中使用SpringApplication時,通常需要調用setWebEnvironment()

23.7 訪問應用程序參數

如果您需要訪問傳遞給SpringApplication.run()的應用程序參數,則可以注入org.springframework.boot.ApplicationArguments bean。 ApplicationArguments接口提供對原始String []參數以及解析選項和非選項參數的訪問:

import org.springframework.boot.*
import org.springframework.beans.factory.annotation.*
import org.springframework.stereotype.*

@Component
public class MyBean {

@Autowired
public MyBean(ApplicationArguments args) {
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
// if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
}

}

Spring Boot還將向Spring Environment 注冊一個CommandLinePropertySource。 這允許您也使用@Value注解注入應用程序參數。

23.8 使用ApplicationRunner或CommandLineRunner

SpringApplication啟動時如果您需要運行一些特定的代碼,就可以實現ApplicationRunner或CommandLineRunner接口。 兩個接口都以相同的方式工作,並提供一個單獨的運行方法,這將在SpringApplication.run(…)完成之前調用。

CommandLineRunner接口提供對應用程序參數的訪問(簡單的字符串數組),而ApplicationRunner使用上述的ApplicationArguments接口。

@Component
public class MyBean implements CommandLineRunner {

public void run(String... args) {
// Do something...
}

}

如果定義了若干CommandLineRunner或ApplicationRunner bean,這些bean必須按特定順序調用,您可以實現org.springframework.core.Ordered接口,也可以使用org.springframework.core.annotation.Order注解。

23.9 Application exit

每個SpringApplication將注冊一個JVM關閉鈎子,以確保ApplicationContext在退出時正常關閉。 可以使用所有標准的Spring生命周期回調(例如DisposableBean接口或@PreDestroy注釋)。

另外,如果希望在應用程序結束時返回特定的退出代碼,那么bean可以實現org.springframework.boot.ExitCodeGenerator接口。

23.10 管理功能

可以通過指定spring.application.admin.enabled屬性來為應用程序啟用與管理相關的功能。 這會在平台MBeanServer上暴露SpringApplicationAdminMXBean。 您可以使用此功能來遠程管理您的Spring Boot應用程序。 這對於任何服務包裝器(service wrapper)實現也是有用的。

如果您想知道應用程序在哪個HTTP端口上運行,請使用local.server.port鍵獲取該屬性。

啟用此功能時請小心,因為MBean公開了關閉應用程序的方法。

24. 外部配置

Spring Boot允許您外部化您的配置,以便您可以在不同的環境中使用相同的應用程序代碼。 您可以使用properties文件,YAML文件,環境變量和命令行參數來外部化配置。 可以使用@Value注釋將屬性值直接注入到您的bean中,該注釋可通過Spring環境(Environment)抽象訪問,或通過@ConfigurationProperties綁定到結構化對象

Spring Boot使用非常特別的PropertySource命令,旨在允許合理地覆蓋值。屬性按以下順序選擇:

  1. 在您的HOME目錄設置的Devtools全局屬性(~/.spring-boot-devtools.properties)。
  2. 單元測試中的 @TestPropertySource 注解。
  3. 單元測試中的 @SpringBootTest#properties 注解屬性
  4. 命令行參數。
  5. SPRING_APPLICATION_JSON 中的屬性值(內嵌JSON嵌入到環境變量或系統屬性中)。
  6. ServletConfig 初始化參數。
  7. ServletContext 初始化參數。
  8. 來自 java:comp/env 的JNDI屬性。
  9. Java系統屬性(System.getProperties())。
  10. 操作系統環境變量。
  11. RandomValuePropertySource,只有隨機的屬性 random.* 中。
  12. jar包外面的 Profile-specific application properties (application- {profile} .properties和YAML變體)
  13. jar包內的 Profile-specific application properties (application-{profile}.properties和YAML變體)
  14. jar包外的應用屬性文件(application.properties和YAML變體)。
  15. jar包內的應用屬性文件(application.properties和YAML變體)。
  16. 在@Configuration上的@PropertySource注解。
  17. 默認屬性(使用SpringApplication.setDefaultProperties設置)。

一個具體的例子,假設你開發一個使用name屬性的@Component:

import org.springframework.stereotype.*
import org.springframework.beans.factory.annotation.*

@Component
public class MyBean {

@Value("${name}")
private String name;

// ...

}

在應用程序類路徑(例如,您的jar中)中,您可以擁有一個application.properties,它為 name 屬性提供了默認屬性值。 在新環境中運行時,可以在您的jar外部提供一個application.properties來覆蓋 name 屬性; 對於一次性測試,您可以使用特定的命令行開關啟動(例如,java -jar app.jar –name=”Spring”)。

SPRING_APPLICATION_JSON屬性可以在命令行中提供一個環境變量。 例如在UN*X shell中:

$ SPRING_APPLICATION_JSON='{"foo":{"bar":"spam"}}' java -jar myapp.jar

在本例中,您將在Spring環境中使用foo.bar = spam。 您也可以在系統變量中將JSON作為spring.application.json提供:

$ java -Dspring.application.json='{"foo":"bar"}' -jar myapp.jar

或命令行參數:

$ java -jar myapp.jar --spring.application.json='{"foo":"bar"}'

或作為JNDI變量 java:comp/env/spring.application.json 。

24.1 配置隨機值

RandomValuePropertySource可用於注入隨機值(例如,進入秘密或測試用例)。 它可以產生整數,長整數,uuid或字符串,例如

my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}

random.int *語法是 OPEN value (,max) CLOSE ,其中OPEN,CLOSE是任何字符和值,max是整數。 如果提供max,則值為最小值,max為最大值(獨占)。

24.2 訪問命令行屬性

默認情況下,SpringApplication將任何命令行選項參數(以’– ‘開頭,例如–server.port=9000)轉換為屬性,並將其添加到Spring環境中。 如上所述,命令行屬性始終優先於其他屬性來源。

如果不希望將命令行屬性添加到環境中,可以使用SpringApplication.setAddCommandLineProperties(false)禁用它們。

24.3 應用程序屬性文件

SpringApplication將從以下位置的application.properties文件中加載屬性,並將它們添加到Spring Environment中:

  1. 當前目錄的/config子目錄
  2. 當前目錄
  3. classpath中/config包
  4. classpath root路徑

該列表按優先級從高到低排序。

也可以使用YAML(’.yml’)文件替代“.properties”。

如果您不喜歡application.properties作為配置文件名,可以通過指定一個spring.config.name Spring environment屬性來切換到另一個。 您還可以使用spring.config.location環境屬性(用逗號分隔的目錄位置列表或文件路徑)顯式引用位置。

$ java -jar myproject.jar --spring.config.name=myproject

$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

spring.config.name和spring.config.location一開始就被用於確定哪些文件必須被加載,因此必須將它們定義為環境屬性(通常是OS env,system屬性或命令行參數)。

如果spring.config.location包含的如果是目錄而非文件,那么它們應該以/結尾(並將在加載之前附加從spring.config.name生成的名稱,包括profile-specific的文件名)。 在spring.config.location中指定的文件按原樣使用,不支持特定於配置文件的變體,並且將被任何特定於配置文件的屬性覆蓋。

默認的搜索路徑 classpath:,classpath:/config,file:,file:config/ 始終會被搜索,不管spring.config.location的值如何。 該搜索路徑從優先級排序從低到高(file:config/最高)。 如果您指定自己的位置,則它們優先於所有默認位置,並使用相同的從最低到最高優先級排序。 這樣,您可以在application.properties(或使用spring.config.name選擇的任何其他基礎名稱)中為應用程序設置默認值,並在運行時使用不同的文件覆蓋它,並保留默認值。

如果您使用環境(environment)變量而不是系統屬性,大多數操作系統不允許使用句點分隔(period-separated)的鍵名稱,但可以使用下划線(例如,SPRING_CONFIG_NAME,而不是spring.config.name)

如果您運行在容器中,則可以使用JNDI屬性(在 java:comp/env 中)或servlet上下文初始化參數,而不是環境變量或系統屬性。

24.4 指定配置(Profile-specific)的屬性

除了application.properties文件外,還可以使用命名約定application- {profile}.properties定義的指定配置文件。 環境具有一組默認配置文件,如果沒有設置活動配置文件(即,如果沒有顯式激活配置文件,則加載了來自application-default.properties的屬性)。

指定配置文件(Profile-specific)的屬性從與標准application.properties相同的位置加載,指定配置( profile-specific)文件始終覆蓋非指定文件,而不管指定配置文件是否在打包的jar內部或外部。

如果有幾個指定配置文件,則應用最后一個配置。 例如,由spring.profiles.active屬性指定的配置文件在通過SpringApplication API配置的配置之后添加,因此優先級高。

如果您在spring.config.location中指定了任何文件,則不會考慮這些特定配置(profile-specific)文件的變體。 如果您還想使用指定配置(profile-specific)文件的屬性,請使用spring.config.location中的目錄。

24.5 properties 文件中的占位符

application.properties中的值在使用時通過已有的環境進行過濾,以便您可以引用之前定義的值(例如,從系統屬性)。

app.name=MyApp
app.description=${app.name} is a Spring Boot application

您也可以使用此技術創建現有Spring Boot屬性的“簡寫“。 有關詳細信息,請參見第72.4節“使用”短命令行參數“how-to”

24.6 使用YAML替代 Properties

YAML是JSON的超集,因此這是分層配置數據一種非常方便的格式,。 每當您的類路徑中都有SnakeYAML庫時,SpringApplication類將自動支持YAML作為 properties 的替代方法。

如果您使用“Starters”,SnakeYAML將通過spring-boot-starter自動提供。

24.6.1 加載 YAML

Spring Framework提供了兩個方便的類,可用於加載YAML文檔。 YamlPropertiesFactoryBean將YAML作為Properties加載,YamlMapFactoryBean將YAML作為Map加載。

例如,下面YAML文檔:

environments:
dev:
url: http://dev.bar.com
name: Developer Setup
prod:
url: http://foo.bar.com
name: My Cool App

將轉化為屬性:

environments.dev.url=http://dev.bar.com
environments.dev.name=Developer Setup
environments.prod.url=http://foo.bar.com
environments.prod.name=My Cool App

YAML列表表示為具有[index] dereferencers的屬性鍵,例如YAML:

my:
servers:
- dev.bar.com
- foo.bar.com

將轉化為屬性:

my.servers[0]=dev.bar.com
my.servers[1]=foo.bar.com

要使用Spring DataBinder工具(@ConfigurationProperties做的)綁定到這樣的屬性,您需要有一個屬性類型為java.util.List(或Set)的目標bean,並且您需要提供一個setter,或者 用可變值初始化它,例如 這將綁定到上面的屬性

@ConfigurationProperties(prefix="my")
public class Config {

private List<String> servers = new ArrayList<String>();

public List<String> getServers() {
return this.servers;
}
}

24.6.2 將YAML作為Spring環境中的屬性文件

可以使用YamlPropertySourceLoader類在Spring環境中將YAML作為PropertySource暴露出來。 這允許您使用熟悉的@Value注解和占位符語法來訪問YAML屬性。

24.6.3 多個YAML文件

您可以使用spring.profiles鍵指定單個文件中的多個特定配置文件YAML文檔,以指示文檔何時應用。 例如:

server:
address: 192.168.1.100
---
spring:
profiles: development
server:
address: 127.0.0.1
---
spring:
profiles: production
server:
address: 192.168.1.120

在上面的示例中,如果開發配置文件處於活動狀態,則server.address屬性將為127.0.0.1。 如果開發和生產配置文件未啟用,則該屬性的值將為192.168.1.100。

如果應用程序上下文啟動時沒有顯式激活,默認配置文件將被激活。 所以在這個YAML中,我們為security.user.password設置一個僅在“默認”配置文件中可用的值:

server:
port: 8000
---
spring:
profiles: default
security:
user:
password: weak

使用“spring.profiles”元素指定的Spring profiles 以選擇使用 字符。 如果為單個文檔指定了否定和非否定的配置文件,則至少有一個非否定配置文件必須匹配,沒有否定配置文件可能匹配。

24.6.4 YAML的缺點

YAML文件無法通過@PropertySource注解加載。 因此,在需要以這種方式加載值的情況下,需要使用properties文件。

24.6.5 合並YAML列表

如上所述,任何YAML內容最終都會轉換為屬性。 當通過配置文件覆蓋“列表”屬性時,該過程可能比較直觀。

例如,假設名稱和描述屬性默認為空的MyPojo對象。 讓我們從FooProperties中公開MyPojo的列表:

@ConfigurationProperties("foo")
public class FooProperties {

private final List<MyPojo> list = new ArrayList<>();

public List<MyPojo> getList() {
return this.list;
}

}

類比以下配置:

foo:
list:
- name: my name
description: my description
---
spring:
profiles: dev
foo:
list:
- name: my another name

如果dev配置沒有激活,FooProperties.list將包含一個如上定義的MyPojo條目。 如果啟用了配置文件,列表仍將包含一個條目(名稱為“my another name”,description=null)。 此配置不會將第二個MyPojo實例添加到列表中,並且不會將項目合並。

當在多個配置文件中指定集合時,使用具有最高優先級的集合(並且僅使用該配置文件):

foo:
list:
- name: my name
description: my description
- name: another name
description: another description
---
spring:
profiles: dev
foo:
list:
- name: my another name

在上面的示例中,考慮到dev配置文件處於激活狀態,FooProperties.list將包含一個MyPojo條目(名稱為“my another name”和description=null)。

24.7 類型安全的配置屬性

使用@Value(“${property}”)注釋來注入配置屬性有時可能很麻煩,特別是如果您正在使用多個層次結構的屬性或數據時。 Spring Boot提供了一種處理屬性的替代方法,允許強類型Bean管理並驗證應用程序的配置。

package com.example;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("foo")
public class FooProperties {

private boolean enabled;

private InetAddress remoteAddress;

private final Security security = new Security();

public boolean isEnabled() { ... }

public void setEnabled(boolean enabled) { ... }

public InetAddress getRemoteAddress() { ... }

public void setRemoteAddress(InetAddress remoteAddress) { ... }

public Security getSecurity() { ... }

public static class Security {

private String username;

private String password;

private List<String> roles = new ArrayList<>(Collections.singleton("USER"));

public String getUsername() { ... }

public void setUsername(String username) { ... }

public String getPassword() { ... }

public void setPassword(String password) { ... }

public List<String> getRoles() { ... }

public void setRoles(List<String> roles) { ... }

}
}

上述POJO定義了以下屬性:

  • foo.enabled,默認為false
  • foo.remote-address,具有可以從String強轉的類型
  • foo.security.username,具有內置的“安全性(security)”,其名稱由屬性名稱決定。 特別是返回類型並沒有被使用,可能是SecurityProperties
  • foo.security.password
  • foo.security.roles,一個String集合

Getters和setter方法通常是必須要有的,因為綁定是通過標准的Java Beans屬性描述符,就像在Spring MVC中一樣。 在某些情況下可能會省略setter方法:

  • Map 只要它們被初始化,需要一個getter,但不一定是一個setter,因為它們可以被binder修改。
  • 集合和數組可以通過索引(通常使用YAML)或使用單個逗號分隔值(Properties中)來訪問。 在后一種情況下,setter方法是強制性的。 我們建議總是為這樣的類型添加一個設置器。 如果您初始化集合,請確保它不是不可變的(如上例所示)
  • 如果已初始化嵌套POJO屬性(如上例中的Security字段),則不需要setter方法。如果您希望binder使用其默認構造函數即時創建實例,則需要一個setter。

有些人使用Project Lombok自動添加getter和setter。 確保Lombok不會為這種類型生成任何特定的構造函數,因為構造函將被容器自動用於實例化對象。

另請參閱@Value和@ConfigurationProperties之間的不同

您還需要列出在@EnableConfigurationProperties注解中注冊的屬性類:

@Configuration
@EnableConfigurationProperties(FooProperties.class)
public class MyConfiguration {
}

@ConfigurationProperties bean以這種方式注冊時,該bean將具有常規名稱:<prefix> - <fqn>,其中是@ConfigurationProperties注解中指定的環境密鑰前綴,是bean的全名(fully qualified name)。 如果注解不提供任何前綴,則僅使用該bean的全名。上面示例中的bean名稱將是foo-com.example.FooProperties。

即使上述配置將為FooProperties創建一個常規bean,我們建議@ConfigurationProperties僅處理環境,特別是不從上下文中注入其他bean。 話雖如此,@EnableConfigurationProperties注釋也會自動應用於您的項目,以便使用@ConfigurationProperties注釋的任何現有的bean都將從環境配置。 您可以通過確保FooProperties已經是一個bean來快速上面的MyConfiguration

@Component
@ConfigurationProperties(prefix="foo")
public class FooProperties {

// ... see above

}

這種配置方式與SpringApplication外部的YAML配置相當:

# application.yml

foo:
remote-address: 192.168.1.1
security:
username: foo
roles:
- USER
- ADMIN

# additional configuration as required

要使用@ConfigurationProperties bean,您可以像其他任何bean一樣注入它們。

@Service
public class MyService {

private final FooProperties properties;

@Autowired
public MyService(FooProperties properties) {
this.properties = properties;
}

//...

@PostConstruct
public void openConnection() {
Server server = new Server(this.properties.getRemoteAddress());
// ...
}

}

使用@ConfigurationProperties還可以生成IDE可以為自己的密鑰提供自動完成的元數據文件,有關詳細信息,請參見附錄B,配置元數據附錄

24.7.1第三方配置

除了使用@ConfigurationProperties來注解類,還可以在public @Bean方法中使用它。 當您希望將屬性綁定到不受控制的第三方組件時,這可能特別有用。

@ConfigurationProperties(prefix = "bar")
@Bean
public BarComponent barComponent() {
...
}

使用 bar 前綴定義的任何屬性將以與上述FooProperties示例類似的方式映射到該BarComponent bean。

24.7.2 寬松的綁定

Spring Boot使用一些寬松的規則將環境屬性綁定到@ConfigurationProperties bean,因此不需要在Environment屬性名稱和bean屬性名稱之間進行完全匹配。 常用的例子是這樣有用的:虛分離(例如上下文路徑綁定到contextPath)和大寫(例如PORT綁定到端口)環境屬性。

例如,給定以下@ConfigurationProperties類:

@ConfigurationProperties(prefix="person")
public class OwnerProperties {

private String firstName;

public String getFirstName() {
return this.firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

}

可以使用以下屬性名稱:

表格 24.1. relaxed binding

Property Note
person.firstName 標准駱峰命名法。
person.first-name 虛線符號,推薦用於.properties和.yml文件。
person.first_name 下划線符號,用於.properties和.yml文件的替代格式。
PERSON_FIRST_NAME 大寫格式 推薦使用系統環境變量時。

24.7.3屬性轉換

當Spring綁定到@ConfigurationProperties bean時,Spring將嘗試將外部應用程序屬性強制為正確的類型。 如果需要自定義類型轉換,您可以提供ConversionService bean(使用bean id conversionService)或自定義屬性編輯器(通過CustomEditorConfigurer bean)或自定義轉換器(使用注釋為@ConfigurationPropertiesBinding的bean定義)。

由於在應用程序生命周期期間非常早請求此Bean,請確保限制ConversionService正在使用的依賴關系。 通常,您需要的任何依賴關系可能無法在創建時完全初始化。 如果配置密鑰強制不需要,只需依賴使用@ConfigurationPropertiesBinding限定的自定義轉換器,就可以重命名自定義ConversionService。

24.7.4 @ConfigurationProperties驗證

當Spring的@Validated注釋解時,Spring Boot將嘗試驗證@ConfigurationProperties類。 您可以直接在配置類上使用JSR-303 javax.validation約束注釋。 只需確保您的類路徑中符合JSR-303實現,然后在您的字段中添加約束注釋:

@ConfigurationProperties(prefix="foo")
@Validated
public class FooProperties {

@NotNull
private InetAddress remoteAddress;

// ... getters and setters

}

為了驗證嵌套屬性的值,您必須將關聯字段注釋為@Valid以觸發其驗證。 例如,基於上述FooProperties示例:

@ConfigurationProperties(prefix="connection")
@Validated
public class FooProperties {

@NotNull
private InetAddress remoteAddress;

@Valid
private final Security security = new Security();

// ... getters and setters

public static class Security {

@NotEmpty
public String username;

// ... getters and setters

}

}

您還可以通過創建名為configurationPropertiesValidator的bean定義來添加自定義的Spring Validator。 @Bean方法應聲明為static。 配置屬性驗證器在應用程序的生命周期早期創建,並聲明@Bean方法,因為static允許創建bean,而無需實例化@Configuration類。 這避免了早期實例化可能引起的任何問題。 這里有一個屬性驗證的例子,所以你可以看到如何設置。

spring-boot-actuator模塊包括一個暴露所有@ConfigurationProperties bean的端點。 只需將您的Web瀏覽器指向/configprops 或使用等效的JMX端點。 請參閱生產就緒功能 細節。

24.7.5 @ConfigurationProperties 對比 @Value

@Value是核心容器功能,它不提供與類型安全配置屬性相同的功能。 下表總結了@ConfigurationProperties和@Value支持的功能:

功能 @ConfigurationProperties @Value
Relaxed binding Yes No
Meta-data support Yes No
SpEL evaluation No Yes

如果您為自己的組件定義了一組配置密鑰,我們建議您將其分組到使用@ConfigurationProperties注釋的POJO中。 還請注意,由於@Value不支持寬松的綁定,如果您需要使用環境變量提供值,那么它不是一個很好的選擇。

最后,當您可以在@Value中編寫一個Spel表達式時,這些表達式不會從應用程序屬性文件中處理。

25. 配置文件(Profiles)

Spring 配置文件提供了將應用程序配置隔離的方法,使其僅在某些環境中可用。 任何@Component或@Configuration都可以使用@Profile進行標記,以限制其在什么時候加載:

@Configuration
@Profile("production")
public class ProductionConfiguration {

// ...

}

一般,您可以使用spring.profiles.active Environment屬性來指定哪些配置文件處於激活狀態。 您可以以任何方式指定屬性,例如,您可以將其包含在您的application.properties中:

spring.profiles.active=dev,hsqldb

或者使用命令行--spring.profiles.active=dev,hsqldb在命令行中指定。

25.1添加激活配置文件

spring.profiles.active屬性遵循與其他屬性相同的優先級規則,PropertySource最高。這意味着您可以在application.properties中指定活動配置文件,然后使用命令行開關替換它們。

有時,將特定於配置文件的屬性添加到激活的配置文件而不是替換它們是有用的。 spring.profiles.include屬性可用於無條件添加激活配置文件。 SpringApplication入口點還具有用於設置其他配置文件的Java API(即,在由spring.profiles.active屬性激活的那些配置文件之上):請參閱setAdditionalProfiles()方法。

例如,當使用開關 -spring.profiles.active=prod 運行具有以下屬性的應用程序時,proddb和prodmq配置文件也將被激活:

---
my.property: fromyamlfile
---
spring.profiles: prod
spring.profiles.include:
- proddb
- prodmq

請記住,可以在YAML文檔中定義spring.profiles屬性,以確定此特定文檔何時包含在配置中。 有關詳細信息,請參見第72.7節“根據環境更改配置”

25.2 以編程方式設置配置文件

您可以通過在應用程序運行之前調用SpringApplication.setAdditionalProfiles(…)以編程方式設置激活配置文件。 也可以使用Spring的ConfigurableEnvironment接口激活配置文件。

25.3 配置文件指定的配置文件

通過@ConfigurationProperties引用的application.properties(或application.yml)和文件的配置文件特定變體都被視為加載文件。 有關詳細信息,請參見第24.4節指定配置(Profile-specific)的屬性”

26. 日志

Spring Boot使用Commons Logging進行所有內部日志記錄,但使基礎日志實現開放。 默認配置提供了Java Util LoggingLog4J2Logback。 在每種情況下,記錄器都預先配置為使用控制台輸出和可選文件輸出都可用。

默認情況下,如果使用’Starters’,將會使用Logback。 還包括適當的Logback路由,以確保使用Java Util Logging,Commons Logging,Log4J或SLF4J的依賴庫都能正常工作。

有很多可用於Java的日志記錄框架。 如果上面的列表看起來很混亂,別擔心。 一般來說,您不需要更改日志依賴關系,並且Spring Boot默認值將正常工作。

26.1 日志格式

Spring Boot的默認日志輸出如下所示:

2014-03-05 10:57:51.112  INFO 45469 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.52
2014-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2014-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1358 ms
2014-03-05 10:57:51.698 INFO 45469 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2014-03-05 10:57:51.702 INFO 45469 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]

輸出以下項目:

  • 日期和時間 - 毫秒精度並且容易排序。
  • 日志級別 - ERROR, WARN, INFO, DEBUG, TRACE.
  • 進程ID。
  • —分隔符來區分實際日志消息的開始。
  • 線程名稱 - 括在方括號中(可能會截斷控制台輸出)。
  • 記錄器名稱 - 這通常是源類名(通常縮寫)。
  • 日志消息。

Logback沒有FATAL級別(對映ERROR)

26.2 控制台輸出

默認的日志配置會在控制台顯示消息。 默認情況下會記錄ERROR,WARN和INFO級別的消息。 您還可以通過–debug啟動您的應用程序來啟用“debug”模式。

$ java -jar myapp.jar --debug

您還可以在application.properties中指定debug=true。

當啟用debug模式時,配置核心記錄器(嵌入式容器,Hibernate和Spring Boot)的選擇可以輸出更多信息。 啟用debug 模式不會將應用程序配置為使用DEBUG級別記錄所有消息。

或者,您可以使用–trace啟動應用程序(或在您的application.properties中為trace=true)啟用“trace”模式。 這將為核心記錄器(嵌入式容器,Hibernate模式生成和整個Spring組合)啟用trace日志。

26.2.1 日志顏色輸出

如果您的終端支持ANSI,顏色輸出可以增加可讀性。 您可以將spring.output.ansi.enabled設置為支持的值來覆蓋自動檢測。

使用%clr關鍵字配置顏色編碼。 在最簡單的形式下,轉換器將根據日志級別對輸出進行着色,例如:

%clr(%5p)

日志級別映射到顏色如下:

  • blue
  • cyan
  • faint
  • green
  • magenta
  • red
  • yellow

26.3 文件輸出

默認情況下,Spring Boot將僅將日志輸出到控制台,不會寫到文件。 如果要將控制台上的日志輸出到日志文件,則需要設置logging.file或logging.path屬性(例如在application.properties中)。

下表顯示了如何一起使用logging.*屬性:

表26.1 Logging屬性

logging.file logging.path Example Description
(none) (none)   僅控制台輸出
Specific file (none) my.log 寫入指定的日志文件。 名稱可以是確切的位置或相對於當前目錄。
(none) Specific directory /var/log 將spring.log寫入指定的目錄。 名稱可以是確切的位置或相對於當前目錄。

日志文件將在10 MB時滾動輸出到文件,默認情況下會記錄控制台輸出,ERROR,WARN和INFO級別的消息。

日志記錄系統在應用程序生命周期早期初始化,並且在通過@PropertySource注解加載的屬性文件中將不會找到log屬性

日志屬性獨立於實際的日志記錄基礎結構。 因此,特定配置key(如Logback的logback.configurationFile)不受Spring Boot管理。

26.4 日志級別

所有支持的日志記錄系統都可以在Spring Environment 中設置log級別(例如在application.properties中),使用‘logging.level.*=LEVEL’,其中’LEVEL’是TRACE,DEBUG,INFO,WARN,ERROR,FATAL, OFF之一。 可以使用logging.level.root配置根記錄器。 示例application.properties:

logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR

默認情況下,Spring Boot會重新啟動Thymeleaf INFO消息,以便它們以DEBUG級別進行記錄。 這有助於降低標准日志輸出中的噪音。 有關如何在自己的配置中應用重映射的詳細信息,請參閱LevelRemappingAppender

26.5 自定義日志配置

可以通過在類路徑中包含適當的庫來激活各種日志系統,並通過在類路徑的根目錄中提供合適的配置文件,或在Spring Environment屬性logging.config指定的位置進一步配置。

您可以使用org.springframework.boot.logging.LoggingSystem系統屬性強制Spring Boot使用特定的日志記錄系統。該值應該是LoggingSystem實現的全名。 您還可以使用none值完全禁用Spring Boot的日志記錄配置。

由於在創建ApplicationContext之前初始化日志,因此無法在Spring @Configuration文件中控制@PropertySources的日志記錄。 系統屬性和常規的Spring Boot外部配置文件工作正常。

根據您的日志記錄系統,將會加載以下文件:

Logging System Customization
Logback logback-spring.xml, logback-spring.groovy, logback.xml or logback.groovy
Log4j2 log4j2-spring.xml or log4j2.xml
JDK (Java Util Logging) logging.properties

如果可能,我們建議您使用-spring變體進行日志記錄配置(例如使用logback-spring.xml而不是logback.xml)。 如果使用標准配置位置,則Spring無法完全控制日志初始化。

Java Util Logging存在已知的類加載問題,從“可執行jar”運行時會導致問題。 我們建議您盡可能避免。

幫助定制一些其他屬性從Spring環境轉移到系統屬性:

Spring Environment System Property Comments
logging.exception-conversion-word LOG_EXCEPTION_CONVERSION_WORD 記錄異常時使用的轉換字。
logging.file LOG_FILE 如果定義了,則用於默認日志配置。
logging.path LOG_PATH 如果定義了,則用於默認日志配置。
logging.pattern.console CONSOLE_LOG_PATTERN 在控制台上使用的日志模式(stdout)。 (僅支持默認logback設置。)
logging.pattern.file FILE_LOG_PATTERN 在文件中使用的日志模式(如果LOG_FILE已啟用)。 (僅支持默認logback設置。)
logging.pattern.level LOG_LEVEL_PATTERN 用於呈現日志級別的格式(默認%5p)。 (僅支持默認logback設置。)
PID PID 當前進程ID(如果可能的話,當未被定義為OS環境變量時被發現)。

支持的所有日志記錄系統在分析其配置文件時可以查看系統屬性。 有關示例,請參閱spring-boot.jar中的默認配置。

如果要在logging屬性中使用占位符,則應使用Spring Boot的語法,而不是底層框架的語法。 值得注意的是,如果您使用Logback,您應該使用:作為屬性名稱與其默認值之間的分隔符,而不是:-

您可以通過覆蓋LOG_LEVEL_PATTERN(或Logback的log.pattern.level)來添加MDC和其他ad-hoc內容到日志行。 例如,如果使用logging.pattern.level = user:%X {user}%5p,則默認日志格式將包含“user”的MDC條目(如果存在)。

2015-09-30 12:30:04.031 user:juergen INFO 22174 --- [  nio-8080-exec-0] demo.Controller
Handling authenticated request

26.6 Logback擴展

Spring Boot包括大量的Logback擴展,可以幫助您進行高級配置。 您可以在logback-spring.xml配置文件中使用這些擴展。

您不能在標准logback.xml配置文件中使用擴展名,因為其加載時間太早。 您需要使用logback-spring.xml或定義logging.config屬性。

擴展名不能與Logback的配置掃描一起使用。 如果您嘗試這樣做,對配置文件進行更改將導致類似於以下記錄之一的錯誤:

ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProperty], current ElementPath is [[configuration][springProperty]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]]

26.6.1 指定配置文件配置

<springProfile>標簽允許您根據活動的Spring配置文件可選地包含或排除配置部分。 配置文件部分支持<configuration>元素在任何位置。 使用name屬性指定哪個配置文件接受配置。 可以使用逗號分隔列表指定多個配置文件。

<springProfile name="staging">
<!-- configuration to be enabled when the "staging" profile is active -->
</springProfile>

<springProfile name="dev, staging">
<!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
</springProfile>

<springProfile name="!production">
<!-- configuration to be enabled when the "production" profile is not active -->
</springProfile>

26.6.2 環境屬性

標簽允許您從Spring環境中顯示屬性,以便在Logback中使用。 如果您在logback中訪問application.properties文件中的值,這將非常有用。 標簽的工作方式與Logback標准的標簽類似,但不是指定直接值,而是指定屬性的來源(來自Environment)。 如果需要將屬性存儲在本地范圍以外的位置,則可以使用scope屬性。 如果在環境中未設置屬性的情況下需要備用值,則可以使用defaultValue屬性。

<springProperty scope="context" name="fluentHost" source="myapp.fluentd.host"
defaultValue="localhost"/>
<appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender">
<remoteHost>${fluentHost}</remoteHost>
...
</appender>

RelaxedPropertyResolver用於訪問Environment屬性。 如果以虛線表示法(my-property-name)指定源,則將嘗試所有寬松的變體(myPropertyName,MY_PROPERTY_NAME等)。

27. 開發Web應用程序

Spring Boot非常適合Web應用程序開發。 您可以使用嵌入式Tomcat,Jetty或Undertow輕松創建自包含的HTTP服務器。 大多數Web應用程序將使用spring-boot-starter-web模塊快速啟動和運行。

如果您尚未開發Spring Boot Web應用程序,則可以按照“Hello World!”示例進行操作。 在“入門”部分中的示例。

27.1 “Spring Web MVC框架”

Spring Web MVC框架(通常簡稱為“Spring MVC”)是一個豐富的“模型視圖控制器”Web框架。 Spring MVC允許您創建特殊的@Controller或@RestController bean來處理傳入的HTTP請求。 您的控制器中的方法將使用@RequestMapping注釋映射到HTTP。

以下是@RestController用於提供JSON數據的典型示例:

@RestController
@RequestMapping(value="/users")
public class MyRestController {

@RequestMapping(value="/{user}", method=RequestMethod.GET)
public User getUser(@PathVariable Long user) {
// ...
}

@RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
List<Customer> getUserCustomers(@PathVariable Long user) {
// ...
}

@RequestMapping(value="/{user}", method=RequestMethod.DELETE)
public User deleteUser(@PathVariable Long user) {
// ...
}

}

Spring MVC是Spring Framework的一部分,詳細信息可在參考文檔中找到。 Spring.io/guide中還有幾個指南可供Spring MVC使用。

27.1.1 Spring MVC自動配置

Spring Boot提供了適用於大多數應用程序的Spring MVC的自動配置。

自動配置在Spring的默認值之上添加以下功能:

  • 包含ContentNegotiatingViewResolver和BeanNameViewResolver bean。
  • 支持提供靜態資源,包括對WebJars的支持(見下文)。
  • Converter,GenericConverter,Formatter beans的自動注冊。
  • 支持HttpMessageConverters(見下文)。
  • 自動注冊MessageCodesResolver(見下文)。
  • 靜態index.html支持。
  • 自定義Favicon支持(見下文)。
  • 自動使用ConfigurableWebBindingInitializer bean(見下文)。

如果要保留Spring Boot MVC功能,並且您只需要添加其他MVC配置(interceptors, formatters, view, controllers等),你可以添加自己的WebConfigurerAdapter類型的@Configuration類,但不能使用@EnableWebMvc。 如果要提供自定義的RequestMappingHandlerMapping,RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver實例,您可以聲明一個提供此類組件的WebMvcRegistrationsAdapter實例。

如果要完全控制Spring MVC,可以使用@EnableWebMvc添加您自己的@Configuration注釋。

27.1.2 HttpMessageConverters

Spring MVC使用HttpMessageConverter接口轉換HTTP請求和響應。 包括一些開箱即用的合理配置,例如對象可以自動轉換為JSON(使用Jackson庫)或XML(使用Jackson XML擴展,如果可用,否則使用JAXB)。 字符串默認使用UTF-8進行編碼。

如果需要添加或自定義轉換器,可以使用Spring Boot HttpMessageConverter類:

import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;

@Configuration
public class MyConfiguration {

@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = ...
HttpMessageConverter<?> another = ...
return new HttpMessageConverters(additional, another);
}

}

上下文中存在的任何HttpMessageConverter bean將被添加到轉換器列表中。 您也可以以這種方式覆蓋默認轉換器。

27.1.3 自定義JSON序列化器和反序列化器

如果您使用Jackson序列化和反序列化JSON數據,則可能需要編寫自己的JsonSerializer和JsonDeserializer類。 自定義序列化程序通常通過一個模塊注冊到Jackson,但是Spring Boot提供了一個備用的@JsonComponent注釋,可以更容易地直接注冊Spring Bean。

您可以直接在JsonSerializer或JsonDeserializer實現中使用@JsonComponent。 您也可以將它用於包含序列化器/解串器的類作為內部類。 例如:

import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;

@JsonComponent
public class Example {

public static class Serializer extends JsonSerializer<SomeObject> {
// ...
}

public static class Deserializer extends JsonDeserializer<SomeObject> {
// ...
}

}

ApplicationContext中的所有@JsonComponent bean將自動注冊到Jackson,並且由於@JsonComponent是使用@Component進行元注解的,所以常規的組件掃描規則適用。

Spring Boot還提供了JsonObjectSerializerJsonObjectDeserializer基類,它們在序列化對象時為標准的Jackson版本提供了有用的替代方法。 有關詳細信息,請參閱Javadoc。

27.1.4 MessageCodesResolver

Spring MVC有一個生成錯誤代碼的策略,用於從綁定錯誤中提取錯誤消息:MessageCodesResolver。 Spring Boot將為您創建一個錯誤代碼,如果您設置spring.mvc.message-codes-resolver.format屬性PREFIX_ERROR_CODE或POSTFIX_ERROR_CODE(請參閱DefaultMessageCodesResolver.Format中的枚舉)。

27.1.5 靜態內容

默認情況下,Spring Boot將從類路徑或ServletContext的根目錄中的名為/static(或/ public或/resources或/META-INF/resources)的目錄提供靜態內容。 它使用Spring MVC中的ResourceHttpRequestHandler,因此您可以通過添加自己的WebMvcConfigurerAdapter並覆蓋addResourceHandlers方法來修改該行為。

在獨立的Web應用程序中,來自容器的默認servlet也被啟用,並且作為后備,如果Spring決定不處理它,則從ServletContext的根目錄提供內容。 大多數情況下,這不會發生(除非您修改默認的MVC配置),因為Spring將始終能夠通過DispatcherServlet處理請求。

默認情況下,資源映射到/ ,但可以通過spring.mvc.static-path-pattern調整。 例如,將所有資源重定位到 /resources/可以配置如下:

spring.mvc.static-path-pattern=/resources/**

您還可以使用spring.resources.static-locations(使用目錄位置列表替換默認值)來自定義靜態資源位置。 如果這樣做,默認歡迎頁面檢測將切換到您的自定義位置,因此,如果在啟動時任何位置都有一個index.html,它將是應用程序的主頁。

除了上述“標准”靜態資源位置之外,還提供了一個特殊情況,用於Webjars內容。 任何具有/ webjars / **中路徑的資源都將從jar文件中提供,如果它們以Webjars格式打包。

如果您的應用程序將被打包為jar,請不要使用 src/main/webapp 目錄。 雖然這個目錄是一個通用的標准,但它只適用於war包,如果生成一個jar,它將被大多數構建工具忽略。

Spring Boot還支持Spring MVC提供的高級資源處理功能,允許使用例如緩存靜態資源或使用Webjars的版本無關的URL。

要為Webjars使用版本無關的URL,只需添加webjars-locator依賴關系即可。然后聲明您的Webjar,以jQuery為例,如“/webjars/jquery/dist/jquery.min.js”,這將產生“/webjars/jquery/xyz/dist/jquery.min.js”,其中xyz是Webjar版本 。

如果您使用JBoss,則需要聲明webjars-locator-jboss-vfs依賴關系而不是webjars-locator; 否則所有Webjars都將解析為404。

要使用緩存清除功能,以下配置將為所有靜態資源配置緩存清除解決方案,從而有效地在URL中添加內容哈希值,例如:

spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**

鏈接資源在運行時在模板中被重寫,這歸功於自動配置為Thymeleaf和FreeMarker的ResourceUrlEncodingFilter。 使用JSP時,應手動聲明此過濾器。 其他模板引擎現在不會自動支持,但可以使用自定義模板宏/幫助程序和使用ResourceUrlProvider

當使用例如JavaScript模塊加載器動態加載資源時,重命名文件不是一個選項。這就是為什么其他策略也得到支持並可以合並的原因。 “固定(fixed)”策略將在URL中添加靜態版本字符串,而不更改文件名:

spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/js/lib/
spring.resources.chain.strategy.fixed.version=v12

使用此配置,位於“/js/lib/”下的JavaScript模塊將使用固定版本策略“/v12/js/lib/mymodule.js”,而其他資源仍將使用內容。

有關更多支持的選項,請參閱ResourceProperties

此功能已在專門的博客文章和Spring Framework參考文檔中進行了詳細描述。

27.1.6 自定義圖標

Spring Boot在配置的靜態內容位置和類路徑的根目錄(按順序)中查找favicon.ico。 如果文件存在,它將被自動用作應用程序的圖標。

27.1.7 ConfigurableWebBindingInitializer

Spring MVC使用WebBindingInitializer為特定請求初始化WebDataBinder。 如果您用@Bean創建自己的ConfigurableWebBindingInitializer @Bean,Spring Boot將自動配置Spring MVC以使用它。

27.1.8 模板引擎

除了REST Web服務,您還可以使用Spring MVC來提供動態HTML內容。 Spring MVC支持各種模板技術,包括Thymeleaf,FreeMarker和JSP。 許多其他模板引擎也運行自己的Spring MVC集成。

Spring Boot包括對以下模板引擎的自動配置支持:

如果可能,應避免使用JSP,當使用嵌入式servlet容器時,JSP有幾個已知的限制

當您使用默認配置的模板引擎之一時,您的模板將從 src/main/resources/templates 自動獲取。

IntelliJ IDEA根據運行應用程序的方式對類路徑進行不同的排序。 通過main方法在IDE中運行應用程序將導致使用Maven或Gradle打包的jar運行應用程序時的不同順序。這可能會導致Spring Boot找不到類路徑上的模板。 如果您受此問題的影響,您可以重新排序IDE中的類路徑,以放置模塊的類和資源。 或者,您可以配置模板前綴以搜索類路徑上的每個模板目錄:classpath*:/templates/

27.1.9 錯誤處理

默認情況下,Spring Boot提供 /error 映射,以合理的方式處理所有錯誤,並在servlet容器中注冊為“global”錯誤頁面。 對於機器客戶端,它將產生JSON響應,其中包含錯誤,HTTP狀態和異常消息的詳細信息。 對於瀏覽器客戶端,有一個’whitelabel’錯誤視圖,以HTML格式呈現相同的數據(定制它只需添加一個解析“error”的視圖)。 要完全替換默認行為,您可以實現ErrorController並注冊該類型的bean定義,或者簡單地添加一個類型為ErrorAttributes的bean來使用現有機制,但只是替換內容。

BasicErrorController可以用作自定義ErrorController的基類。 如果要添加新內容類型的處理程序(默認情況下是專門處理text/html並為其他內容提供備選),這一點尤其有用。 要做到這一點,只需擴展BasicErrorController並添加一個帶有@RequestMapping的公共方法,並創建一個新類型的bean。

您還可以定義一個@ControllerAdvice來自定義為特定控制器 and/or 異常類型返回的JSON文檔。

@ControllerAdvice(basePackageClasses = FooController.class)
public class FooControllerAdvice extends ResponseEntityExceptionHandler {

@ExceptionHandler(YourException.class)
@ResponseBody
ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
HttpStatus status = getStatus(request);
return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status);
}

private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
return HttpStatus.valueOf(statusCode);
}

}

在上面的示例中,如果由FooController在同一個包中定義的控件拋出了YourException,則將使用CustomerErrorType POJO的json表示法而不是ErrorAttributes表示形式。

自定義錯誤頁面

如果要顯示給定狀態代碼的自定義HTML錯誤頁面,請將文件添加到/error文件夾。 錯誤頁面可以是靜態HTML(即添加在任何靜態資源文件夾下)或使用模板構建。 該文件的名稱應該是確切的狀態代碼或一個序列掩碼。

例如,要將404映射到靜態HTML文件,您的文件夾結構將如下所示:

src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>

要使用FreeMarker模板映射所有5xx錯誤,使用如下結構:

src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.ftl
+- <other templates>

對於更復雜的映射,您還可以添加實現ErrorViewResolver接口的bean。

public class MyErrorViewResolver implements ErrorViewResolver {

@Override
public ModelAndView resolveErrorView(HttpServletRequest request,
HttpStatus status, Map<String, Object> model) {
// Use the request or status to optionally return a ModelAndView
return ...
}

}

您還可以使用常規的Spring MVC功能,如@ExceptionHandler方法@ControllerAdvice。 然后,ErrorController將接收任何未處理的異常。

映射Spring MVC之外的錯誤頁面

對於不使用Spring MVC的應用程序,可以使用ErrorPageRegistrar接口來直接注冊ErrorPages。這個抽象直接與底層的嵌入式servlet容器一起工作,即使沒有Spring MVC DispatcherServlet也可以工作。

@Bean
public ErrorPageRegistrar errorPageRegistrar(){
return new MyErrorPageRegistrar();
}

// ...

private static class MyErrorPageRegistrar implements ErrorPageRegistrar {

@Override
public void registerErrorPages(ErrorPageRegistry registry) {
registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
}

}

N.B. 如果您注冊一個最終由Filter過濾的路徑的ErrorPage(例如,像一些非Spring Web框架,例如Jersey和Wicket一樣),則必須將Filter顯式注冊為ERROR dispatcher,例如。

@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
...
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
}

(默認的FilterRegistrationBean不包括ERROR dispatcher 類型)。

WebSphere Application Server上的錯誤處理

當部署到servlet容器時,Spring Boot會使用其錯誤頁面過濾器將具有錯誤狀態的請求轉發到相應的錯誤頁面。 如果響應尚未提交,則該請求只能轉發到正確的錯誤頁面。 默認情況下,WebSphere Application Server 8.0及更高版本在成功完成servlet的服務方法后提交響應。 您應該通過將com.ibm.ws.webcontainer.invokeFlushAfterService設置為false來禁用此行為

27.1.10 Spring HATEOAS

如果您正在開發一種利用超媒體的RESTful API,Spring Boot可以為Spring HATEOAS提供自動配置,適用於大多數應用程序。 自動配置取代了使用@EnableHypermediaSupport的需求,並注冊了一些Bean,以便輕松構建基於超媒體的應用程序,包括LinkDiscoverers(用於客戶端支持)和配置為將響應正確地組織到所需表示中的ObjectMapper。 ObjectMapper將根據spring.jackson。*屬性或Jackson2ObjectMapperBuilder bean(如果存在)進行自定義。

您可以使用@EnableHypermediaSupport控制Spring HATEOAS配置。 請注意,這將禁用上述ObjectMapper定制。

27.1.11 CORS 支持

跨原始資源共享(CORS)是大多數瀏覽器實現的W3C規范,允許您以靈活的方式指定什么樣的跨域請求被授權,而不是使用一些不太安全和不太強大的方法,如IFRAME或JSONP。

從版本4.2起,Spring MVC支持CORS開箱即用。 在Spring Boot應用程序中的controller方法使用@CrossOrigin注解的CORS配置不需要任何特定的配置。 可以通過使用自定義的addCorsMappings(CorsRegistry)方法注冊WebMvcConfigurer bean來定義全局CORS配置:

@Configuration
public class MyConfiguration {

@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**");
}
};
}
}

27.2 JAX-RS 和 Jersey

如果您喜歡JAX-RS編程模型的REST endpoints ,您可以使用一個可用的實現而不是Spring MVC。 如果您剛剛在應用程序上下文中注冊了一個@Bean的Servlet或Filter,那么Jersey 1.x和Apache CXF的功能非常出色。 Jersey2.x有一些本地Spring支持,所以我們也提供自動配置支持它在Spring Boot與啟動器。

要開始使用Jersey 2.x,只需將spring-boot-starter-jersey作為依賴項,然后您需要一個@Bean類型ResourceConfig,您可以在其中注冊所有端點(endpoints):

@Component
public class JerseyConfig extends ResourceConfig {

public JerseyConfig() {
register(Endpoint.class);
}

}

Jersey對掃描可執行檔案的包是相當有限的。 例如,當運行可執行的war文件時,它無法掃描在WEB-INF/classes中找到的包中的端點(endpoints)。 為了避免這種限制,不應使packages方法,並且應使用上述寄存器方法單獨注冊(register)端點。

您還可以注冊任意數量的ResourceConfigCustomizer的實現bean,以實現更高級的自定義。

所有注冊的端點都應為具有HTTP資源注解(@GET等)的@Components,例如。

@Component
@Path("/hello")
public class Endpoint {

@GET
public String message() {
return "Hello";
}

}

由於Endpoint是一個Spring @Component,所以Spring的生命周期由Spring管理,您可以使用@Autowired依賴關系並使用@Value注入外部配置。 默認情況下,Jersey servlet將被注冊並映射到/ *。 您可以通過將@ApplicationPath添加到ResourceConfig來更改映射。

默認情況下,Jersey將通過@Bean以名為jerseyServletRegistration的ServletRegistrationBean類型在Servlet進行設置。 默認情況下,servlet將被初始化,但是您可以使用spring.jersey.servlet.load-on-startup進行自定義。您可以通過創建一個自己的同名文件來禁用或覆蓋該bean。 您也可以通過設置spring.jersey.type = filter(在這種情況下,@Bean來替換或替換為jerseyFilterRegistration),使用Filter而不是Servlet。 servlet有一個@Order,您可以使用spring.jersey.filter.order設置。 可以使用spring.jersey.init.* 給出Servlet和過濾器注冊的init參數,以指定屬性的映射。

有一個Jersey示例,所以你可以看到如何設置。 還有一個Jersey1.x示例。 請注意,在Jersey1.x示例中,spring-boot maven插件已經被配置為打開一些Jersey jar,以便它們可以被JAX-RS實現掃描(因為示例要求它們在Filter注冊中進行掃描) 。 如果您的任何JAX-RS資源作為嵌套的jar打包,您可能需要執行相同操作。

27.3 嵌入式servlet容器支持

Spring Boot包括對嵌入式Tomcat,Jetty和Undertow服務器的支持。 大多數開發人員將簡單地使用適當的“Starter”來獲取完全配置的實例。 默認情況下,嵌入式服務器將監聽端口8080上的HTTP請求。

如果您選擇在CentOS上使用Tomcat,請注意,默認情況下,臨時目錄用於存儲已編譯的JSP,文件上傳等。當您的應用程序正在運行導致故障時,該目錄可能會被tmpwatch刪除。 為了避免這種情況,您可能需要自定義tmpwatch配置,以便tomcat.*目錄不被刪除,或配置server.tomcat.basedir,以便嵌入式Tomcat使用不同的位置

27.3.1 Servlets, Filters 和 listeners

當使用嵌入式servlet容器時,可以使用Spring bean或通過掃描Servlet組件(例如HttpSessionListener)注冊Servlet規范中的Servlet,過濾器和所有監聽器。

將Servlets,過濾器和監聽器注冊為Spring bean

任何Servlet,Filter或Servlet Listener 實例都會作為Spring bean注冊到嵌入式容器中。 可以非常方便地在配置過程中引用您的application.properties中的值。

默認情況下,如果容器中只包含一個Servlet,它將映射到/。 在多個Servlet bean的情況下,bean名稱將作為路徑前綴。 過濾器(Filters)將映射到/*,默認過濾所有請求。

如果基於慣例的映射不夠靈活,可以使用ServletRegistrationBean,FilterRegistrationBean和ServletListenerRegistrationBean類來完成控制。

27.3.2 Servlet Context 初始化

嵌入式servlet容器不會直接執行Servlet 3.0+ javax.servlet.ServletContainerInitializer接口或Spring的org.springframework.web.WebApplicationInitializer接口。 這樣設計的目的旨在降低在war中運行的第三方庫破壞Spring Boot應用程序的風險。

如果您需要在Spring Boot應用程序中執行servlet context 初始化,則應注冊一個實現org.springframework.boot.context.embedded.ServletContextInitializer接口的bean。 單個onStartup方法提供對ServletContext的訪問,並且如果需要,可以輕松地用作現有WebApplicationInitializer的適配器。

掃描Servlet,過濾器和監聽器

使用嵌入式容器時,可以使用@ServletComponentScan啟用@WebServlet,@WebFilter和@WebListener注解類的自動注冊。

@ServletComponentScan在獨立容器中不起作用,在該容器中將使用容器的內置發現機制。

27.3.3 EmbeddedWebApplicationContext

在Spring Boot引導下,將會使用一種新類型的ApplicationContext來支持嵌入式的servlet容器。 EmbeddedWebApplicationContext是一種特殊類型的WebApplicationContext,它通過搜索單個EmbeddedServletContainerFactory bean來引導自身。 通常,TomcatEmbeddedServletContainerFactory,JettyEmbeddedServletContainerFactory或UndertowEmbeddedServletContainerFactory將被自動配置。

您通常不需要知道這些實現類。 大多數應用程序將被自動配置,並將代表您創建適當的ApplicationContext和EmbeddedServletContainerFactory。

27.3.4 定制嵌入式servlet容器

可以使用Spring Environment屬性配置常見的servlet容器設置。 通常您可以在application.properties文件中定義屬性。

常用服務器設置包括:

  • 網絡設置:偵聽端口的HTTP請求(server.port),接口地址綁定到server.address等。
  • 會話設置:會話是否持久化(server.session.persistence),會話超時(server.session.timeout),會話數據的位置(server.session.store-dir)和session-cookie配置(server.session.cookie.*)。
  • 錯誤管理:錯誤頁面的位置(server.error.path)等
  • SSL
  • HTTP壓縮

Spring Boot盡可能地嘗試公開常見設置,但並不總是可能的。 對於這些情況,專用命名空間提供服務器特定的定制(請參閱server.tomcat和server.undertow)。 例如,可以使用嵌入式servlet容器的特定功能來配置訪問日志

有關完整列表,請參閱 ServerProperties 類。

用程序定制

如果需要以編程方式配置嵌入式servlet容器,您可以注冊一個實現EmbeddedServletContainerCustomizer接口的Spring bean。 EmbeddedServletContainerCustomizer提供對ConfigurableEmbeddedServletContainer的訪問,其中包含許多自定義設置方法。

import org.springframework.boot.context.embedded.*;
import org.springframework.stereotype.Component;

@Component
public class CustomizationBean implements EmbeddedServletContainerCustomizer {

@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setPort(9000);
}

}

直接自定義ConfigurableEmbeddedServletContainer

如果上述定制技術有太多限制,您可以自己注冊TomcatEmbeddedServletContainerFactory,JettyEmbeddedServletContainerFactory或UndertowEmbeddedServletContainerFactory bean。

@Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.setPort(9000);
factory.setSessionTimeout(10, TimeUnit.MINUTES);
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
return factory;
}

setter方法提供了許多配置選項。 如果您需要做更多的自定義,還會提供幾種保護方法“鈎子”。 有關詳細信息,請參閱源代碼文檔。

27.3.5 JSP限制

當運行使用嵌入式servlet容器(並打包為可執行文檔)的Spring Boot應用程序時,對JSP支持有一些限制。

  • 可以使用Tomcat和war包,即可執行的war將會起作用,並且也可以部署到標准容器(不限於但包括Tomcat)中。 由於Tomcat中的硬編碼文件模式,可執行的jar將無法正常工作。
  • 可以使用Jetty和war包,即可執行的war將會起作用,並且也可以部署到任何標准的容器,它應該可以工作。
  • Undertow不支持JSP。
  • 創建自定義的error.jsp頁面將不會覆蓋默認視圖以進行錯誤處理,而應使用自定義錯誤頁面

28. Security

如果Spring Security位於類路徑上,則默認情況下,Web應用程序將在所有HTTP端點上使用“basic”身份驗證。 要向Web應用程序添加方法級安全性,您還可以使用所需的設置添加@EnableGlobalMethodSecurity。 有關更多信息,請參見“Spring Security Reference”。

默認的AuthenticationManager有一個用戶(用戶名’user’和隨機密碼,在應用程序啟動時以INFO級別打印)

Using default security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35

如果您調整日志記錄配置,請確保將org.springframework.boot.autoconfigure.security類別設置為記錄INFO消息,否則將不會打印默認密碼。

您可以通過提供security.user.password來更改密碼。 這個和其他有用的屬性通過 SecurityProperties(屬性前綴“security”)進行外部化。

默認的安全配置在SecurityAutoConfiguration和從那里導入的類中實現(用於Web安全的SpringBootWebSecurityConfiguration和用於認證配置的AuthenticationManagerConfiguration,這在非Web應用程序中也是相關的)。 要完全關閉默認的Web應用程序安全配置,您可以使用@EnableWebSecurity添加一個bean(這不會禁用身份驗證管理器配置或Actuator的安全性)。 要定制它,您通常使用WebSecurityConfigurerAdapter類型的外部屬性和bean(例如添加基於表單的登錄)。 要關閉身份驗證管理器配置,您可以添加AuthenticationManager類型的bean,或者通過將AuthenticationManagerBuilder自動連接到您的一個@Configuration類中的方法來配置全局AuthenticationManager。 Spring Boot示例中有幾個安全應用程序可以讓您開始使用常見的用例

您在Web應用程序中獲得的基本功能包括:

  • 具有內存存儲和單個用戶的AuthenticationManager Bean(請參閱用於用戶屬性的SecurityProperties.User)。
  • 對於常見的靜態資源位置,忽略(不安全)路徑(/css/**, /js/**, /images/**, /webjars/** and **/favicon.ico)。
  • HTTP所有其他端點的baseic security 。
  • 安全事件發布到Spring的ApplicationEventPublisher(成功、不成功的身份驗證、拒絕訪問)。
  • 默認情況下,Spring Security提供的常見的底層功能(HSTS,XSS,CSRF,緩存)都是打開的。

所有上述可以使用外部屬性(security.*)打開、關閉或修改。 要覆蓋訪問規則而不更改任何其他自動配置的功能,請添加一個帶有@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)的WebSecurityConfigurerAdapter類型的Bean,並配置它以滿足您的需要。

默認情況下,WebSecurityConfigurerAdapter將匹配任何路徑。 如果您不想完全覆蓋Spring Boot自動配置的訪問規則,您的適配器必須顯式配置您要覆蓋的路徑。

28.1 OAuth2

如果您的類路徑中有spring-security-oauth2,您可以利用一些自動配置來輕松設置授權或資源服務器。 有關完整的詳細信息,請參閱“Spring Security OAuth 2開發人員指南”。

28.1.1 授權服務器

要創建授權服務器並授予訪問令牌,您需要使用@EnableAuthorizationServer並提供security.oauth2.client.client-id和security.oauth2.client.client-secret]屬性。 客戶端將為您注冊在內存中。

$ curl client:secret@localhost:8080/oauth/token -d grant_type=password -d username=user -d password=pwd

/token 端點的基本身份驗證憑證是client-id和client-secret。 用戶憑據是普通的Spring Security用戶details (在Spring引導中默認為“user”和隨機密碼)。

要關閉自動配置並自行配置授權服務器功能,只需添加一個類型為AuthorizationServerConfigurer的@Bean。

28.1.2 資源服務器

要使用訪問令牌(token),您需要一個資源服務器(可以與授權服務器相同)。 創建資源服務器很簡單,只需添加@EnableResourceServer並提供一些配置,以允許服務器解碼訪問令牌。 如果您的應用程序也是授權服務器,則它已經知道如何解碼令牌,無需做其他事情。 如果你的應用程序是一個獨立的服務,那么你需要給它一些更多的配置,以下選項之一:

如果您同時指定user-info-uri和token-info-uri,那么您可以設置一個標志,表示優先於另一個(prefer-token-inf=true是默認值)。

或者(不是user-info-uri或token-info-uri的情況)如果令牌是JWT,您可以配置security.oauth2.resource.jwt.key-value來本地解碼(key是驗證密鑰verification key)。 驗證密鑰值是對稱秘密或PEM編碼的RSA公鑰。 如果您沒有密鑰,並且它是公開的,您可以提供一個可以使用security.oauth2.resource.jwt.key-uri下載的URI(具有“value”字段的JSON對象)。 例如在PWS上:

$ curl https://uaa.run.pivotal.io/token_key
{"alg":"SHA256withRSA","value":"-----BEGIN PUBLIC KEY-----\nMIIBI...\n-----END PUBLIC KEY-----\n"}

如果您使用security.oauth2.resource.jwt.key-uri,則應用程序啟動時需要運行授權服務器。 如果找不到密鑰,它將記錄一個警告,並告訴您如何解決該問題。

如果您使用security.oauth2.resource.jwt.key-uri,則應用程序啟動時需要運行授權服務器。 如果找不到密鑰,它將會在日志記錄一個警告,並告訴您如何解決該問題。

OAuth2資源由order security.oauth2.resource.filter-order的過濾器鏈保護,默認情況下保護執行器(actuator)端點的過濾器(所以執行器(actuator)端點將保留在HTTP Basic上,除非更改順序)。

28.2 User Info中的令牌類型

Google和某些其他第三方身份認證提供商對在header中發送到用戶信息端點的令牌類型名稱更為嚴格。 默認值為“Bearer”,適合大多數提供程序並匹配規范,但如果需要更改,可以設置security.oauth2.resource.token-type。

28.3 自定義用戶信息RestTemplate

如果您有user-info-uri,則資源服務器功能在內部使用OAuth2RestTemplate來獲取用戶身份驗證信息。 這是以UserInfoRestTemplateFactory類型的@Bean提供的。 大多數提供程序的默認值應該是能滿足正常使用,但有時您可能需要添加其他攔截器,或者更改請求驗證器(例如:令牌如何附加到傳出請求)。 進行自定義,只需創建一個類型為UserInfoRestTemplateCustomizer的bean - 它具有一個方法,在bean創建之后但在初始化之前將被調用。 這里定制的rest模板只能在內部進行驗證。 或者,您可以定義自己的UserInfoRestTemplateFactory @Bean來完全控制。

要在YAML中設置RSA密鑰值,請使用“pipe”繼續標記將其分割成多行(“|”),並記住縮進鍵值(它是標准的 YAML 語言功能)。 例:

security:
oauth2:
resource:
jwt:
keyValue: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC...
-----END PUBLIC KEY-----

28.3.1 Client

要使您的 web-app 進入OAuth2客戶端,您可以簡單地添加@ EnableOAuth2Client,Spring Boot將創建一個OAuth2ClientContext和OAuth2ProtectedResourceDetails,這些是創建OAuth2RestOperations所必需的。 Spring Boot不會自動創建這樣的bean,但是您可以輕松創建自己的bean:

@Bean
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails details) {
return new OAuth2RestTemplate(details, oauth2ClientContext);
}

您可能需要添加限定符並查看您的配置,因為您的應用程序可能會定義多個RestTemplate。

此配置使用security.oauth2.client.*作為憑據(可能與授權服務器中使用的相同),但另外還需要知道授權服務器中的授權和令牌URI。 例如:

application.yml.

security:
oauth2:
client:
clientId: bd1c0a783ccdd1c9b9e4
clientSecret: 1a9030fbca47a5b2c28e92f19050bb77824b5ad1
accessTokenUri: https://github.com/login/oauth/access_token
userAuthorizationUri: https://github.com/login/oauth/authorize
clientAuthenticationScheme: form

當您嘗試使用OAuth2RestTemplate時,具有此配置的應用程序將重定向到Github進行授權。 如果您已經登錄Github,您甚至不會注意到它已經被認證。 如果您的應用程序在端口8080上運行(在Github或其他提供商注冊自己的客戶端應用程序以獲得更大的靈活性),這些特定的憑據才會起作用。

要限制客戶端在獲取訪問令牌時要求的范圍,您可以設置security.oauth2.client.scope(逗號分隔或YAML中的數組)。 默認情況下,scope是空的,由授權服務器決定其默認值,通常取決於客戶端注冊中的設置。

還有一個security.oauth2.client.client-authentication-scheme的設置,默認為“header”(但是如果像Github那樣,您可能需要將其設置為“form”,例如,您的OAuth2提供程序不喜歡header 認證)。 事實上,security.oauth2.client.*屬性綁定到AuthorizationCodeResourceDetails的一個實例,因此可以指定其所有的屬性。

在非Web應用程序中,您仍然可以創建一個OAuth2RestOperations,它仍然連接到security.oauth2.client.*配置中。 在這種情況下,它是一個“客戶端憑據令牌授予”,您如果使用它就請求它(並且不需要使用@EnableOAuth2Client或@EnableOAuth2Sso)。為了防止定義基礎設施,只需從配置中刪除security.oauth2.client.client-id(或使其成為空字符串)。

28.3.2 單點登錄

OAuth2客戶端可用於從提供商獲取用戶詳細信息(如果此類功能可用),然后將其轉換為Spring Security的身份驗證令牌。 以上資源服務器通過user-info-uri屬性支持此功能這是基於OAuth2的單點登錄(SSO)協議的基礎,Spring Boot可以通過提供@ EnableOAuth2Sso注解來輕松加入。 上面的Github客戶端可以通過添加該注釋並聲明在何處查找端點(除了上面列出的security.oauth2.client.*配置)外,還可以保護所有資源並使用Github/user/endpoint進行身份驗證:

application.yml.

security:
oauth2:
...
resource:
userInfoUri: https://api.github.com/user
preferTokenInfo: false

由於默認情況下所有路徑都是安全的,所以沒有可以向未經身份驗證的用戶顯示“家”頁面,並邀請他們登錄(通過訪問/登錄路徑或由security.oauth2.sso.login-path指定的路徑) 。

由於默認情況下所有路徑都是要求安全的,所以沒有可以向未經身份驗證的用戶顯示“home”頁面,並邀請他們登錄(通過訪問/login 路徑或由security.oauth2.sso.login-path指定的路徑) 。

要自定義保護的訪問規則或路徑,因此您可以添加“home”頁面,例如,@EnableOAuth2Sso可以添加到WebSecurityConfigurerAdapter,並且注解將使其被修飾和增強,以使所需的/login路徑可以工作。 例如,這里我們簡單地允許未經身份驗證的訪問“/“下的主頁面,並保留其他所有內容的默認值:

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
public void init(WebSecurity web) {
web.ignore("/");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests().anyRequest().authenticated();
}

}

28.4 Actuator Security

如果Actuator也在使用中,您會發現:

  • 即使應用程序端點不安全,管理端點也是安全的。
  • Security 事件將轉換為AuditEvent實例,並發布到AuditEventRepository。
  • 默認用戶將具有ACTUATOR角色以及USER角色。

Actuator的安全功能可以使用外部屬性(management.security.*)進行修改。要覆蓋應用程序訪問規則,請添加一個類型為WebSecurityConfigurerAdapter的@Bean,如果您不想覆蓋執行程序訪問規則,則使用@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)或@Order(ManagementServerProperties.ACCESS_OVERRIDE_ORDER)覆蓋執行器訪問規則。

29. 使用SQL數據庫

Spring Framework 為使用SQL數據庫提供了廣泛的支持。 從使用JdbcTemplate直接JDBC訪問到完成“對象關系映射”技術,如Hibernate。Spring Data提供了額外的功能,直接從接口創建Repository實現,並使用約定從方法名稱生成查詢。

29.1 配置DataSource

Java的javax.sql.DataSource接口提供了使用數據庫連接的標准方法。傳統上,DataSource使用URL和一些憑據來建立數據庫連接。

還可以查看更多高級示例的“操作方法”部分,通常可以完全控制DataSource的配置。

29.1.1 嵌入式數據庫支持

使用內存中嵌入式數據庫開發應用程序通常很方便。 顯然,內存數據庫不提供持久化存儲; 您的應用程序啟動時,您將需要初始化數據庫,並在應用程序結束時丟棄數據。

“How-to”部分包含如何初始化數據庫

Spring Boot可以自動配置嵌入式 H2HSQLDerby 數據庫。 您不需要提供任何連接URL,只需將要使用的嵌入式數據庫的依賴關系包含進去即可。

如果您在測試中使用此功能,您可能會注意到,整個測試套件都會重復使用相同的數據庫,而不管您使用的應用程序上下文的數量。 如果要確保每個上下文都有一個單獨的嵌入式數據庫,您應該將spring.datasource.generate-unique-name設置為true。

例如,典型的POM依賴關系是:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>

對於要自動配置的嵌入式數據庫,您需要依賴spring-jdbc。 在這個例子中,它是通過spring-boot-starter-data-jpa傳遞的。

如果由於某種原因配置嵌入式數據庫的連接URL,則應注意確保數據庫的自動關閉被禁用。 如果你使用H2,你應該使用DB_CLOSE_ON_EXIT=FALSE這樣做。 如果您使用HSQLDB,則應確保不使用shutdown=true。 禁用數據庫的自動關閉允許Spring Boot控制數據庫何時關閉,從而確保在不再需要訪問數據庫時發生這種情況。

29.1.2 連接到生產環境數據庫

生產數據庫連接也可以使用連接池數據源自動配置。 這是選擇具體實現的算法:

  • 我們更喜歡Tomcat連接池DataSource的性能和並發性,所以如果可用,我們總是選擇它。
  • 否則,如果HikariCP可用,我們將使用它。
  • 如果Tomcat池數據源和HikariCP都不可用,並且如果Commons DBCP可用,我們將使用它,但是我們不建議在生產中使用它,並且不支持它。
  • 最后,如果Commons DBCP2可用,我們將使用它。

如果您使用spring-boot-starter-jdbc或spring-boot-starter-data-jpa 的startters,您將自動獲得對tomcat-jdbc的依賴。

您可以完全繞過該算法,並通過spring.datasource.type屬性指定要使用的連接池。 如果您在Tomcat容器中運行應用程序,則默認情況下提供tomcat-jdbc,這一點尤為重要。

可以隨時手動配置其他連接池。如果您定義自己的DataSource bean,則不會發生自動配置。

DataSource配置由spring.datasource中的外部配置屬性控制。 例如,您可以在application.properties中聲明以下部分:

spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

您應至少使用spring.datasource.url屬性指定url,否則Spring Boot將嘗試自動配置嵌入式數據庫。

您通常不需要指定驅動程序類名稱,因為Spring Boot可以從url為大多數數據庫推斷出驅動程序名稱。

對於要創建的池數據源,我們需要能夠驗證有效的Driver類是否可用,所以我們在做任何事情之前檢查它。 即 如果您設置spring.datasource.driver-class-name=com.mysql.jdbc.Driver,那么該類必須可加載。

有關更多支持的選項,請參閱 DataSourceProperties。 這些是標准選項,無論實際執行情況如何。 還可以使用各自的前綴(spring.datasource.tomcat.*,spring.datasource.hikari.*和spring.datasource.dbcp2.*)微調實現特定的設置。 有關更多詳細信息,請參閱您正在使用的連接池實現的文檔。

例如,如果您正在使用Tomcat連接池,您可以自定義許多其他設置:

# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.tomcat.max-wait=10000

# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.tomcat.max-active=50

# Validate the connection before borrowing it from the pool.
spring.datasource.tomcat.test-on-borrow=true

29.1.3 連接到JNDI DataSource

如果要將Spring Boot應用程序部署到應用程序服務器,則可能需要使用應用程序服務器內置功能來配置和管理DataSource,並使用JNDI進行訪問。

spring.datasource.jndi-name屬性可以用作spring.datasource.url,spring.datasource.username和spring.datasource.password屬性的替代方法,以從特定的JNDI位置訪問DataSource。 例如,application.properties中的以下部分顯示了如何訪問JBoss AS定義的DataSource:

spring.datasource.jndi-name=java:jboss/datasources/customers

29.2 使用JdbcTemplate

Spring的JdbcTemplate和NamedParameterJdbcTemplate類是自動配置的,您可以將它們直接連接到您自己的bean中:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

private final JdbcTemplate jdbcTemplate;

@Autowired
public MyBean(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

// ...

}

29.3 JPA 和 ‘Spring Data’

Java Persistence API是一種標准技術,可讓您將對象映射到關系數據庫。 spring-boot-starter-data-jpa POM提供了一種快速入門的方法。 它提供以下關鍵依賴:

  • Hibernate - 最受歡迎的JPA實現之一。
  • Spring Data JPA - 可以輕松實現基於JPA的存儲庫。
  • Spring ORMs - 來自Spring Framework的核心ORM支持。

我們不會在這里介紹太多的JPA或Spring Data的細節。 您可以從spring.io中查看“使用JPA訪問數據”指南,並閱讀Spring Data JPAHibernate參考文檔。

默認情況下,Spring Boot使用Hibernate 5.0.x. 但是,如果您願意,也可以使用4.3.x或5.2.x。 請參考 Hibernate 4Hibernate 5.2 示例,看看如何做到這一點。

29.3.1 實體類

傳統上,JPA’Entity’類在persistence.xml文件中指定。 使用Spring Boot此文件不是必需的,而是使用“實體掃描”。 默認情況下,將搜索主配置類下面的所有包(用@EnableAutoConfiguration或@SpringBootApplication注解的類)。

任何用@Entity,@Embeddable或@MappedSuperclass注解的類將被考慮。 典型的實體類將如下所示:

package com.example.myapp.domain;

import java.io.Serializable;
import javax.persistence.*;

@Entity
public class City implements Serializable {

@Id
@GeneratedValue
private Long id;

@Column(nullable = false)
private String name;

@Column(nullable = false)
private String state;

// ... additional members, often include @OneToMany mappings

protected City() {
// no-args constructor required by JPA spec
// this one is protected since it shouldn't be used directly
}

public City(String name, String state) {
this.name = name;
this.country = country;
}

public String getName() {
return this.name;
}

public String getState() {
return this.state;
}

// ... etc

}

您可以使用@EntityScan注解自定義實體掃描位置。 請參見第77.4節“從Spring配置中分離@Entity定義”操作方法。

29.3.2 Spring Data JPA Repositories

Spring Data JPA庫是可以定義用於訪問數據的接口。 JPA查詢是從您的方法名稱自動創建的。 例如,CityRepository接口可以聲明findAllByState(String state)方法來查找給定狀態下的所有城市。

對於更復雜的查詢,您可以使用Spring數據查詢注解來注解您的方法。

Spring數據存儲庫通常從Repository或CrudRepository接口擴展。 如果您正在使用自動配置,將從包含主配置類(通過@EnableAutoConfiguration或@SpringBootApplication注解的包)的包中搜索存儲庫(repositories)。

這是一個典型的Spring數據庫:

package com.example.myapp.domain;

import org.springframework.data.domain.*;
import org.springframework.data.repository.*;

public interface CityRepository extends Repository<City, Long> {

Page<City> findAll(Pageable pageable);

City findByNameAndCountryAllIgnoringCase(String name, String country);

}

我們只是觸及了Spring Data JPA的表面。 有關完整的詳細信息,請查閱其參考文檔

29.3.3 創建和刪除JPA數據庫

默認情況下,僅當您使用嵌入式數據庫(H2,HSQL或Derby)時才會自動創建JPA數據庫。 您可以使用spring.jpa。*屬性顯式配置JPA設置。 例如,要創建和刪除表,您可以將以下內容添加到application.properties中。

spring.jpa.hibernate.ddl-auto=create-drop

Hibernate自己的內部屬性名稱(如果你記得更好)是hibernate.hbm2ddl.auto。您可以使用spring.jpa.properties *(將其添加到實體管理器時這個前綴會被刪除)與其他Hibernate屬性一起設置。 例:

spring.jpa.properties.hibernate.globally_quoted_identifiers=true

hibernate.globally_quoted_identifiers 傳遞給Hibernate實體管理器。

默認情況下,DDL執行(或驗證)將延遲到ApplicationContext啟動。 還有一個spring.jpa.generate-ddl標志,但是如果Hibernate 自動配置是激活的,那么它將不會被使用,因為ddl-auto配置更好。

29.3.4 在View中打開EntityManager

如果您正在運行Web應用程序,Spring Boot將默認注冊OpenEntityManagerInViewInterceptor來應用“查看”中的“打開EntityManager”模式,即允許在Web視圖中進行延遲加載。 如果你不想要這個行為,你應該在你的application.properties中將spring.jpa.open-in-view設置為false。

29.4 使用H2的Web控制台

H2數據庫提供了一個基於瀏覽器的控制台,Spring Boot可以為您自動配置。 滿足以下條件時,控制台將自動配置:

如果您不使用Spring Boot的開發人員工具,但仍希望使用H2的控制台,那么可以通過配置一個值為true的spring.h2.console.enabled屬性來實現。 H2控制台僅用於開發期間,因此應注意確保spring.h2.console.enabled在生產中未設置為true。

29.4.1 更改H2控制台的路徑

默認情況下,控制台路徑將在 /h2-console上。 您可以使用spring.h2.console.path屬性來自定義控制台的路徑。

29.4.2 保護H2控制台

當Spring Security位於類路徑上且啟用了基本身份驗證時,H2控制台將自動使用基本身份驗證進行保護。 以下屬性可用於自定義安全配置:

  • security.user.role
  • security.basic.authorize-mode
  • security.basic.enabled

29.5 使用jOOQ

Java面向對象查詢(jOOQ)是Data Geekery的產品,它從數據庫生成Java代碼,並通過流暢的API構建類型安全的SQL查詢。 商業版和開源版都可以與Spring Boot一起使用。

29.5.1 代碼生成

為了使用jOOQ類型安全的查詢,您需要從數據庫模式生成Java類。 您可以按照jOOQ用戶手冊中的說明進行操作。 如果您正在使用jooq-codegen-maven插件(並且還使用spring-boot-starter-parent“父POM”),您可以安全地省略插件的標簽。 您還可以使用Spring Boot定義的版本變量(例如h2.version)來聲明插件的數據庫依賴關系。 以下是一個例子:

<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<executions>
...
</executions>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
<configuration>
<jdbc>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:~/yourdatabase</url>
</jdbc>
<generator>
...
</generator>
</configuration>
</plugin>

29.5.2 使用 DSLContext

jOOQ提供的流暢的API是通過org.jooq.DSLContext接口啟動的。 Spring Boot將自動配置DSLContext作為Spring Bean並將其連接到應用程序DataSource。 要使用DSLContext,您只需@Autowire它:

@Component
public class JooqExample implements CommandLineRunner {

private final DSLContext create;

@Autowired
public JooqExample(DSLContext dslContext) {
this.create = dslContext;
}

}

jOOQ手冊傾向於使用名為create的變量來保存DSLContext,我們在此示例中也是這樣。

然后,您可以使用DSLContext構建查詢:

public List<GregorianCalendar> authorsBornAfter1980() {
return this.create.selectFrom(AUTHOR)
.where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1)))
.fetch(AUTHOR.DATE_OF_BIRTH);
}

29.5.3 定制jOOQ

您可以通過在application.properties中設置spring.jooq.sql-dialect來自定義jOOQ使用的SQL方言。 例如,要指定Postgres,您可以添加:

spring.jooq.sql-dialect=Postgres

通過定義自己的@Bean定義可以實現更高級的定制,這些定義將在創建jOOQ配置時使用。您可以為以下jOOQ類型定義bean:

  • ConnectionProvider
  • TransactionProvider
  • RecordMapperProvider
  • RecordListenerProvider
  • ExecuteListenerProvider
  • VisitListenerProvider

如果要完全控制jOOQ配置,您還可以創建自己的org.jooq.Configuration @Bean。

30. 使用NoSQL技術

Spring Data提供了額外的項目,可幫助您訪問各種NoSQL技術,包括MongoDBNeo4JElasticsearchSolrRedisGemfireCassandraCouchbaseLDAP。 Spring Boot為Redis,MongoDB,Neo4j,Elasticsearch,Solr Cassandra,Couchbase和LDAP提供了自動配置; 您也可以使用其他項目,但您需要自行配置它們。 請參閱projects.spring.io/spring-data中相應的參考文檔。

30.1 Redis

Redis是一個緩存,消息代理並有功能豐富的鍵值存儲數據庫。Spring Boot提供了Jedis客戶端庫的基本自動配置和Spring Data Redis提供的抽象。 有一個spring-boot-starter-data-redis“Starter”用於以方便的方式收集依賴關系。

30.1.1 連接到Redis

您可以像任何其他Spring Bean一樣注入自動配置的RedisConnectionFactory,StringRedisTemplate或vanilla RedisTemplate實例。 默認情況下,實例將嘗試使用localhost:6379連接到Redis服務器:

@Component
public class MyBean {

private StringRedisTemplate template;

@Autowired
public MyBean(StringRedisTemplate template) {
this.template = template;
}

// ...

}

如果您添加了您自己的任何自動配置類型的@Bean,它將替換默認值(除了在RedisTemplate的情況下,排除是基於bean名稱“redisTemplate”而不是其類型)。 如果commons-pool2在類路徑上,則默認情況下將獲得一個pooled連接工廠。

30.2 MongoDB

MongoDB是一個開源的NoSQL文檔數據庫,它使用類似JSON的架構,而不是傳統的基於表的關系數據。 Spring Boot為MongoDB提供了幾種便利,包括spring-boot-starter-data-mongodb’Starter’。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM