繁体   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