Spring Boot は、Web アプリケーションの開発に最適です。組み込み Tomcat、Jetty、Undertow、Netty を使用して、自己完結型の HTTP サーバーを作成できます。ほとんどの Web アプリケーションは、spring-boot-starter-web
モジュールを使用して、すばやく起動して実行します。spring-boot-starter-webflux
モジュールを使用して、リアクティブ Web アプリケーションを構築することもできます。
Spring Boot Web アプリケーションをまだ開発していない場合は、入門セクションの "Hello World!" の例に従うことができます。
1. サーブレット Web アプリケーション
サーブレットベースの Web アプリケーションを構築する場合は、Spring MVC または Jersey 用の Spring Boot の自動構成を利用できます。
1.1. 「Spring Web MVC フレームワーク」
Spring Web MVC フレームワーク ( "Spring MVC" と呼ばれることが多い) は、リッチな「モデル、ビュー、コントローラー」Web フレームワークです。Spring MVC を使用すると、受信 HTTP リクエストを処理するための特別な @Controller
または @RestController
Bean を作成できます。コントローラーのメソッドは、@RequestMapping
アノテーションを使用して HTTP にマップされます。
次のコードは、JSON データを提供する典型的な @RestController
を示しています。
@RestController
@RequestMapping("/users")
public class MyRestController {
private final UserRepository userRepository;
private final CustomerRepository customerRepository;
public MyRestController(UserRepository userRepository, CustomerRepository customerRepository) {
this.userRepository = userRepository;
this.customerRepository = customerRepository;
}
@GetMapping("/{userId}")
public User getUser(@PathVariable Long userId) {
return this.userRepository.findById(userId).get();
}
@GetMapping("/{userId}/customers")
public List<Customer> getUserCustomers(@PathVariable Long userId) {
return this.userRepository.findById(userId).map(this.customerRepository::findByUser).get();
}
@DeleteMapping("/{userId}")
public void deleteUser(@PathVariable Long userId) {
this.userRepository.deleteById(userId);
}
}
@RestController
@RequestMapping("/users")
class MyRestController(private val userRepository: UserRepository, private val customerRepository: CustomerRepository) {
@GetMapping("/{userId}")
fun getUser(@PathVariable userId: Long): User {
return userRepository.findById(userId).get()
}
@GetMapping("/{userId}/customers")
fun getUserCustomers(@PathVariable userId: Long): List<Customer> {
return userRepository.findById(userId).map(customerRepository::findByUser).get()
}
@DeleteMapping("/{userId}")
fun deleteUser(@PathVariable userId: Long) {
userRepository.deleteById(userId)
}
}
次の例に示すように、関数型バリアントである "WebMvc.fn" は、ルーティング構成をリクエストの実際の処理から分離します。
@Configuration(proxyBeanMethods = false)
public class MyRoutingConfiguration {
private static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON);
@Bean
public RouterFunction<ServerResponse> routerFunction(MyUserHandler userHandler) {
return route()
.GET("/{user}", ACCEPT_JSON, userHandler::getUser)
.GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers)
.DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser)
.build();
}
}
@Configuration(proxyBeanMethods = false)
class MyRoutingConfiguration {
@Bean
fun routerFunction(userHandler: MyUserHandler): RouterFunction<ServerResponse> {
return RouterFunctions.route()
.GET("/{user}", ACCEPT_JSON, userHandler::getUser)
.GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers)
.DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser)
.build()
}
companion object {
private val ACCEPT_JSON = accept(MediaType.APPLICATION_JSON)
}
}
@Component
public class MyUserHandler {
public ServerResponse getUser(ServerRequest request) {
...
return ServerResponse.ok().build();
}
public ServerResponse getUserCustomers(ServerRequest request) {
...
return ServerResponse.ok().build();
}
public ServerResponse deleteUser(ServerRequest request) {
...
return ServerResponse.ok().build();
}
}
@Component
class MyUserHandler {
fun getUser(request: ServerRequest?): ServerResponse {
return ServerResponse.ok().build()
}
fun getUserCustomers(request: ServerRequest?): ServerResponse {
return ServerResponse.ok().build()
}
fun deleteUser(request: ServerRequest?): ServerResponse {
return ServerResponse.ok().build()
}
}
Spring MVC はコア Spring Framework の一部であり、詳細情報はリファレンスドキュメントで入手できます。spring.io/guides で入手可能な Spring MVC をカバーするガイドもいくつかあります。
RouterFunction Bean をいくつでも定義して、ルーターの定義をモジュール化できます。優先順位を適用する必要がある場合は、Bean をオーダーできます。 |
1.1.1. Spring MVC 自動構成
Spring Boot は、ほとんどのアプリケーションでうまく機能する Spring MVC の自動構成を提供します。
自動構成により、Spring のデフォルトに加えて次の機能が追加されます。
ContentNegotiatingViewResolver
およびBeanNameViewResolver
Bean の包含。WebJars のサポートを含む静的リソースの提供のサポート(このドキュメントで後述)。
Converter
、GenericConverter
、Formatter
Bean の自動登録。HttpMessageConverters
のサポート(このドキュメントで後述)。MessageCodesResolver
の自動登録(このドキュメントで後述)。静的
index.html
サポート。ConfigurableWebBindingInitializer
Bean の自動使用(このドキュメントで後述)。
これらの Spring Boot MVC のカスタマイズを保持し、さらに MVC のカスタマイズ(インターセプター、フォーマッター、View Controller、およびその他の機能)を作成する場合は、@EnableWebMvc
なしで型 WebMvcConfigurer
の独自の @Configuration
クラスを追加できます。
RequestMappingHandlerMapping
、RequestMappingHandlerAdapter
、ExceptionHandlerExceptionResolver
のカスタムインスタンスを提供し、それでも Spring Boot MVC のカスタマイズを維持したい場合は、型 WebMvcRegistrations
の Bean を宣言し、それを使用してこれらのコンポーネントのカスタムインスタンスを提供できます。
Spring MVC を完全に制御したい場合は、@EnableWebMvc
でアノテーションを付けた独自の @Configuration
を追加するか、@EnableWebMvc
の Javadoc に従って、独自の @Configuration
アノテーション付き DelegatingWebMvcConfiguration
を追加できます。
Spring MVC は、 Spring MVC が使用する |
1.1.2. HttpMessageConverters
Spring MVC は、HttpMessageConverter
インターフェースを使用して HTTP リクエストとレスポンスを変換します。適切なデフォルトは、すぐに含まれています。例: オブジェクトは、JSON (Jackson ライブラリを使用) または XML (使用可能な場合は Jackson XML 拡張を使用するか、Jackson XML 拡張が使用できない場合は JAXB を使用) に自動的に変換できます。デフォルトでは、文字列は UTF-8
でエンコードされます。
コンバーターを追加またはカスタマイズする必要がある場合は、次のように、Spring Boot の HttpMessageConverters
クラスを使用できます。
@Configuration(proxyBeanMethods = false)
public class MyHttpMessageConvertersConfiguration {
@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = new AdditionalHttpMessageConverter();
HttpMessageConverter<?> another = new AnotherHttpMessageConverter();
return new HttpMessageConverters(additional, another);
}
}
@Configuration(proxyBeanMethods = false)
class MyHttpMessageConvertersConfiguration {
@Bean
fun customConverters(): HttpMessageConverters {
val additional: HttpMessageConverter<*> = AdditionalHttpMessageConverter()
val another: HttpMessageConverter<*> = AnotherHttpMessageConverter()
return HttpMessageConverters(additional, another)
}
}
コンテキストに存在する HttpMessageConverter
Bean は、コンバーターのリストに追加されます。同じ方法でデフォルトのコンバーターをオーバーライドすることもできます。
1.1.3. MessageCodesResolver
Spring MVC には、バインディングエラーからエラーメッセージをレンダリングするためのエラーコードを生成するための戦略があります: MessageCodesResolver
。spring.mvc.message-codes-resolver-format
プロパティ PREFIX_ERROR_CODE
または POSTFIX_ERROR_CODE
を設定すると、Spring Boot によって作成されます ( DefaultMessageCodesResolver.Format
(Javadoc) の列挙を参照)。
1.1.4. 静的コンテンツ
デフォルトでは、Spring Boot は、クラスパス内の /static
(または /public
または /resources
または /META-INF/resources
) というディレクトリから、または ServletContext
のルートから静的コンテンツを提供します。Spring MVC の ResourceHttpRequestHandler
を使用しているため、独自の WebMvcConfigurer
を追加して addResourceHandlers
メソッドをオーバーライドすることで、その動作を変更できます。
スタンドアロン Web アプリケーションでは、コンテナーのデフォルトサーブレットは有効になっていません。server.servlet.register-default-servlet
プロパティを使用して有効にすることができます。
デフォルトのサーブレットはフォールバックとして機能し、Spring が処理しないと決定した場合に ServletContext
のルートからコンテンツを提供します。Spring は常に DispatcherServlet
を介してリクエストを処理できるため、ほとんどの場合、これは発生しません (デフォルトの MVC 構成を変更しない限り)。
デフォルトでは、リソースは /**
にマップされますが、spring.mvc.static-path-pattern
プロパティでそれを調整できます。たとえば、すべてのリソースを /resources/**
に再配置するには、次のようにします。
spring.mvc.static-path-pattern=/resources/**
spring:
mvc:
static-path-pattern: "/resources/**"
spring.web.resources.static-locations
プロパティを使用して静的リソースの場所をカスタマイズすることもできます(デフォルト値をディレクトリの場所のリストに置き換えます)。ルートサーブレットコンテキストパス "/"
も、場所として自動的に追加されます。
前述の「標準」の静的リソースの場所に加えて、Webjars コンテンツ (英語) には特別なケースが作成されます。デフォルトでは、パスが /webjars/**
のリソースは、Webjars 形式でパッケージ化されている場合、jar ファイルから提供されます。パスは spring.mvc.webjars-path-pattern
プロパティでカスタマイズできます。
アプリケーションが jar としてパッケージ化されている場合は、src/main/webapp ディレクトリを使用しないでください。このディレクトリは一般的な標準ですが、war パッケージでのみ機能し、jar を生成する場合、ほとんどのビルドツールでは暗黙のうちに無視されます。 |
Spring Boot は、Spring MVC が提供する高度なリソース処理機能もサポートし、静的リソースのキャッシュ無効化や Webjar のバージョンに依存しない URL の使用などのユースケースを可能にします。
Webjar のバージョンに依存しない URL を使用するには、webjars-locator-core
依存関係を追加します。次に、Webjar を宣言します。jQuery を例にとると、"/webjars/jquery/jquery.min.js"
を追加すると "/webjars/jquery/x.y.z/jquery.min.js"
になります。ここで、x.y.z
は Webjar のバージョンです。
JBoss を使用する場合、webjars-locator-core ではなく webjars-locator-jboss-vfs 依存関係を宣言する必要があります。それ以外の場合、すべての Webjar は 404 として解決されます。 |
キャッシュ無効化を使用するには、次の構成ですべての静的リソースのキャッシュ無効化ソリューションを構成し、URL に <link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>
などのコンテンツハッシュを効果的に追加します。
spring.web.resources.chain.strategy.content.enabled=true
spring.web.resources.chain.strategy.content.paths=/**
spring:
web:
resources:
chain:
strategy:
content:
enabled: true
paths: "/**"
リソースへのリンクは、Thymeleaf および FreeMarker 用に自動構成された ResourceUrlEncodingFilter のおかげで、実行時にテンプレートで書き換えられます。JSP を使用する場合は、このフィルターを手動で宣言する必要があります。現在、他のテンプレートエンジンは自動的にサポートされていませんが、カスタムテンプレートマクロ / ヘルパーおよび ResourceUrlProvider (Javadoc) を使用することができます。 |
JavaScript モジュールローダーなどを使用してリソースを動的にロードする場合、ファイルの名前を変更することはできません。そのため、他の戦略もサポートされており、組み合わせることができます。"fixed" 戦略では、次の例に示すように、ファイル名を変更せずに URL に静的バージョン文字列を追加します。
spring.web.resources.chain.strategy.content.enabled=true
spring.web.resources.chain.strategy.content.paths=/**
spring.web.resources.chain.strategy.fixed.enabled=true
spring.web.resources.chain.strategy.fixed.paths=/js/lib/
spring.web.resources.chain.strategy.fixed.version=v12
spring:
web:
resources:
chain:
strategy:
content:
enabled: true
paths: "/**"
fixed:
enabled: true
paths: "/js/lib/"
version: "v12"
この構成では、"/js/lib/"
にある JavaScript モジュールは固定バージョン管理戦略("/v12/js/lib/mymodule.js"
)を使用しますが、他のリソースはコンテンツコンテンツ(<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>
)を引き続き使用します。
サポートされるオプションの詳細については、WebProperties.Resources
[GitHub] (英語) を参照してください。
この機能は、専用のブログ投稿 (英語) および Spring Framework のリファレンスドキュメントで詳細に説明されています。 |
1.1.5. ウェルカムページ
Spring Boot は、静的なウェルカムページとテンプレート化されたウェルカムページの両方をサポートしています。最初に、構成された静的コンテンツの場所で index.html
ファイルを探します。見つからない場合は、index
テンプレートを探します。どちらかが見つかった場合、アプリケーションのウェルカムページとして自動的に使用されます。
1.1.6. カスタムファビコン
他の静的リソースと同様に、Spring Boot は構成された静的コンテンツの場所で favicon.ico
をチェックします。そのようなファイルが存在する場合、アプリケーションのファビコンとして自動的に使用されます。
1.1.7. パスマッチングとコンテンツネゴシエーション
Spring MVC は、リクエストパスを調べて、アプリケーションで定義されたマッピング (たとえば、コントローラーメソッドの @GetMapping
アノテーション) と照合することにより、受信 HTTP リクエストをハンドラーにマッピングできます。
Spring Boot は、デフォルトでサフィックスパターンマッチングを無効にすることを選択します。これは、"GET /projects/spring-boot.json"
のようなリクエストが @GetMapping("/projects/spring-boot")
マッピングにマッチングされないことを意味します。これは、Spring MVC アプリケーションのベストプラクティスと見なされています。この機能は、これまで、適切な "Accept" リクエストヘッダーを送信しなかった HTTP クライアントで主に役立ちました。正しいコンテンツ型をクライアントに送信する必要がありました。今日では、コンテントネゴシエーションの信頼性ははるかに高くなっています。
適切な "Accept" リクエストヘッダーを一貫して送信しない HTTP クライアントを処理する方法は他にもあります。サフィックスマッチングを使用する代わりに、クエリパラメーターを使用して、"GET /projects/spring-boot?format=json"
などのリクエストが @GetMapping("/projects/spring-boot")
にマップされるようにすることができます。
spring.mvc.contentnegotiation.favor-parameter=true
spring:
mvc:
contentnegotiation:
favor-parameter: true
または、別のパラメーター名を使用する場合:
spring.mvc.contentnegotiation.favor-parameter=true
spring.mvc.contentnegotiation.parameter-name=myparam
spring:
mvc:
contentnegotiation:
favor-parameter: true
parameter-name: "myparam"
ほとんどの標準メディア型はすぐにサポートされますが、新しいメディア型を定義することもできます。
spring.mvc.contentnegotiation.media-types.markdown=text/markdown
spring:
mvc:
contentnegotiation:
media-types:
markdown: "text/markdown"
Spring Framework 5.3 の時点で、Spring MVC は、リクエストパスをコントローラーハンドラーに一致させるためのいくつかの実装戦略をサポートしています。以前は AntPathMatcher
戦略のみをサポートしていましたが、現在は PathPatternParser
も提供しています。Spring Boot は、新しい戦略を選択して選択するための構成プロパティを提供するようになりました。
spring.mvc.pathmatch.matching-strategy=path-pattern-parser
spring:
mvc:
pathmatch:
matching-strategy: "path-pattern-parser"
この新しい実装を検討する必要がある理由の詳細については、専用のブログ投稿 (英語) を参照してください。
PathPatternParser は最適化された実装ですが、一部のパスパターンバリアントの使用を制限します。サフィックスパターンマッチングまたは DispatcherServlet とサーブレットプレフィックス (spring.mvc.servlet.path ) のマッピングとは互換性がありません。 |
デフォルトでは、リクエストのハンドラーが見つからない場合、Spring MVC は 404 未検出 エラーレスポンスを送信します。代わりに NoHandlerFoundException
をスローするには、configprop:spring.mvc.throw-exception-if-no-handler-found を true
に設定します。デフォルトでは、静的コンテンツの提供は /**
にマップされるため、すべてのリクエストにハンドラーが提供されることに注意してください。NoHandlerFoundException
をスローするには、spring.mvc.static-path-pattern
を /resources/**
などのより具体的な値に設定するか、spring.web.resources.add-mappings
を false
に設定して、静的コンテンツの提供を完全に無効にする必要があります。
1.1.8. ConfigurableWebBindingInitializer
Spring MVC は WebBindingInitializer
を使用して、特定のリクエストに対して WebDataBinder
を初期化します。独自の ConfigurableWebBindingInitializer
@Bean
を作成すると、Spring Boot はそれを使用するように Spring MVC を自動的に構成します。
1.1.9. テンプレートエンジン
REST Web サービスだけでなく、Spring MVC を使用して動的 HTML コンテンツを提供することもできます。Spring MVC は、Thymeleaf、FreeMarker、JSP など、さまざまなテンプレートテクノロジをサポートしています。また、他の多くのテンプレートエンジンには、独自の Spring MVC 統合が含まれています。
Spring Boot には、次のテンプレートエンジンの自動構成サポートが含まれています。
可能であれば、JSP を避ける必要があります。組み込みサーブレットコンテナーで使用する場合、いくつかの既知の制限があります。 |
これらのテンプレートエンジンのいずれかを既定の構成で使用すると、src/main/resources/templates
からテンプレートが自動的に選択されます。
1.1.10. エラー処理
デフォルトでは、Spring Boot はすべてのエラーを適切な方法で処理する /error
マッピングを提供し、サーブレットコンテナーに「グローバル」エラーページとして登録されます。マシンクライアントの場合、エラー、HTTP ステータス、例外メッセージの詳細を含む JSON レスポンスを生成します。ブラウザークライアントの場合、同じデータを HTML 形式でレンダリングする「ホワイトラベル」エラービューがあります(カスタマイズするには、error
に解決される View
を追加します)。
デフォルトのエラー処理動作をカスタマイズする場合に設定できる server.error
プロパティがいくつかあります。付録の “サーバープロパティ” セクションを参照してください。
デフォルトの動作を完全に置き換えるには、ErrorController
を実装してその型の Bean 定義を登録するか、型 ErrorAttributes
の Bean を追加して既存のメカニズムを使用しますが、内容を置き換えます。
BasicErrorController は、カスタム ErrorController の基本クラスとして使用できます。これは、新しいコンテンツ型のハンドラーを追加する場合に特に便利です(デフォルトでは、text/html を具体的に処理し、他のすべてにフォールバックを提供します)。これを行うには、BasicErrorController を継承し、produces 属性を持つ @RequestMapping を使用して public メソッドを追加し、新しい型の Bean を作成します。 |
Spring Framework 6.0 の時点で、RFC 7807 問題の詳細がサポートされています。Spring MVC は、次のような application/problem+json
メディア型でカスタムエラーメッセージを生成できます。
{
"type": "https://example.org/problems/unknown-project",
"title": "Unknown project",
"status": 404,
"detail": "No project found for id 'spring-unknown'",
"instance": "/projects/spring-unknown"
}
このサポートは、spring.mvc.problemdetails.enabled
を true
に設定することで有効にできます。
次の例に示すように、@ControllerAdvice
アノテーションが付けられたクラスを定義して、特定のコントローラーまたは例外型、あるいはその両方を返すように JSON ドキュメントをカスタマイズすることもできます。
@ControllerAdvice(basePackageClasses = SomeController.class)
public class MyControllerAdvice extends ResponseEntityExceptionHandler {
@ResponseBody
@ExceptionHandler(MyException.class)
public ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
HttpStatus status = getStatus(request);
return new ResponseEntity<>(new MyErrorBody(status.value(), ex.getMessage()), status);
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer code = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
HttpStatus status = HttpStatus.resolve(code);
return (status != null) ? status : HttpStatus.INTERNAL_SERVER_ERROR;
}
}
@ControllerAdvice(basePackageClasses = [SomeController::class])
class MyControllerAdvice : ResponseEntityExceptionHandler() {
@ResponseBody
@ExceptionHandler(MyException::class)
fun handleControllerException(request: HttpServletRequest, ex: Throwable): ResponseEntity<*> {
val status = getStatus(request)
return ResponseEntity(MyErrorBody(status.value(), ex.message), status)
}
private fun getStatus(request: HttpServletRequest): HttpStatus {
val code = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE) as Int
val status = HttpStatus.resolve(code)
return status ?: HttpStatus.INTERNAL_SERVER_ERROR
}
}
上記の例では、MyException
が SomeController
と同じパッケージで定義されたコントローラーによってスローされた場合、ErrorAttributes
表現の代わりに MyErrorBody
POJO の JSON 表現が使用されます。
場合によっては、コントローラーレベルで処理されたエラーは、メトリクスインフラストラクチャによって記録されません。アプリケーションは、処理された例外をリクエスト属性として設定することにより、そのような例外がリクエストメトリクスとともに記録されることを保証できます。
@Controller
public class MyController {
@ExceptionHandler(CustomException.class)
String handleCustomException(HttpServletRequest request, CustomException ex) {
request.setAttribute(ErrorAttributes.ERROR_ATTRIBUTE, ex);
return "errorView";
}
}
@Controller
class MyController {
@ExceptionHandler(CustomException::class)
fun handleCustomException(request: HttpServletRequest, ex: CustomException?): String {
request.setAttribute(ErrorAttributes.ERROR_ATTRIBUTE, ex)
return "errorView"
}
}
カスタムエラーページ
特定のステータスコードのカスタム 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.ftlh +- <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
if (status == HttpStatus.INSUFFICIENT_STORAGE) {
// We could add custom model values here
new ModelAndView("myview");
}
return null;
}
}
class MyErrorViewResolver : ErrorViewResolver {
override fun resolveErrorView(request: HttpServletRequest, status: HttpStatus,
model: Map<String, Any>): ModelAndView? {
// Use the request or status to optionally return a ModelAndView
if (status == HttpStatus.INSUFFICIENT_STORAGE) {
// We could add custom model values here
return ModelAndView("myview")
}
return null
}
}
@ExceptionHandler
メソッドや @ControllerAdvice
などの通常の Spring MVC 機能も使用できます。その後、ErrorController
は未処理の例外を取得します。
Spring MVC 以外のエラーページのマッピング
Spring MVC を使用しないアプリケーションの場合、ErrorPageRegistrar
インターフェースを使用して ErrorPages
を直接登録できます。この抽象化は、基盤となる埋め込みサーブレットコンテナーと直接連携し、Spring MVC DispatcherServlet
がなくても機能します。
@Configuration(proxyBeanMethods = false)
public class MyErrorPagesConfiguration {
@Bean
public ErrorPageRegistrar errorPageRegistrar() {
return this::registerErrorPages;
}
private void registerErrorPages(ErrorPageRegistry registry) {
registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
}
}
@Configuration(proxyBeanMethods = false)
class MyErrorPagesConfiguration {
@Bean
fun errorPageRegistrar(): ErrorPageRegistrar {
return ErrorPageRegistrar { registry: ErrorPageRegistry -> registerErrorPages(registry) }
}
private fun registerErrorPages(registry: ErrorPageRegistry) {
registry.addErrorPages(ErrorPage(HttpStatus.BAD_REQUEST, "/400"))
}
}
Filter によって処理されるパスで ErrorPage を登録する場合(Jersey や Wicket などの一部の非 SpringWeb フレームワークで一般的)、次に示すように、Filter を ERROR ディスパッチャーとして明示的に登録する必要があります。次の例: |
@Configuration(proxyBeanMethods = false)
public class MyFilterConfiguration {
@Bean
public FilterRegistrationBean<MyFilter> myFilter() {
FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(new MyFilter());
// ...
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
}
}
@Configuration(proxyBeanMethods = false)
class MyFilterConfiguration {
@Bean
fun myFilter(): FilterRegistrationBean<MyFilter> {
val registration = FilterRegistrationBean(MyFilter())
// ...
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType::class.java))
return registration
}
}
デフォルトの FilterRegistrationBean
には ERROR
ディスパッチャー型が含まれていないことに注意してください。
WAR デプロイでのエラー処理
サーブレットコンテナーにデプロイされると、Spring Boot はエラーページフィルターを使用して、エラーステータスのあるリクエストを適切なエラーページに転送します。サーブレット仕様ではエラーページを登録するための API が提供されていないため、これが必要です。war ファイルをデプロイするコンテナーとアプリケーションが使用するテクノロジーによっては、追加の構成が必要になる場合があります。
エラーページフィルターは、レスポンスがまだコミットされていない場合にのみ、リクエストを正しいエラーページに転送できます。デフォルトでは、WebSphere アプリケーションサーバー 8.0 以降は、サーブレットのサービスメソッドが正常に完了すると、レスポンスをコミットします。com.ibm.ws.webcontainer.invokeFlushAfterService
を false
に設定して、この動作を無効にする必要があります。
1.1.11. CORS サポート
クロスオリジンリソース共有 [Mozilla] (CORS)は、ほとんどのブラウザー (英語) で実装されている W3C 仕様 (英語) であり、IFRAME や JSONP などの安全性の低いアプローチを使用する代わりに、どのようなクロスドメインリクエストを認可するかを柔軟に指定できます。
バージョン 4.2 以降、Spring MVC は CORS をサポートします。Spring Boot アプリケーションで @CrossOrigin
(Javadoc) アノテーションを使用してコントローラーメソッド CORS 構成を使用する場合、特定の構成は必要ありません。グローバル CORS 設定は、次の例に示すように、カスタマイズされた addCorsMappings(CorsRegistry)
メソッドで WebMvcConfigurer
Bean を登録することで定義できます。
@Configuration(proxyBeanMethods = false)
public class MyCorsConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**");
}
};
}
}
@Configuration(proxyBeanMethods = false)
class MyCorsConfiguration {
@Bean
fun corsConfigurer(): WebMvcConfigurer {
return object : WebMvcConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
registry.addMapping("/api/**")
}
}
}
}
1.2. JAX-RS および Jersey
REST エンドポイントに JAX-RS プログラミングモデルを使用する場合は、Spring MVC の代わりに使用可能な実装の 1 つを使用できます。Jersey (英語) と Apache CXF (英語) は、すぐに使用できます。CXF では、アプリケーションコンテキストで Servlet
または Filter
を @Bean
として登録する必要があります。Jersey にはネイティブ Spring サポートがいくつかあるため、スターターとともに Spring Boot での自動構成サポートも提供します。
Jersey を開始するには、spring-boot-starter-jersey
を依存関係として含めてから、次の例に示すように、すべてのエンドポイントを登録する型 ResourceConfig
の @Bean
が 1 つ必要です。
@Component
public class MyJerseyConfig extends ResourceConfig {
public MyJerseyConfig() {
register(MyEndpoint.class);
}
}
Jersey の実行可能アーカイブのスキャンのサポートはかなり制限されています。例: 実行可能な war ファイルを実行している場合、完全に実行可能な jar ファイルまたは WEB-INF/classes で見つかったパッケージ内のエンドポイントをスキャンできません。この制限を回避するには、packages メソッドを使用せず、前の例に示すように、register メソッドを使用してエンドポイントを個別に登録する必要があります。 |
より高度なカスタマイズのために、ResourceConfigCustomizer
を実装する Bean を任意の数だけ登録することもできます。
登録されたすべてのエンドポイントは、次の例に示すように、HTTP リソースアノテーション(@GET
など)を含む @Components
である必要があります。
@Component
@Path("/hello")
public class MyEndpoint {
@GET
public String message() {
return "Hello";
}
}
Endpoint
は Spring @Component
であるため、そのライフサイクルは Spring によって管理され、@Autowired
アノテーションを使用して依存関係を注入し、@Value
アノテーションを使用して外部構成を注入できます。デフォルトでは、Jersey サーブレットが登録され、/*
にマップされます。@ApplicationPath
を ResourceConfig
に追加することにより、マッピングを変更できます。
デフォルトでは、Jersey は、jerseyServletRegistration
という名前の ServletRegistrationBean
型の @Bean
のサーブレットとして設定されます。デフォルトでは、サーブレットは遅延初期化されますが、spring.jersey.servlet.load-on-startup
を設定することでその動作をカスタマイズできます。同じ名前で独自の Bean を作成することにより、その Bean を無効化またはオーバーライドできます。spring.jersey.type=filter
を設定することにより、サーブレットの代わりにフィルターを使用することもできます(この場合、置換またはオーバーライドする @Bean
は jerseyFilterRegistration
です)。フィルターには @Order
があり、spring.jersey.filter.order
で設定できます。Jersey をフィルターとして使用する場合、Jersey によってインターセプトされないリクエストを処理するサーブレットが存在する必要があります。アプリケーションにそのようなサーブレットが含まれていない場合は、server.servlet.register-default-servlet
を true
に設定して、デフォルトのサーブレットを有効にすることをお勧めします。spring.jersey.init.*
を使用してプロパティのマップを指定することにより、サーブレットとフィルターの両方の登録に init パラメーターを指定できます。
1.3. 組み込みサーブレットコンテナーのサポート
サーブレットアプリケーションの場合、Spring Boot には、組み込み Tomcat [Apache] (英語) 、Jetty (英語) 、Undertow [GitHub] (英語) サーバーのサポートが含まれています。ほとんどの開発者は、適切な「スターター」を使用して、完全に構成されたインスタンスを取得します。デフォルトでは、組み込みサーバーはポート 8080
で HTTP リクエストをリッスンします。
1.3.1. サーブレット、フィルター、リスナー
組み込みサーブレットコンテナーを使用する場合、Spring Bean を使用するか、サーブレットコンポーネントをスキャンすることにより、サーブレット、フィルター、すべてのリスナー(HttpSessionListener
など)をサーブレット仕様から登録できます。
サーブレット、フィルター、リスナーを Spring Bean として登録する
Spring Bean である Servlet
、Filter
、サーブレット *Listener
インスタンスはすべて、組み込みコンテナーに登録されます。これは、構成中に application.properties
から値を参照する場合に特に便利です。
デフォルトでは、コンテキストに含まれるサーブレットが 1 つのみの場合、/
にマッピングされます。複数のサーブレット Bean の場合、Bean 名がパスプレフィックスとして使用されます。フィルターは /*
にマップします。
規則ベースのマッピングに十分な柔軟性がない場合は、ServletRegistrationBean
、FilterRegistrationBean
、ServletListenerRegistrationBean
クラスを使用して完全に制御できます。
通常、フィルター Bean は順序付けされていないままにしておくのが安全です。特定の順序が必要な場合は、Filter
に @Order
のアノテーションを付けるか、Ordered
を実装するようにする必要があります。Bean メソッドに @Order
アノテーションを付けて、Filter
の順序を構成することはできません。Filter
クラスを変更して @Order
を追加したり、Ordered
を実装したりできない場合は、Filter
の FilterRegistrationBean
を定義し、setOrder(int)
メソッドを使用して登録 Bean の順序を設定する必要があります。Ordered.HIGHEST_PRECEDENCE
でリクエスト本文を読み取るフィルターを構成することは避けてください。これは、アプリケーションの文字エンコード構成に反する可能性があるためです。サーブレットフィルターがリクエストをラップする場合は、OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER
以下の順序で設定する必要があります。
アプリケーション内のすべての Filter の順序を確認するには、web ロギンググループ(logging.level.web=debug )のデバッグレベルロギングを有効にします。登録されたフィルターの詳細(順序や URL パターンなど)は、起動時にログに記録されます。 |
Filter Bean はアプリケーションのライフサイクルの非常に早い段階で初期化されるため、登録するときは注意してください。他の Bean と相互作用する Filter を登録する必要がある場合は、代わりに DelegatingFilterProxyRegistrationBean (Javadoc) の使用を検討してください。 |
1.3.2. サーブレットコンテキストの初期化
組み込みサーブレットコンテナーは、jakarta.servlet.ServletContainerInitializer
インターフェースまたは Spring の org.springframework.web.WebApplicationInitializer
インターフェースを直接実行しません。これは、war 内で実行するように設計されたサードパーティライブラリが Spring Boot アプリケーションを破壊するリスクを減らすことを目的とした意図的な設計上の決定です。
Spring Boot アプリケーションでサーブレットコンテキストの初期化を実行する必要がある場合は、org.springframework.boot.web.servlet.ServletContextInitializer
インターフェースを実装する Bean を登録する必要があります。単一の onStartup
メソッドは ServletContext
へのアクセスを提供し、必要に応じて、既存の WebApplicationInitializer
へのアダプターとして簡単に使用できます。
1.3.3. ServletWebServerApplicationContext
内部的には、Spring Boot は組み込みサーブレットコンテナーのサポートに異なる型の ApplicationContext
を使用します。ServletWebServerApplicationContext
は、単一の ServletWebServerFactory
Bean を検索することによってそれ自体をブートストラップする特殊な型の WebApplicationContext
です。通常、TomcatServletWebServerFactory
、JettyServletWebServerFactory
、UndertowServletWebServerFactory
は自動構成されています。
通常、これらの実装クラスを意識する必要はありません。ほとんどのアプリケーションは自動構成され、適切な ApplicationContext および ServletWebServerFactory がユーザーに代わって作成されます。 |
組み込みコンテナーのセットアップでは、ServletContext
は、アプリケーションコンテキストの初期化中に発生するサーバーの起動の一部として設定されます。このため、ApplicationContext
の Bean は、ServletContext
で確実に初期化できません。これを回避する 1 つの方法は、Bean の依存関係として ApplicationContext
を挿入し、必要な場合にのみ ServletContext
にアクセスすることです。もう 1 つの方法は、サーバーの起動後にコールバックを使用することです。これは、次のように ApplicationStartedEvent
をリッスンする ApplicationListener
を使用して実行できます。
public class MyDemoBean implements ApplicationListener<ApplicationStartedEvent> {
private ServletContext servletContext;
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
ApplicationContext applicationContext = event.getApplicationContext();
this.servletContext = ((WebApplicationContext) applicationContext).getServletContext();
}
}
1.3.4. 埋め込みサーブレットコンテナーのカスタマイズ
一般的なサーブレットコンテナー設定は、Spring Environment
プロパティを使用して構成できます。通常、application.properties
または application.yaml
ファイルでプロパティを定義します。
一般的なサーバー設定は次のとおりです。
ネットワーク設定: 受信 HTTP リクエストのリスンポート(
server.port
)、server.address
にバインドするインターフェースアドレスなど。セッション設定: セッションが永続的か(
server.servlet.session.persistent
)、セッションタイムアウト(server.servlet.session.timeout
)、セッションデータの場所(server.servlet.session.store-dir
)、セッション Cookie 構成(server.servlet.session.cookie.*
)。エラー管理: エラーページ(
server.error.path
)などの場所。
Spring Boot は、可能な限り共通の設定を公開しようとしますが、常に可能とは限りません。これらの場合、専用の名前空間はサーバー固有のカスタマイズを提供します(server.tomcat
および server.undertow
を参照)。たとえば、アクセスログは、組み込みサーブレットコンテナーの特定の機能を使用して設定できます。
完全なリストについては、ServerProperties [GitHub] (英語) クラスを参照してください。 |
SameSite クッキー
SameSite
cookie 属性は、クロスサイトリクエストで Cookie を送信するかどうか、および送信する方法を制御するために Web ブラウザーで使用できます。この属性は、属性が欠落しているときに使用されるデフォルト値を変更し始めた最新の Web ブラウザーに特に関係があります。
セッション Cookie の SameSite
属性を変更する場合は、server.servlet.session.cookie.same-site
プロパティを使用できます。このプロパティは、自動構成された Tomcat、Jetty、Undertow サーバーでサポートされています。また、Spring Session サーブレットベースの SessionRepository
Bean を構成するためにも使用されます。
例: セッション Cookie に None
の SameSite
属性を持たせたい場合は、application.properties
または application.yaml
ファイルに以下を追加できます。
server.servlet.session.cookie.same-site=none
server:
servlet:
session:
cookie:
same-site: "none"
HttpServletResponse
に追加された他の Cookie の SameSite
属性を変更する場合は、CookieSameSiteSupplier
を使用できます。CookieSameSiteSupplier
には Cookie
が渡され、SameSite
値または null
を返す場合があります。
特定の Cookie をすばやく照合するために使用できる便利なファクトリおよびフィルターメソッドがいくつかあります。例: 次の Bean を追加すると、正規表現 myapp.*
と一致する名前のすべての Cookie に Lax
の SameSite
が自動的に適用されます。
@Configuration(proxyBeanMethods = false)
public class MySameSiteConfiguration {
@Bean
public CookieSameSiteSupplier applicationCookieSameSiteSupplier() {
return CookieSameSiteSupplier.ofLax().whenHasNameMatching("myapp.*");
}
}
@Configuration(proxyBeanMethods = false)
class MySameSiteConfiguration {
@Bean
fun applicationCookieSameSiteSupplier(): CookieSameSiteSupplier {
return CookieSameSiteSupplier.ofLax().whenHasNameMatching("myapp.*")
}
}
プログラムによるカスタマイズ
組み込みサーブレットコンテナーをプログラムで設定する必要がある場合は、WebServerFactoryCustomizer
インターフェースを実装する Spring Bean を登録できます。WebServerFactoryCustomizer
は、多数のカスタマイズ setter メソッドを含む ConfigurableServletWebServerFactory
へのアクセスを提供します。次の例は、プログラムでポートを設定する方法を示しています。
@Component
public class MyWebServerFactoryCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
}
}
@Component
class MyWebServerFactoryCustomizer : WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
override fun customize(server: ConfigurableServletWebServerFactory) {
server.setPort(9000)
}
}
TomcatServletWebServerFactory
、JettyServletWebServerFactory
、UndertowServletWebServerFactory
は ConfigurableServletWebServerFactory
の専用バリアントであり、Tomcat、Jetty、Undertow 用にそれぞれ追加のカスタマイズ setter メソッドがあります。次の例は、Tomcat 固有の構成オプションへのアクセスを提供する TomcatServletWebServerFactory
をカスタマイズする方法を示しています。
@Component
public class MyTomcatWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory server) {
server.addConnectorCustomizers((connector) -> connector.setAsyncTimeout(Duration.ofSeconds(20).toMillis()));
}
}
@Component
class MyTomcatWebServerFactoryCustomizer : WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
override fun customize(server: TomcatServletWebServerFactory) {
server.addConnectorCustomizers({ connector -> connector.asyncTimeout = Duration.ofSeconds(20).toMillis() })
}
}
ConfigurableServletWebServerFactory を直接カスタマイズする
ServletWebServerFactory
から拡張する必要があるより高度なユースケースの場合は、そのような型の Bean を自分で公開できます。
Setter は、多くの構成オプション用に提供されています。よりエキゾチックな何かをする必要がある場合、いくつかの protected メソッド「フック」も提供されます。詳細については、ソースコードのドキュメント (Javadoc) を参照してください。
自動構成されたカスタマイザーは引き続きカスタムファクトリに適用されるため、そのオプションは慎重に使用してください。 |
1.3.5. JSP の制限
組み込みサーブレットコンテナーを使用する(実行可能アーカイブとしてパッケージ化されている)Spring Boot アプリケーションを実行する場合、JSP サポートにはいくつかの制限があります。
Jetty と Tomcat では、war パッケージを使用すれば動作するはずです。実行可能な war は、
java -jar
で起動すると動作し、任意の標準コンテナーに配備することもできます。実行可能 jar を使用する場合、JSP はサポートされません。Undertow は JSP をサポートしていません。
カスタム
error.jsp
ページを作成しても、エラー処理のデフォルトビューは上書きされません。代わりにカスタムエラーページを使用する必要があります。
2. リアクティブ Web アプリケーション
Spring Boot は、Spring Webflux の自動構成を提供することにより、リアクティブ Web アプリケーションの開発を簡素化します。
2.1. 「Spring WebFlux フレームワーク」
Spring WebFlux は、Spring Framework 5.0 で導入された新しいリアクティブ Web フレームワークです。Spring MVC とは異なり、サーブレット API を必要とせず、完全に非同期でノンブロッキングであり、Reactor プロジェクト (英語) を通じて Reactive Streams (英語) 仕様を実装します。
Spring WebFlux には、関数型とアノテーション型の 2 つのフレーバーがあります。次の例に示すように、アノテーションベースのものは Spring MVC モデルに非常に近いものです。
@RestController
@RequestMapping("/users")
public class MyRestController {
private final UserRepository userRepository;
private final CustomerRepository customerRepository;
public MyRestController(UserRepository userRepository, CustomerRepository customerRepository) {
this.userRepository = userRepository;
this.customerRepository = customerRepository;
}
@GetMapping("/{userId}")
public Mono<User> getUser(@PathVariable Long userId) {
return this.userRepository.findById(userId);
}
@GetMapping("/{userId}/customers")
public Flux<Customer> getUserCustomers(@PathVariable Long userId) {
return this.userRepository.findById(userId).flatMapMany(this.customerRepository::findByUser);
}
@DeleteMapping("/{userId}")
public Mono<Void> deleteUser(@PathVariable Long userId) {
return this.userRepository.deleteById(userId);
}
}
@RestController
@RequestMapping("/users")
class MyRestController(private val userRepository: UserRepository, private val customerRepository: CustomerRepository) {
@GetMapping("/{userId}")
fun getUser(@PathVariable userId: Long): Mono<User?> {
return userRepository.findById(userId)
}
@GetMapping("/{userId}/customers")
fun getUserCustomers(@PathVariable userId: Long): Flux<Customer> {
return userRepository.findById(userId).flatMapMany { user: User? ->
customerRepository.findByUser(user)
}
}
@DeleteMapping("/{userId}")
fun deleteUser(@PathVariable userId: Long): Mono<Void> {
return userRepository.deleteById(userId)
}
}
次の例に示すように、関数型バリアントである "WebFlux.fn" は、ルーティング構成をリクエストの実際の処理から分離します。
@Configuration(proxyBeanMethods = false)
public class MyRoutingConfiguration {
private static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON);
@Bean
public RouterFunction<ServerResponse> monoRouterFunction(MyUserHandler userHandler) {
return route()
.GET("/{user}", ACCEPT_JSON, userHandler::getUser)
.GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers)
.DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser)
.build();
}
}
@Configuration(proxyBeanMethods = false)
class MyRoutingConfiguration {
@Bean
fun monoRouterFunction(userHandler: MyUserHandler): RouterFunction<ServerResponse> {
return RouterFunctions.route(
GET("/{user}").and(ACCEPT_JSON), userHandler::getUser).andRoute(
GET("/{user}/customers").and(ACCEPT_JSON), userHandler::getUserCustomers).andRoute(
DELETE("/{user}").and(ACCEPT_JSON), userHandler::deleteUser)
}
companion object {
private val ACCEPT_JSON = accept(MediaType.APPLICATION_JSON)
}
}
@Component
public class MyUserHandler {
public Mono<ServerResponse> getUser(ServerRequest request) {
...
}
public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
...
}
public Mono<ServerResponse> deleteUser(ServerRequest request) {
...
}
}
@Component
class MyUserHandler {
fun getUser(request: ServerRequest?): Mono<ServerResponse> {
return ServerResponse.ok().build()
}
fun getUserCustomers(request: ServerRequest?): Mono<ServerResponse> {
return ServerResponse.ok().build()
}
fun deleteUser(request: ServerRequest?): Mono<ServerResponse> {
return ServerResponse.ok().build()
}
}
WebFlux は Spring Framework の一部であり、詳細な情報はリファレンスドキュメントで入手できます。
RouterFunction Bean をいくつでも定義して、ルーターの定義をモジュール化できます。優先順位を適用する必要がある場合は、Bean をオーダーできます。 |
開始するには、spring-boot-starter-webflux
モジュールをアプリケーションに追加します。
アプリケーションに spring-boot-starter-web モジュールと spring-boot-starter-webflux モジュールの両方を追加すると、WebFlux ではなく Spring Boot が Spring MVC を自動構成します。この動作が選択されたのは、多くの Spring 開発者が spring-boot-starter-webflux を Spring MVC アプリケーションに追加してリアクティブ WebClient を使用するためです。選択したアプリケーションの種類を SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE) に設定することで、引き続き選択を強制できます。 |
2.1.1. Spring WebFlux 自動構成
Spring Boot は、ほとんどのアプリケーションで適切に機能する Spring WebFlux の自動構成を提供します。
自動構成により、Spring のデフォルトに加えて次の機能が追加されます。
Spring Boot WebFlux 機能を保持し、さらに WebFlux の構成を追加する場合、@EnableWebFlux
なしで型 WebFluxConfigurer
の独自の @Configuration
クラスを追加できます。
Spring WebFlux を完全に制御したい場合は、@EnableWebFlux
アノテーションが付けられた独自の @Configuration
を追加できます。
2.1.2. HttpMessageReaders および HttpMessageWriters を使用した HTTP コーデック
Spring WebFlux は、HttpMessageReader
および HttpMessageWriter
インターフェースを使用して、HTTP リクエストおよびレスポンスを変換します。これらは、クラスパスで使用可能なライブラリを調べることにより、実用的なデフォルトを持つように CodecConfigurer
で構成されます。
Spring Boot は、コーデックの専用構成プロパティ spring.codec.*
を提供します。また、CodecCustomizer
インスタンスを使用して、さらにカスタマイズを適用します。例: spring.jackson.*
設定キーは Jackson コーデックに適用されます。
コーデックを追加またはカスタマイズする必要がある場合は、次の例に示すように、カスタム CodecCustomizer
コンポーネントを作成できます。
@Configuration(proxyBeanMethods = false)
public class MyCodecsConfiguration {
@Bean
public CodecCustomizer myCodecCustomizer() {
return (configurer) -> {
configurer.registerDefaults(false);
configurer.customCodecs().register(new ServerSentEventHttpMessageReader());
// ...
};
}
}
class MyCodecsConfiguration {
@Bean
fun myCodecCustomizer(): CodecCustomizer {
return CodecCustomizer { configurer: CodecConfigurer ->
configurer.registerDefaults(false)
configurer.customCodecs().register(ServerSentEventHttpMessageReader())
}
}
}
Boot のカスタム JSON シリアライザーとデシリアライザーを活用することもできます。
2.1.3. 静的コンテンツ
デフォルトでは、Spring Boot は、クラスパス内の /static
(または /public
または /resources
または /META-INF/resources
)と呼ばれるディレクトリから静的コンテンツを提供します。Spring WebFlux の ResourceWebHandler
を使用するため、独自の WebFluxConfigurer
を追加して addResourceHandlers
メソッドをオーバーライドすることにより、その動作を変更できます。
デフォルトでは、リソースは /**
にマップされますが、spring.webflux.static-path-pattern
プロパティを設定することでそれを調整できます。たとえば、すべてのリソースを /resources/**
に再配置するには、次のようにします。
spring.webflux.static-path-pattern=/resources/**
spring:
webflux:
static-path-pattern: "/resources/**"
spring.web.resources.static-locations
を使用して、静的リソースの場所をカスタマイズすることもできます。これにより、デフォルト値がディレクトリの場所のリストに置き換えられます。そうすると、デフォルトのウェルカムページ検出がカスタムの場所に切り替わります。起動時にいずれかの場所に index.html
がある場合、アプリケーションのホームページです。
前述の「標準」の静的リソースの場所に加えて、Webjars コンテンツ (英語) には特別なケースが作成されます。デフォルトでは、パスが /webjars/**
のリソースは、Webjars 形式でパッケージ化されている場合、jar ファイルから提供されます。パスは spring.webflux.webjars-path-pattern
プロパティでカスタマイズできます。
Spring WebFlux アプリケーションはサーブレット API に厳密に依存していないため、war ファイルとしてデプロイすることはできず、src/main/webapp ディレクトリを使用しません。 |
2.1.4. ウェルカムページ
Spring Boot は、静的なウェルカムページとテンプレート化されたウェルカムページの両方をサポートしています。最初に、構成された静的コンテンツの場所で index.html
ファイルを探します。見つからない場合は、index
テンプレートを探します。どちらかが見つかった場合、アプリケーションのウェルカムページとして自動的に使用されます。
2.1.5. テンプレートエンジン
REST Web サービスだけでなく、Spring WebFlux を使用して動的 HTML コンテンツを提供することもできます。Spring WebFlux は、Thymeleaf、FreeMarker、Mustache など、さまざまなテンプレートテクノロジーをサポートしています。
Spring Boot には、次のテンプレートエンジンの自動構成サポートが含まれています。
これらのテンプレートエンジンのいずれかを既定の構成で使用すると、src/main/resources/templates
からテンプレートが自動的に選択されます。
2.1.6. エラー処理
Spring Boot は、すべてのエラーを適切な方法で処理する WebExceptionHandler
を提供します。処理順序でのその位置は、WebFlux によって提供されるハンドラーの直前であり、最後に考慮されます。マシンクライアントの場合、エラー、HTTP ステータス、例外メッセージの詳細を含む JSON レスポンスを生成します。ブラウザークライアントには、同じデータを HTML 形式でレンダリングする「ホワイトラベル」エラーハンドラーがあります。また、独自の HTML テンプレートを提供してエラーを表示することもできます(次のセクションを参照)。
Spring Boot でエラー処理を直接カスタマイズする前に、Spring WebFlux で RFC 7807 問題の詳細サポートを利用できます。Spring WebFlux は、次のような application/problem+json
メディア型でカスタムエラーメッセージを生成できます。
{
"type": "https://example.org/problems/unknown-project",
"title": "Unknown project",
"status": 404,
"detail": "No project found for id 'spring-unknown'",
"instance": "/projects/spring-unknown"
}
このサポートは、spring.webflux.problemdetails.enabled
を true
に設定することで有効にできます。
この機能をカスタマイズするための最初のステップは、多くの場合、既存のメカニズムを使用しますが、エラーの内容を置換または拡張することを伴います。そのために、型 ErrorAttributes
の Bean を追加できます。
エラー処理の動作を変更するには、ErrorWebExceptionHandler
を実装し、その型の Bean 定義を登録します。ErrorWebExceptionHandler
は非常に低レベルであるため、次の例に示すように、Spring Boot は WebFlux 関数方法でエラーを処理できる便利な AbstractErrorWebExceptionHandler
も提供します。
@Component
public class MyErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
public MyErrorWebExceptionHandler(ErrorAttributes errorAttributes, Resources resources,
ApplicationContext applicationContext) {
super(errorAttributes, resources, applicationContext);
}
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml);
}
private boolean acceptsXml(ServerRequest request) {
return request.headers().accept().contains(MediaType.APPLICATION_XML);
}
public Mono<ServerResponse> handleErrorAsXml(ServerRequest request) {
BodyBuilder builder = ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR);
// ... additional builder calls
return builder.build();
}
}
@Component
class MyErrorWebExceptionHandler(errorAttributes: ErrorAttributes?, resources: WebProperties.Resources?,
applicationContext: ApplicationContext?) : AbstractErrorWebExceptionHandler(errorAttributes, resources, applicationContext) {
override fun getRoutingFunction(errorAttributes: ErrorAttributes): RouterFunction<ServerResponse> {
return RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml)
}
private fun acceptsXml(request: ServerRequest): Boolean {
return request.headers().accept().contains(MediaType.APPLICATION_XML)
}
fun handleErrorAsXml(request: ServerRequest?): Mono<ServerResponse> {
val builder = ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
// ... additional builder calls
return builder.build()
}
}
より完全な図を得るには、DefaultErrorWebExceptionHandler
を直接サブクラス化し、特定のメソッドをオーバーライドすることもできます。
場合によっては、コントローラーまたはハンドラー関数レベルで処理されたエラーは、メトリクスインフラストラクチャによって記録されません。アプリケーションは、処理された例外をリクエスト属性として設定することにより、そのような例外がリクエストメトリクスとともに記録されることを保証できます。
@Controller
public class MyExceptionHandlingController {
@GetMapping("/profile")
public Rendering userProfile() {
// ...
throw new IllegalStateException();
}
@ExceptionHandler(IllegalStateException.class)
public Rendering handleIllegalState(ServerWebExchange exchange, IllegalStateException exc) {
exchange.getAttributes().putIfAbsent(ErrorAttributes.ERROR_ATTRIBUTE, exc);
return Rendering.view("errorView").modelAttribute("message", exc.getMessage()).build();
}
}
@Controller
class MyExceptionHandlingController {
@GetMapping("/profile")
fun userProfile(): Rendering {
// ...
throw IllegalStateException()
}
@ExceptionHandler(IllegalStateException::class)
fun handleIllegalState(exchange: ServerWebExchange, exc: IllegalStateException): Rendering {
exchange.attributes.putIfAbsent(ErrorAttributes.ERROR_ATTRIBUTE, exc)
return Rendering.view("errorView").modelAttribute("message", exc.message ?: "").build()
}
}
カスタムエラーページ
特定のステータスコードのカスタム HTML エラーページを表示する場合は、/error
ディレクトリにファイルを追加するなどして、error/*
から解決されるビューを追加できます。エラーページは、静的 HTML (つまり、任意の静的リソースディレクトリに追加) にするか、テンプレートを使用して構築することができます。ファイルの名前は、正確なステータスコード、ステータスコードシリーズマスク、または他に一致するものがない場合のデフォルトの error
である必要があります。デフォルトのエラービューへのパスは error/error
であるのに対し、Spring MVC ではデフォルトのエラービューは error
であることに注意してください。
例: 404
を静的 HTML ファイルにマップするには、ディレクトリ構造は次のようになります。
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
Mustache テンプレートを使用してすべての 5xx
エラーをマップするには、ディレクトリ構造は次のようになります。
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.mustache
+- <other templates>
2.1.7. Web フィルター
Spring WebFlux は、HTTP リクエスト / レスポンス交換をフィルタリングするために実装できる WebFilter
インターフェースを提供します。アプリケーションコンテキストで見つかった WebFilter
Bean は、各交換のフィルタリングに自動的に使用されます。
フィルターの順序が重要な場合、Ordered
を実装するか、@Order
でアノテーションを付けることができます。Spring Boot の自動構成により、Web フィルターが構成される場合があります。その場合、次の表に示す順序が使用されます。
Web フィルター | 順序 |
---|---|
|
|
|
|
|
|
2.2. 埋め込み型リアクティブサーバーのサポート
Spring Boot には、Reactor Netty、Tomcat、Jetty、Undertow の組み込みリアクティブ Web サーバーのサポートが含まれています。ほとんどの開発者は、適切な「スターター」を使用して、完全に構成されたインスタンスを取得します。デフォルトでは、組み込みサーバーはポート 8080 で HTTP リクエストをリッスンします。
2.3. リアクティブサーバーリソースの構成
Reactor Netty または Jetty サーバーを自動構成する場合、Spring Boot は、サーバーインスタンスに HTTP リソースを提供する特定の Bean ReactorResourceFactory
または JettyResourceFactory
を作成します。
デフォルトでは、これらのリソースは、最適なパフォーマンスのために、Reactor Netty および Jetty クライアントとも共有されます。
同じテクノロジーがサーバーとクライアントに使用されます
クライアントインスタンスは、Spring Boot によって自動構成された
WebClient.Builder
Bean を使用して構築されます
開発者は、カスタム ReactorResourceFactory
または JettyResourceFactory
Bean を提供することにより、Jetty および Reactor Netty のリソース構成をオーバーライドできます。これは、クライアントとサーバーの両方に適用されます。
WebClient ランタイムセクションでクライアント側のリソース構成について詳しく知ることができます。
3. グレースフルシャットダウン
グレースフルシャットダウンは、4 つの組み込み Web サーバー(Jetty、Reactor Netty、Tomcat、Undertow)のすべてと、リアクティブ Web アプリケーションとサーブレットベースの Web アプリケーションの両方でサポートされています。これは、アプリケーションコンテキストを閉じる一部として発生し、SmartLifecycle
Bean を停止する最初のフェーズで実行されます。この停止処理は、既存のリクエストの補完は許可されるが、新しいリクエストは許可されない猶予期間を提供するタイムアウトを使用します。新しいリクエストが許可されない正確な方法は、使用されている Web サーバーによって異なります。Jetty、Reactor Netty、および Tomcat は、ネットワーク層でのリクエストの受け入れを停止します。Undertow はリクエストを受け入れますが、サービスを利用できない (503) レスポンスですぐにレスポンスします。
Tomcat による正常なシャットダウンには、Tomcat 9.0.33 以降が必要です。 |
グレースフルシャットダウンを有効にするには、次の例に示すように、server.shutdown
プロパティを構成します。
server.shutdown=graceful
server:
shutdown: "graceful"
タイムアウト期間を構成するには、次の例に示すように、spring.lifecycle.timeout-per-shutdown-phase
プロパティを構成します。
spring.lifecycle.timeout-per-shutdown-phase=20s
spring:
lifecycle:
timeout-per-shutdown-phase: "20s"
IDE が適切な SIGTERM シグナルを送信しない場合、IDE でグレースフルシャットダウンを使用すると正しく機能しない可能性があります。詳細については、IDE のドキュメントを参照してください。 |
4. Spring Security
Spring Security がクラスパスにある場合、Web アプリケーションはデフォルトで保護されます。Spring Boot は、Spring Security のコンテンツネゴシエーション戦略に基づいて、httpBasic
と formLogin
のどちらを使用するかを決定します。メソッドレベルのセキュリティを Web アプリケーションに追加するために、必要な設定で @EnableGlobalMethodSecurity
を追加することもできます。追加情報は Spring Security リファレンスガイドにあります。
デフォルトの UserDetailsService
にはシングルユーザーがいます。次の例に示すように、ユーザー名は user
であり、パスワードはランダムであり、アプリケーションの起動時に WARN レベルで出力されます。
Using generated security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35 This generated password is for development use only. Your security configuration must be updated before running your application in production.
ロギング構成を微調整する場合は、org.springframework.boot.autoconfigure.security カテゴリが WARN -level メッセージを記録するように設定されていることを確認してください。それ以外の場合、デフォルトのパスワードは出力されません。 |
spring.security.user.name
および spring.security.user.password
を提供することにより、ユーザー名とパスワードを変更できます。
Web アプリケーションでデフォルトで取得する基本機能は次のとおりです。
UserDetailsService
(または WebFlux アプリケーションの場合はReactiveUserDetailsService
)メモリ内ストアを持つ Bean と、生成されたパスワードを持つ単一のユーザー(ユーザーのプロパティについてはSecurityProperties.User
(Javadoc) を参照)。アプリケーション全体(アクチュエーターがクラスパス上にある場合はアクチュエーターエンドポイントを含む)に対するフォームベースのログインまたは HTTP Basic セキュリティ(リクエストの
Accept
ヘッダーに依存)。認証イベントを公開するための
DefaultAuthenticationEventPublisher
。
Bean を追加することにより、異なる AuthenticationEventPublisher
を提供できます。
4.1. MVC セキュリティ
デフォルトのセキュリティ構成は、SecurityAutoConfiguration
および UserDetailsServiceAutoConfiguration
に実装されています。SecurityAutoConfiguration
は Web セキュリティのために SpringBootWebSecurityConfiguration
をインポートし、UserDetailsServiceAutoConfiguration
は認証を構成します。これは Web 以外のアプリケーションにも関連します。デフォルトの Web アプリケーションセキュリティ構成を完全にオフにするか、OAuth2 クライアントやリソースサーバーなどの複数の Spring Security コンポーネントを組み合わせるには、型 SecurityFilterChain
の Bean を追加します(そうしても、UserDetailsService
構成またはアクチュエーターのセキュリティは無効になりません)。
UserDetailsService
構成をオフにするために、型 UserDetailsService
、AuthenticationProvider
、AuthenticationManager
の Bean を追加することもできます。
アクセスルールは、カスタム SecurityFilterChain
Bean を追加することでオーバーライドできます。Spring Boot は、アクチュエーターエンドポイントと静的リソースのアクセスルールをオーバーライドするために使用できる便利なメソッドを提供します。EndpointRequest
を使用して、management.endpoints.web.base-path
プロパティに基づく RequestMatcher
を作成できます。PathRequest
を使用して、一般的に使用される場所にリソース用の RequestMatcher
を作成できます。
4.2. WebFlux セキュリティ
Spring MVC アプリケーションと同様に、spring-boot-starter-security
依存関係を追加することで WebFlux アプリケーションを保護できます。デフォルトのセキュリティ設定は ReactiveSecurityAutoConfiguration
および UserDetailsServiceAutoConfiguration
に実装されています。ReactiveSecurityAutoConfiguration
は Web セキュリティのために WebFluxSecurityConfiguration
をインポートし、UserDetailsServiceAutoConfiguration
は認証を構成します。これは、非 Web アプリケーションにも関連します。デフォルトの Web アプリケーションセキュリティ設定を完全にオフにするには、型 WebFilterChainProxy
の Bean を追加します (追加しても UserDetailsService
設定やアクチュエーターのセキュリティは無効になりません)。
UserDetailsService
構成もオフにするには、型 ReactiveUserDetailsService
または ReactiveAuthenticationManager
の Bean を追加できます。
カスタム SecurityWebFilterChain
Bean を追加することにより、アクセスルールと、OAuth 2 クライアントやリソースサーバーなどの複数の Spring Security コンポーネントの使用を構成できます。Spring Boot は、アクチュエーターエンドポイントおよび静的リソースのアクセスルールをオーバーライドするために使用できる便利なメソッドを提供します。EndpointRequest
を使用して、management.endpoints.web.base-path
プロパティに基づく ServerWebExchangeMatcher
を作成できます。
PathRequest
を使用して、一般的に使用される場所のリソース用の ServerWebExchangeMatcher
を作成できます。
例: 次のようなものを追加して、セキュリティ構成をカスタマイズできます。
@Configuration(proxyBeanMethods = false)
public class MyWebFluxSecurityConfiguration {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.authorizeExchange((exchange) -> {
exchange.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();
exchange.pathMatchers("/foo", "/bar").authenticated();
});
http.formLogin(withDefaults());
return http.build();
}
}
@Configuration(proxyBeanMethods = false)
class MyWebFluxSecurityConfiguration {
@Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
http.authorizeExchange { spec ->
spec.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
spec.pathMatchers("/foo", "/bar").authenticated()
}
http.formLogin(withDefaults())
return http.build()
}
}
4.3. OAuth2
OAuth2 (英語) は、Spring でサポートされている広く使用されている認可フレームワークです。
4.3.1. クライアント
クラスパスに spring-security-oauth2-client
がある場合は、自動構成を利用して OAuth2/OpenIDConnect クライアントをセットアップできます。この構成では、OAuth2ClientProperties
のプロパティを利用します。同じプロパティがサーブレットアプリケーションとリアクティブアプリケーションの両方に適用できます。
次の例に示すように、spring.security.oauth2.client
プレフィックスに複数の OAuth2 クライアントとプロバイダーを登録できます。
spring.security.oauth2.client.registration.my-login-client.client-id=abcd
spring.security.oauth2.client.registration.my-login-client.client-secret=password
spring.security.oauth2.client.registration.my-login-client.client-name=Client for OpenID Connect
spring.security.oauth2.client.registration.my-login-client.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-login-client.scope=openid,profile,email,phone,address
spring.security.oauth2.client.registration.my-login-client.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.my-login-client.client-authentication-method=client_secret_basic
spring.security.oauth2.client.registration.my-login-client.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.my-client-1.client-id=abcd
spring.security.oauth2.client.registration.my-client-1.client-secret=password
spring.security.oauth2.client.registration.my-client-1.client-name=Client for user scope
spring.security.oauth2.client.registration.my-client-1.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-1.scope=user
spring.security.oauth2.client.registration.my-client-1.redirect-uri={baseUrl}/authorized/user
spring.security.oauth2.client.registration.my-client-1.client-authentication-method=client_secret_basic
spring.security.oauth2.client.registration.my-client-1.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.my-client-2.client-id=abcd
spring.security.oauth2.client.registration.my-client-2.client-secret=password
spring.security.oauth2.client.registration.my-client-2.client-name=Client for email scope
spring.security.oauth2.client.registration.my-client-2.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-2.scope=email
spring.security.oauth2.client.registration.my-client-2.redirect-uri={baseUrl}/authorized/email
spring.security.oauth2.client.registration.my-client-2.client-authentication-method=client_secret_basic
spring.security.oauth2.client.registration.my-client-2.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=https://my-auth-server.com/oauth2/authorize
spring.security.oauth2.client.provider.my-oauth-provider.token-uri=https://my-auth-server.com/oauth2/token
spring.security.oauth2.client.provider.my-oauth-provider.user-info-uri=https://my-auth-server.com/userinfo
spring.security.oauth2.client.provider.my-oauth-provider.user-info-authentication-method=header
spring.security.oauth2.client.provider.my-oauth-provider.jwk-set-uri=https://my-auth-server.com/oauth2/jwks
spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=name
spring:
security:
oauth2:
client:
registration:
my-login-client:
client-id: "abcd"
client-secret: "password"
client-name: "Client for OpenID Connect"
provider: "my-oauth-provider"
scope: "openid,profile,email,phone,address"
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
client-authentication-method: "client_secret_basic"
authorization-grant-type: "authorization_code"
my-client-1:
client-id: "abcd"
client-secret: "password"
client-name: "Client for user scope"
provider: "my-oauth-provider"
scope: "user"
redirect-uri: "{baseUrl}/authorized/user"
client-authentication-method: "client_secret_basic"
authorization-grant-type: "authorization_code"
my-client-2:
client-id: "abcd"
client-secret: "password"
client-name: "Client for email scope"
provider: "my-oauth-provider"
scope: "email"
redirect-uri: "{baseUrl}/authorized/email"
client-authentication-method: "client_secret_basic"
authorization-grant-type: "authorization_code"
provider:
my-oauth-provider:
authorization-uri: "https://my-auth-server.com/oauth2/authorize"
token-uri: "https://my-auth-server.com/oauth2/token"
user-info-uri: "https://my-auth-server.com/userinfo"
user-info-authentication-method: "header"
jwk-set-uri: "https://my-auth-server.com/oauth2/jwks"
user-name-attribute: "name"
OpenID Connect ディスカバリ (英語) をサポートする OpenID Connect プロバイダーの場合、構成をさらに簡素化できます。プロバイダーは、発行者識別子としてアサートする URI である issuer-uri
を使用して構成する必要があります。例: 提供された issuer-uri
が "https://example.com" の場合、「OpenID プロバイダー構成リクエスト」が "https://example.com/.well-known/openid-configuration" に対して行われます。結果は "OpenID Provider Configuration Response" であると予想されます。次の例は、OpenID Connect プロバイダーを issuer-uri
で構成する方法を示しています。
spring.security.oauth2.client.provider.oidc-provider.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
spring:
security:
oauth2:
client:
provider:
oidc-provider:
issuer-uri: "https://dev-123456.oktapreview.com/oauth2/default/"
デフォルトでは、Spring Security の OAuth2LoginAuthenticationFilter
は /login/oauth2/code/*
に一致する URL のみを処理します。redirect-uri
をカスタマイズして別のパターンを使用する場合は、そのカスタムパターンを処理するための構成を提供する必要があります。例: サーブレットアプリケーションの場合、次のような独自の SecurityFilterChain
を追加できます。
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
public class MyOAuthClientConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.anyRequest().authenticated()
)
.oauth2Login((login) -> login
.redirectionEndpoint((endpoint) -> endpoint
.baseUri("/login/oauth2/callback/*")
)
);
return http.build();
}
}
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
open class MyOAuthClientConfiguration {
@Bean
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
authorize(anyRequest, authenticated)
}
oauth2Login {
redirectionEndpoint {
baseUri = "/login/oauth2/callback/*"
}
}
}
return http.build()
}
}
Spring Boot は、クライアント登録の管理のために Spring Security によって使用される InMemoryOAuth2AuthorizedClientService を自動構成します。InMemoryOAuth2AuthorizedClientService の機能には制限があるため、開発環境でのみ使用することをお勧めします。本番環境では、JdbcOAuth2AuthorizedClientService を使用するか、OAuth2AuthorizedClientService の独自の実装を作成することを検討してください。 |
Common Provider の OAuth2 クライアント登録
Google、Github、Facebook、Okta などの一般的な OAuth2 プロバイダーと OpenID プロバイダーについては、プロバイダーのデフォルトのセット (それぞれ google
、github
、facebook
、okta
) が提供されています。
これらのプロバイダーをカスタマイズする必要がない場合は、provider
属性をデフォルトを推測する必要がある属性に設定できます。また、クライアント登録のキーがデフォルトでサポートされているプロバイダーと一致する場合、Spring Boot も同様に推測します。
つまり、次の例の 2 つの構成では Google プロバイダーを使用します。
spring.security.oauth2.client.registration.my-client.client-id=abcd
spring.security.oauth2.client.registration.my-client.client-secret=password
spring.security.oauth2.client.registration.my-client.provider=google
spring.security.oauth2.client.registration.google.client-id=abcd
spring.security.oauth2.client.registration.google.client-secret=password
spring:
security:
oauth2:
client:
registration:
my-client:
client-id: "abcd"
client-secret: "password"
provider: "google"
google:
client-id: "abcd"
client-secret: "password"
4.3.2. リソースサーバー
クラスパスに spring-security-oauth2-resource-server
がある場合、Spring Boot は OAuth2 リソースサーバーをセットアップできます。JWT 構成の場合、次の例に示すように、JWK セット URI または OIDC 発行者 URI を指定する必要があります。
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://example.com/oauth2/default/v1/keys
spring:
security:
oauth2:
resourceserver:
jwt:
jwk-set-uri: "https://example.com/oauth2/default/v1/keys"
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: "https://dev-123456.oktapreview.com/oauth2/default/"
認可サーバーが JWK Set URI をサポートしていない場合、JWT の署名の検証に使用される公開鍵でリソースサーバーを構成できます。これは、spring.security.oauth2.resourceserver.jwt.public-key-location プロパティを使用して実行できます。値は、PEM エンコードされた x509 形式の公開鍵を含むファイルを指す必要があります。 |
spring.security.oauth2.resourceserver.jwt.audiences
プロパティを使用して、JWT の aud クレームの予期される値を指定できます。例: JWT に値 my-audience
の aud クレームを含めるよう要求するには:
spring.security.oauth2.resourceserver.jwt.audiences[0]=my-audience
spring:
security:
oauth2:
resourceserver:
jwt:
audiences:
- "my-audience"
同じプロパティがサーブレットアプリケーションとリアクティブアプリケーションの両方に適用されます。あるいは、サーブレットアプリケーション用に独自の JwtDecoder
Bean を定義したり、リアクティブアプリケーション用に ReactiveJwtDecoder
を定義したりできます。
JWT の代わりに Opaque トークンが使用されている場合は、次のプロパティを構成して、イントロスペクションを通じてトークンを検証できます。
spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://example.com/check-token
spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id
spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret
spring:
security:
oauth2:
resourceserver:
opaquetoken:
introspection-uri: "https://example.com/check-token"
client-id: "my-client-id"
client-secret: "my-client-secret"
繰り返しますが、同じプロパティがサーブレットアプリケーションとリアクティブアプリケーションの両方に適用できます。あるいは、サーブレットアプリケーション用に独自の OpaqueTokenIntrospector
Bean を定義したり、リアクティブアプリケーション用に ReactiveOpaqueTokenIntrospector
を定義したりできます。
4.3.3. 認可サーバー
クラスパスに spring-security-oauth2-authorization-server
がある場合は、いくつかの自動構成を利用して、サーブレットベースの OAuth2 認可サーバーをセットアップできます。
次の例に示すように、spring.security.oauth2.authorizationserver.client
プレフィックスで複数の OAuth2 クライアントを登録できます。
spring.security.oauth2.authorizationserver.client.my-client-1.registration.client-id=abcd
spring.security.oauth2.authorizationserver.client.my-client-1.registration.client-secret={noop}secret1
spring.security.oauth2.authorizationserver.client.my-client-1.registration.client-authentication-methods[0]=client_secret_basic
spring.security.oauth2.authorizationserver.client.my-client-1.registration.authorization-grant-types[0]=authorization_code
spring.security.oauth2.authorizationserver.client.my-client-1.registration.authorization-grant-types[1]=refresh_token
spring.security.oauth2.authorizationserver.client.my-client-1.registration.redirect-uris[0]=https://my-client-1.com/login/oauth2/code/abcd
spring.security.oauth2.authorizationserver.client.my-client-1.registration.redirect-uris[1]=https://my-client-1.com/authorized
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[0]=openid
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[1]=profile
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[2]=email
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[3]=phone
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[4]=address
spring.security.oauth2.authorizationserver.client.my-client-1.require-authorization-consent=true
spring.security.oauth2.authorizationserver.client.my-client-2.registration.client-id=efgh
spring.security.oauth2.authorizationserver.client.my-client-2.registration.client-secret={noop}secret2
spring.security.oauth2.authorizationserver.client.my-client-2.registration.client-authentication-methods[0]=client_secret_jwt
spring.security.oauth2.authorizationserver.client.my-client-2.registration.authorization-grant-types[0]=client_credentials
spring.security.oauth2.authorizationserver.client.my-client-2.registration.scopes[0]=user.read
spring.security.oauth2.authorizationserver.client.my-client-2.registration.scopes[1]=user.write
spring.security.oauth2.authorizationserver.client.my-client-2.jwk-set-uri=https://my-client-2.com/jwks
spring.security.oauth2.authorizationserver.client.my-client-2.token-endpoint-authentication-signing-algorithm=RS256
spring:
security:
oauth2:
authorizationserver:
client:
my-client-1:
registration:
client-id: "abcd"
client-secret: "{noop}secret1"
client-authentication-methods:
- "client_secret_basic"
authorization-grant-types:
- "authorization_code"
- "refresh_token"
redirect-uris:
- "https://my-client-1.com/login/oauth2/code/abcd"
- "https://my-client-1.com/authorized"
scopes:
- "openid"
- "profile"
- "email"
- "phone"
- "address"
require-authorization-consent: true
my-client-2:
registration:
client-id: "efgh"
client-secret: "{noop}secret2"
client-authentication-methods:
- "client_secret_jwt"
authorization-grant-types:
- "client_credentials"
scopes:
- "user.read"
- "user.write"
jwk-set-uri: "https://my-client-2.com/jwks"
token-endpoint-authentication-signing-algorithm: "RS256"
client-secret プロパティは、構成された PasswordEncoder と一致する形式である必要があります。PasswordEncoder のデフォルトのインスタンスは PasswordEncoderFactories.createDelegatingPasswordEncoder() によって作成されます。 |
Spring Boot が Spring Authorization Server に提供する自動構成は、すぐに開始できるように設計されています。ほとんどのアプリケーションはカスタマイズを必要とし、自動構成をオーバーライドするためにいくつかの Bean を定義する必要があります。
次のコンポーネントを Bean として定義して、Spring Authorization Server に固有の自動構成をオーバーライドできます。
RegisteredClientRepository
AuthorizationServerSettings
SecurityFilterChain
com.nimbusds.jose.jwk.source.JWKSource<com.nimbusds.jose.proc.SecurityContext>
JwtDecoder
Spring Boot は、登録されたクライアントの管理のために Spring Authorization Server によって使用される InMemoryRegisteredClientRepository を自動構成します。InMemoryRegisteredClientRepository の機能は限られているため、開発環境でのみ使用することをお勧めします。本番環境では、JdbcRegisteredClientRepository を使用するか、独自の RegisteredClientRepository 実装を作成することを検討してください。 |
追加情報は、Spring Authorization Server リファレンスガイドの入門の章にあります。
4.4. SAML 2.0
4.4.1. 証明書利用者
クラスパスに spring-security-saml2-service-provider
がある場合は、自動構成を利用して SAML 2.0 依存パーティをセットアップできます。この構成では、Saml2RelyingPartyProperties
のプロパティを使用します。
証明書利用者登録は、ID プロバイダー IDP とサービスプロバイダー SP の間のペア構成を表します。次の例に示すように、spring.security.saml2.relyingparty
プレフィックスに複数の証明書利用者を登録できます。
spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party1.decryption.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party1.decryption.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party1.singlelogout.url=https://myapp/logout/saml2/slo
spring.security.saml2.relyingparty.registration.my-relying-party1.singlelogout.response-url=https://remoteidp2.slo.url
spring.security.saml2.relyingparty.registration.my-relying-party1.singlelogout.binding=POST
spring.security.saml2.relyingparty.registration.my-relying-party1.assertingparty.verification.credentials[0].certificate-location=path-to-verification-cert
spring.security.saml2.relyingparty.registration.my-relying-party1.assertingparty.entity-id=remote-idp-entity-id1
spring.security.saml2.relyingparty.registration.my-relying-party1.assertingparty.sso-url=https://remoteidp1.sso.url
spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party2.decryption.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party2.decryption.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.verification.credentials[0].certificate-location=path-to-other-verification-cert
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.entity-id=remote-idp-entity-id2
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.sso-url=https://remoteidp2.sso.url
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.singlelogout.url=https://remoteidp2.slo.url
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.singlelogout.response-url=https://myapp/logout/saml2/slo
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.singlelogout.binding=POST
spring:
security:
saml2:
relyingparty:
registration:
my-relying-party1:
signing:
credentials:
- private-key-location: "path-to-private-key"
certificate-location: "path-to-certificate"
decryption:
credentials:
- private-key-location: "path-to-private-key"
certificate-location: "path-to-certificate"
singlelogout:
url: "https://myapp/logout/saml2/slo"
response-url: "https://remoteidp2.slo.url"
binding: "POST"
assertingparty:
verification:
credentials:
- certificate-location: "path-to-verification-cert"
entity-id: "remote-idp-entity-id1"
sso-url: "https://remoteidp1.sso.url"
my-relying-party2:
signing:
credentials:
- private-key-location: "path-to-private-key"
certificate-location: "path-to-certificate"
decryption:
credentials:
- private-key-location: "path-to-private-key"
certificate-location: "path-to-certificate"
assertingparty:
verification:
credentials:
- certificate-location: "path-to-other-verification-cert"
entity-id: "remote-idp-entity-id2"
sso-url: "https://remoteidp2.sso.url"
singlelogout:
url: "https://remoteidp2.slo.url"
response-url: "https://myapp/logout/saml2/slo"
binding: "POST"
SAML2 ログアウトの場合、デフォルトでは、Spring Security の Saml2LogoutRequestFilter
および Saml2LogoutResponseFilter
は /logout/saml2/slo
に一致する URL のみを処理します。AP が開始したログアウトリクエストの送信先となる url
または AP がログアウトレスポンスを送信する response-url
をカスタマイズする場合は、別のパターンを使用して、そのカスタムパターンを処理するための構成を提供する必要があります。例: サーブレットアプリケーションの場合、次のような独自の SecurityFilterChain
を追加できます。
@Configuration(proxyBeanMethods = false)
public class MySamlRelyingPartyConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());
http.saml2Login(withDefaults());
http.saml2Logout((saml2) -> saml2.logoutRequest((request) -> request.logoutUrl("/SLOService.saml2"))
.logoutResponse((response) -> response.logoutUrl("/SLOService.saml2")));
return http.build();
}
}
5. Spring Session
Spring Boot は、さまざまなデータストアに Spring Session 自動構成を提供します。サーブレット Web アプリケーションを構築する場合、次のストアを自動構成できます。
Redis
JDBC
Hazelcast
MongoDB
サーブレットの自動構成により、@Enable*HttpSession
を使用する必要がなくなります。
クラスパスに単一の Spring Session モジュールが存在する場合、Spring Boot はそのストア実装を自動的に使用します。複数の実装がある場合、Spring Boot は特定の実装を選択するために次の順序を使用します。
Redis
JDBC
Hazelcast
MongoDB
Redis、JDBC、Hazelcast、MongoDB のいずれも使用できない場合、
SessionRepository
は構成されません。
リアクティブ Web アプリケーションを構築する場合、次のストアを自動構成できます。
Redis
MongoDB
リアクティブ自動構成は、@Enable*WebSession
を使用する必要性を置き換えます。
サーブレット構成と同様に、複数の実装がある場合、Spring Boot は特定の実装を選択するために次の順序を使用します。
Redis
MongoDB
Redis も MongoDB も利用できない場合、
ReactiveSessionRepository
は構成されません。
各ストアには特定の追加設定があります。たとえば、次の例に示すように、JDBC ストアのテーブルの名前をカスタマイズできます。
spring.session.jdbc.table-name=SESSIONS
spring:
session:
jdbc:
table-name: "SESSIONS"
セッションのタイムアウトを設定するには、spring.session.timeout
プロパティを使用できます。そのプロパティがサーブレット Web アプリケーションで設定されていない場合、自動構成は server.servlet.session.timeout
の値にフォールバックします。
@Enable*HttpSession
(サーブレット)または @Enable*WebSession
(リアクティブ)を使用して、Spring Session の構成を制御できます。これにより、自動構成がバックオフします。Spring Session は、前述の構成プロパティではなく、アノテーションの属性を使用して構成できます。
6. Spring for GraphQL
GraphQL アプリケーションを構築する場合は、Spring Boot の Spring for GraphQL の自動構成を利用できます。Spring for GraphQL プロジェクトは GraphQL Java [GitHub] (英語) に基づいています。少なくとも spring-boot-starter-graphql
スターターが必要です。GraphQL はトランスポートに依存しないため、GraphQL API を Web 上で公開するには、アプリケーションに 1 つ以上の追加のスターターが必要です。
スターター | トランスポート | 実装 |
---|---|---|
| HTTP | Spring MVC |
| WebSocket | サーブレットアプリ用の WebSocket |
| HTTP、WebSocket | Spring WebFlux |
| TCP、WebSocket | Spring WebFlux on Reactor Netty |
6.1. GraphQL スキーマ
Spring GraphQL アプリケーションには、起動時に定義済みのスキーマが必要です。デフォルトでは、src/main/resources/graphql/**
に ".graphqls" または ".gqls" スキーマファイルを書き込むことができ、Spring Boot はそれらを自動的に取得します。spring.graphql.schema.locations
を使用して場所をカスタマイズし、spring.graphql.schema.file-extensions
を使用してファイル拡張子をカスタマイズできます。
すべてのアプリケーションモジュール内のスキーマファイルとその場所の依存関係を Spring Boot で検出する場合は、spring.graphql.schema.locations を "classpath*:graphql/**/" に設定できます (classpath*: プレフィックスに注意してください)。 |
次のセクションでは、このサンプル GraphQL スキーマを検討し、2 つの型と 2 つのクエリを定義します。
type Query {
greeting(name: String! = "Spring"): String!
project(slug: ID!): Project
}
""" A Project in the Spring portfolio """
type Project {
""" Unique string id used in URLs """
slug: ID!
""" Project name """
name: String!
""" URL of the git repository """
repositoryUrl: String!
""" Current support status """
status: ProjectStatus!
}
enum ProjectStatus {
""" Actively supported by the Spring team """
ACTIVE
""" Supported by the community """
COMMUNITY
""" Prototype, not officially supported yet """
INCUBATING
""" Project being retired, in maintenance mode """
ATTIC
""" End-Of-Lifed """
EOL
}
デフォルトでは、GraphiQL などのツールに必要なため、スキーマでフィールドイントロスペクションが許可 (英語) されます。スキーマに関する情報を公開したくない場合は、spring.graphql.schema.introspection.enabled を false に設定することでイントロスペクションを無効にできます。 |
6.2. GraphQL RuntimeWiring
GraphQL Java RuntimeWiring.Builder
を使用して、カスタムスカラー型、ディレクティブ、型リゾルバー、DataFetcher
などを登録できます。Spring 構成で RuntimeWiringConfigurer
Bean を宣言して、RuntimeWiring.Builder
にアクセスできます。Spring Boot はそのような Bean を検出し、GraphQlSource ビルダーに追加します。
ただし、通常、アプリケーションは DataFetcher
を直接実装せず、代わりにアノテーション付きコントローラーを作成します。Spring Boot は、アノテーション付きのハンドラーメソッドを持つ @Controller
クラスを自動的に検出し、DataFetcher
として登録します。@Controller
クラスを使用したグリーティングクエリの実装例を次に示します。
@Controller
public class GreetingController {
@QueryMapping
public String greeting(@Argument String name) {
return "Hello, " + name + "!";
}
}
;
@Controller
class GreetingController {
@QueryMapping
fun greeting(@Argument name: String): String {
return "Hello, $name!"
}
}
6.3. Querydsl および QueryByExample リポジトリのサポート
Spring Data は、Querydsl リポジトリと QueryByExample リポジトリの両方をサポートします。Spring GraphQL は、Querydsl および QueryByExample リポジトリを DataFetcher
として構成できます。
@GraphQlRepository
でアノテーションが付けられ、次のいずれかを継承する Spring Data リポジトリ:
QuerydslPredicateExecutor
ReactiveQuerydslPredicateExecutor
QueryByExampleExecutor
ReactiveQueryByExampleExecutor
Spring Boot によって検出され、トップレベルのクエリに一致する DataFetcher
の候補と見なされます。
6.4. トランスポート
6.4.1. HTTP および WebSocket
GraphQL HTTP エンドポイントは、デフォルトで HTTP POST /graphql
にあります。パスは spring.graphql.path
でカスタマイズできます。
Spring MVC と Spring の両方の HTTP エンドポイント WebFlux は、0 の @Order を持つ RouterFunction Bean によって提供されます。独自の RouterFunction Bean を定義する場合は、適切な @Order アノテーションを追加して、それらが正しくソートされるようにすることができます。 |
GraphQL WebSocket エンドポイントはデフォルトでオフになっています。有効にするには:
サーブレットアプリケーションの場合は、WebSocket スターター
spring-boot-starter-websocket
を追加しますWebFlux アプリケーションの場合、追加の依存関係は必要ありません
どちらの場合も、
spring.graphql.websocket.path
アプリケーションプロパティを設定する必要があります
Spring GraphQL は Web インターセプトモデルを提供します。これは、HTTP リクエストヘッダーから情報を取得して GraphQL コンテキストに設定したり、同じコンテキストから情報を取得してレスポンスヘッダーに書き込んだりする場合に非常に便利です。Spring Boot を使用すると、WebInterceptor
Bean を宣言して、Web トランスポートに登録することができます。
Spring MVC および Spring WebFlux は、CORS(クロスオリジンリソースシェアリング)リクエストをサポートします。CORS は、さまざまなドメインを使用するブラウザーからアクセスされる GraphQL アプリケーションの Web 構成の重要な部分です。
Spring Boot は、spring.graphql.cors.*
名前空間で多くの構成プロパティをサポートします。設定例を次に示します。
spring.graphql.cors.allowed-origins=https://example.org
spring.graphql.cors.allowed-methods=GET,POST
spring.graphql.cors.max-age=1800s
spring:
graphql:
cors:
allowed-origins: "https://example.org"
allowed-methods: GET,POST
max-age: 1800s
6.4.2. RSocket
RSocket は、WebSocket または TCP に加えて、トランスポートとしてもサポートされています。RSocket サーバーが構成されているが完了すると、spring.graphql.rsocket.mapping
を使用して特定のルートに GraphQL ハンドラーを構成できます。例: そのマッピングを "graphql"
として構成すると、RSocketGraphQlClient
でリクエストを送信するときにルートとして使用できるようになります。
Spring Boot は、コンポーネントに挿入できる RSocketGraphQlClient.Builder<?>
Bean を自動構成します。
@Component
public class RSocketGraphQlClientExample {
private final RSocketGraphQlClient graphQlClient;
public RSocketGraphQlClientExample(RSocketGraphQlClient.Builder<?> builder) {
this.graphQlClient = builder.tcp("example.spring.io", 8181).route("graphql").build();
}
@Component
class RSocketGraphQlClientExample(private val builder: RSocketGraphQlClient.Builder<*>) {
そして、リクエストを送信します。
Mono<Book> book = this.graphQlClient.document("{ bookById(id: \"book-1\"){ id name pageCount author } }")
.retrieve("bookById")
.toEntity(Book.class);
val book = graphQlClient.document(
"""
{
bookById(id: "book-1"){
id
name
pageCount
author
}
}
"""
)
.retrieve("bookById").toEntity(Book::class.java)
6.5. 例外処理
Spring GraphQL を使用すると、アプリケーションは、順次呼び出される 1 つ以上の Spring DataFetcherExceptionResolver
コンポーネントを登録できます。例外は、graphql.GraphQLError
オブジェクトのリストに解決する必要があります。Spring GraphQL 例外処理ドキュメントを参照してください。Spring Boot は DataFetcherExceptionResolver
Bean を自動的に検出し、GraphQlSource.Builder
に登録します。
6.6. GraphiQL とスキーマプリンター
Spring GraphQL は、GraphQLAPI を使用または開発する際に開発者を支援するためのインフラストラクチャーを提供します。
Spring GraphQL には、デフォルトで "/graphiql"
で公開されるデフォルトの GraphiQL [GitHub] (英語) ページが付属しています。このページはデフォルトで無効になっており、spring.graphql.graphiql.enabled
プロパティでオンにできます。このようなページを公開する多くのアプリケーションは、カスタムビルドを好みます。デフォルトの実装は開発中に非常に役立ちます。これが、開発中に spring-boot-devtools
で自動的に公開される理由です。
spring.graphql.schema.printer.enabled
プロパティが有効になっている場合は、/graphql/schema
で GraphQL スキーマをテキスト形式で公開することもできます。
7. Spring HATEOAS
ハイパーメディアを利用する RESTful API を開発する場合、Spring Boot は、ほとんどのアプリケーションで適切に機能する Spring HATEOAS の自動構成を提供します。自動構成は、@EnableHypermediaSupport
を使用する必要性を置き換え、ハイパーメディアベースのアプリケーションの構築を容易にするために多数の Bean を登録します。これには、LinkDiscoverers
(クライアント側サポート用)や、レスポンスを目的の表現に正しくマーシャリングするように構成された ObjectMapper
が含まれます。ObjectMapper
は、さまざまな spring.jackson.*
プロパティを設定するか、存在する場合は Jackson2ObjectMapperBuilder
Bean によってカスタマイズされます。
@EnableHypermediaSupport
を使用して、Spring HATEOAS の構成を制御できます。これを行うと、前述の ObjectMapper
のカスタマイズが無効になることに注意してください。
spring-boot-starter-hateoas は Spring MVC に固有であり、Spring WebFlux と組み合わせないでください。Spring HATEOAS を Spring WebFlux と一緒に使用するために、spring-boot-starter-webflux とともに org.springframework.hateoas:spring-hateoas への直接依存関係を追加できます。 |
8. 次のステップ
これで、Spring Boot を使用して Web アプリケーションを開発する方法を十分に理解できたはずです。次のいくつかのセクションでは、Spring Boot がさまざまなデータテクノロジー、メッセージングシステム、およびその他の IO 機能とどのように統合されるかについて説明します。アプリケーションのニーズに基づいて、これらのいずれかを選択できます。