我一直在努力通过@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如何知道autoComplete
和validation
应该使用{{1 }}?
答案 0 :(得分:1)
为您的示例简化了以下Spring机制的描述:
在启动时,Spring Boot会扫描类路径以查找所有用@Configuration
,@Component
等注释的类,并构建一个bean定义列表。在您的示例中,它找到了Routes
和ServiceImpl
类。
在此Spring之后,将扫描Bean定义列表中每个类的所有方法以获取更多的@Bean
注释,并将该方法(尤其是返回类型)添加到Bean定义列表中。在您的示例中,它找到了route
方法。
第一次扫描后,Spring会知道存在哪些bean类型以及哪些bean类实现哪些接口。而且Spring知道创建bean实例需要哪些构造函数参数,Inject
目标或方法参数。 Spring使用此信息以正确的顺序实例化bean。
在您的示例中,Spring知道Router
需要AutoComplete
和Validation
,并且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会将其注入。在您的情况下,自动完成和验证将指向同一实例。