簡體   English   中英

通過@Configuration、@Bean 和 @Component 進行 Spring 依賴注入

[英]Spring Dependency Injection via @Configuration, @Bean and @Component

我一直在努力通過@Configuration@Bean@Component注釋完全理解依賴注入是如何工作的。

我的代碼如下。

1) Route.kt

/* Route.kt */

package com.example.service

import com.example.service.ports.AutoComplete
import com.example.service.ports.Validation
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.MediaType.APPLICATION_JSON
import org.springframework.web.reactive.function.server.router

@Configuration
@Suppress("unused")
class Routes(private val autoComplete: AutoComplete,
             private val validation: Validation) {

    @Bean
    fun route() = router {
        ("/service-lookup" and accept(APPLICATION_JSON)).nest {
            GET("/auto-complete/{service}", autoComplete::autoComplete)
            GET("/validation/{service}", validation::validation)
        }
    }
}

2) ServiceImpl.kt

package com.example.service

import com.example.service.ports.AutoComplete
import com.example.service.ports.Validation
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.server.ServerRequest
import org.springframework.web.reactive.function.server.ServerResponse
import reactor.core.publisher.Mono

@Component
@Suppress("unused")
class ServiceImpl: AutoComplete, Validation {
    override fun autoComplete(request: ServerRequest): Mono<ServerResponse> {
        TODO("not implemented autoComplete") //To change body of created functions use File | Settings | File Templates.
    }

    override fun validation(request: ServerRequest): Mono<ServerResponse> {
        TODO("not implemented validation") //To change body of created functions use File | Settings | File Templates.
    }
}

3) ports/AutoComplete.kt

package com.example.service.ports

import org.springframework.web.reactive.function.server.ServerRequest
import org.springframework.web.reactive.function.server.ServerResponse
import reactor.core.publisher.Mono

interface AutoComplete {

    fun autoComplete(request: ServerRequest): Mono<ServerResponse>

}

4) ports/Validation.kt

package com.example.service.ports

import org.springframework.web.reactive.function.server.ServerRequest
import org.springframework.web.reactive.function.server.ServerResponse
import reactor.core.publisher.Mono

interface Validation {

    fun validation(request: ServerRequest): Mono<ServerResponse>

}

我的問題是,如何將route從創建豆Route.kt知道, autoCompletevalidation應使用ServiceImpl類從ServiceImpl.kt

以下對 Spring 機制的描述為您簡化了示例:

在啟動時,Spring Boot 會掃描所有用@Configuration@Component等注釋的類的類路徑,並構建一個 bean 定義列表。 在您的示例中,它找到了RoutesServiceImpl類。

在此之后,Spring 會掃描 bean 定義列表中每個類的所有方法以獲取進一步的@Bean注釋,並將該方法(尤其是返回類型)添加到 bean 定義列表中。 在您的示例中,它找到了route方法。

在第一次掃描之后,Spring 知道存在哪些 bean 類型以及哪個 bean 類實現了哪些接口。 Spring 知道創建 bean 實例需要哪些構造函數參數、 Inject目標或方法參數。 有了這些信息,Spring 就會以正確的順序實例化 bean。 在您的示例中,Spring 知道Router需要AutoCompleteValidation並且ServiceImpl實現了這些接口。 因此它必須先實例化ServiceImpl然后再實例化Router

如果不止一個 b​​ean 實現了相同的接口,Spring 將拋出異常,您必須進一步限定該 bean。

我將嘗試澄清:

@Component - 它與 spring 自動配置和組件掃描緊密結合。 只要在@ComponentScanned 注解定義的組件掃描路徑中,所有標有 Component 的東西都會被拾取。 @Components 分為三種風格:

A) 存儲庫 - 用於持久化

B) 控制器,例如 RestController

C) 服務 - 沒有狀態的服務。 F.ex 一個門面。

該注解用於自動構建應用程序上下文,以及為綁定到上下文的 bean 定義構造型。

@Bean - @Bean 和 @Component 有相同的目標,但 @Bean 不是 @Component。 它們都構建了應用程序上下文,但它們以非常不同的方式進行構建。 而@Component 定義了類的構造型並告訴 spring 選擇它。 Bean 全權負責手動配置您正在創建的實例。 實現和配置是完全分離的,您可以更好地控制 Bean 的生成方式。

@Configuration與@Bean 結合使用。 @Bean 與 @Component 相比是一個方法級別的注解,因此通常的情況是一個類用 @Configuration 標記,然后還有一個用 @Bean 注釋的方法在后面。

在您的特定示例中,您創建了一個 @Bean 路由器。 路由器是基於注入到路由中的自動完成和驗證創建的。 Spring 能夠根據最佳匹配候選者確定要注入的內容。 由於您有兩個接口 AutoComplete 的單個實現 bean 實例,因此它會注入它。 在您的情況下, autoComplete 和驗證將指向同一個實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM