通过@ Configuration,@ Bean和@Component

时间:2019-07-04 02:31:33

标签: spring spring-boot kotlin spring-webflux

我一直在努力通过@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 bean如何知道autoCompletevalidation应该使用{{1 }}?

2 个答案:

答案 0 :(得分:1)

为您的示例简化了以下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

如果再有一个bean实现相同的接口,则Spring会引发异常,并且您必须进一步限定bean。

答案 1 :(得分:1)

我将尝试澄清:

@Component -与spring自动配置和组件扫描紧密绑定。只要您在@ComponentScanned注释定义的组件扫描路径中将所有带有Component的内容都将被拾取。 @Components具有三种风味:

A)存储库-用于持久性

B)控制器,例如RestController

C)服务-没有状态的服务。 F.ex a Facade。

此批注用于自动构建Application上下文,并为绑定到上下文的bean定义构造型。

@Bean -@Bean和@Component具有相同的目标,但是@Bean不是@Component。他们都构建了应用程序上下文,但是它们以非常不同的方式来实现。 @Component定义了类的构造型,并告诉spring进行选择。 Bean完全负责手动配置要创建的实例。实现和配置完全分开,您可以更好地控制Bean的生成方式。

@Configuration 与@Bean结合使用。 @Bean与@Component相反,是方法级别的注释,因此,通常的情况是用@Configuration标记一个类,然后再跟随一个用@Bean注释的其他方法。

在您的特定示例中 您已经创建了一个@Bean路由器。路由器是根据注入到路由中的自动完成和验证创建的。 Spring能够根据最佳匹配候选者找出要注入的内容。由于您具有两个自动完成接口的单个​​实现Bean实例,因此Validation会将其注入。在您的情况下,自动完成和验证将指向同一实例。