简体   繁体   English

通过@Configuration、@Bean 和 @Component 进行 Spring 依赖注入

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

I have been struggling to understand fully how the dependency injection works via @Configuration , @Bean and @Component annotations.我一直在努力通过@Configuration@Bean@Component注释完全理解依赖注入是如何工作的。

My Code is as follows.我的代码如下。

1) Route.kt 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 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 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 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>

}

My question is, how does the route bean created from Route.kt know that the autoComplete and validation should use the ServiceImpl class from ServiceImpl.kt ?我的问题是,如何将route从创建豆Route.kt知道, autoCompletevalidation应使用ServiceImpl类从ServiceImpl.kt

The following description of the Spring mechanism is simplified for you example:以下对 Spring 机制的描述为您简化了示例:

At startup Spring Boot scans the classpath for all classes annotated with @Configuration , @Component , etc and builds a bean definition list.在启动时,Spring Boot 会扫描所有用@Configuration@Component等注释的类的类路径,并构建一个 bean 定义列表。 In your example it finds the Routes and ServiceImpl classes.在您的示例中,它找到了RoutesServiceImpl类。

After this Spring scans all methods of every class in the bean definition list for further @Bean annotations and adds the method (especially the return type) to the bean definition list.在此之后,Spring 会扫描 bean 定义列表中每个类的所有方法以获取进一步的@Bean注释,并将该方法(尤其是返回类型)添加到 bean 定义列表中。 In your example it finds the route method.在您的示例中,它找到了route方法。

After the first scan Spring knows which bean types are present and which bean class implements which interfaces.在第一次扫描之后,Spring 知道存在哪些 bean 类型以及哪个 bean 类实现了哪些接口。 And Spring knows which constructor parameters, Inject targets or method parameters are required to create an instance of the bean. Spring 知道创建 bean 实例需要哪些构造函数参数、 Inject目标或方法参数。 With this information Spring instantiates the beans in the correct order.有了这些信息,Spring 就会以正确的顺序实例化 bean。 In your example Spring knows that Router requires AutoComplete and Validation and that ServiceImpl implements these interfaces.在您的示例中,Spring 知道Router需要AutoCompleteValidation并且ServiceImpl实现了这些接口。 Therefore it has to instantiate ServiceImpl first and Router later.因此它必须先实例化ServiceImpl然后再实例化Router

If more then one bean implements the same interface Spring throws an exception and you have to further qualify the bean.如果不止一个 b​​ean 实现了相同的接口,Spring 将抛出异常,您必须进一步限定该 bean。

I will try to clarify:我将尝试澄清:

@Component - It is tighty bound to the spring auto configuration and component scanning. @Component - 它与 spring 自动配置和组件扫描紧密结合。 Everything marked with Component will be picked up as long as you have it in the path of the component scanning defined by @ComponentScanned annotation.只要在@ComponentScanned 注解定义的组件扫描路径中,所有标有 Component 的东西都会被拾取。 The @Components come into three flavours: @Components 分为三种风格:

A) Repositories - used for persistence A) 存储库 - 用于持久化

B) Controllers for example RestController B) 控制器,例如 RestController

C) Service - a service without state . C) 服务 - 没有状态的服务。 F.ex a Facade. F.ex 一个门面。

This annotation is used to automate the construction of the Application context,as well as to define a stereotype for the bean bound to the context.该注解用于自动构建应用程序上下文,以及为绑定到上下文的 bean 定义构造型。

@Bean - @Bean and @Component have the same goal, but @Bean is not a @Component. @Bean - @Bean 和 @Component 有相同的目标,但 @Bean 不是 @Component。 They both build the application context, but they do it in a very different way.它们都构建了应用程序上下文,但它们以非常不同的方式进行构建。 While @Component defines a stereotype of the class and tells spring to pick it up.而@Component 定义了类的构造型并告诉 spring 选择它。 The Bean has full responsibility of manually configuring the instance of what you are creating. Bean 全权负责手动配置您正在创建的实例。 The implementation and the configuration are fully separated and you receive a higher degree of control on how exactly the Bean is generated.实现和配置是完全分离的,您可以更好地控制 Bean 的生成方式。

@Configuration is used in conjunction with @Bean. @Configuration与@Bean 结合使用。 @Bean in contrast to @Component is a method level annotation therefore the usual case is that a class is marked with @Configuration and then one ro more methods annotated with @Bean are following. @Bean 与 @Component 相比是一个方法级别的注解,因此通常的情况是一个类用 @Configuration 标记,然后还有一个用 @Bean 注释的方法在后面。

In your particular example You have create a @Bean router.在您的特定示例中,您创建了一个 @Bean 路由器。 The router was created based on the autoComplete and validation which were injected in the Routes.路由器是基于注入到路由中的自动完成和验证创建的。 Spring was able to figure out what to inject based on the best matching candidate. Spring 能够根据最佳匹配候选者确定要注入的内容。 Since you have a single implementing bean instance of the two interfaces AutoComplete, Validation it injects it.由于您有两个接口 AutoComplete 的单个实现 bean 实例,因此它会注入它。 In your case autoComplete and validation will point to the same instance.在您的情况下, autoComplete 和验证将指向同一个实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM