[英]Dynamically @Autowire bean depending on the @Scope in Spring
我有一個緩存響應的服務。 我使用一個簡單的 Map 來緩存響應。
我也有兩個范圍: @RequestScope
和@GrpcScope
。 @RequestScope
顯然是針對從 rest controller 收到的請求,而@GrpcScope
是針對 grpc 請求的。 我的服務不知道它當前正在運行什么 scope。兩個(grpc 和 rest)控制器都使用相同的服務,並且在運行時可能只有一個 scope 處於活動狀態。
如果 scope 是@RequestScope
,我希望FooService
使用RequestScopedFooCache
,如果 scope 是@GrpcScope
GrpcScopedFooCache
我怎樣才能做到這一點?
// for RequestScope
@RestController
public class FooRestController{
@Autowired
FooService fooService;
@GetMapping
public BarResponse getFoo(){
return fooService.fooRequest(...)
}
}
// for @GrpcScope
@GrpcController
public class FooGrpcController{
@Autowired
FooService fooService;
public BarResponse getFoo(){
return fooService.fooRequest(...)
}
}
@Service
public class FooService {
@Autowired
FooCache cache; // doesn't know which bean to autowire however there could be only one of them at runtime
BarResponse fooRequest(String id) {
if(cache.get(id))
...
}
}
public interface FooCache {
...
}
@Component
@RequestScope
public class RequestScopedFooCache implements FooCache {
...
}
@Component
@GrpcScope
public class GrpcScopedFooCache implements FooCache {
...
}
使用 SpringBoot 2.4.+ 版本
不完全是您所要求的,但我可能會為 FooService 創建自己的 bean 方法並為它們提供限定名稱。
更改 FooService 以將 FooCache 作為構造函數:
public class FooService {
private final FooCache cache;
public FooService(FooCache cache) {
this.cache = cache;
}
BarResponse fooRequest(String id) {
if (cache.get(id))
...
}
}
給 FooCache 實現限定名稱:
public interface FooCache {
...
}
@Component("GRPC_CACHE")
@RequestScope
public class RequestScopedFooCache implements FooCache {
...
}
@Component("REQUEST_CACHE")
@GrpcScope
public class GrpcScopedFooCache implements FooCache {
...
}
用於設置 FooService bean 的 bean 管理器:
class FooServiceBeanManager {
@Bean("GRPC_SERVICE")
public FooService grpcFooService(@Qualifier("GRPC_CACHE") FooCache fooCache) {
return new FooService(fooCache);
}
@Bean("REQUEST_SERVICE")
public FooService requestFooService(@Qualifier("GRPC_CACHE") FooCache fooCache) {
return new FooService(fooCache);
}
}
使用@Qualifer
指定您想要在控制器中使用的 bean:
// for RequestScope
@RestController
public class FooRestController {
private final FooService fooService;
@Autowired
public FooRestController(@Qualifier("REQUEST_SERVICE") FooService fooService) {
this.fooService = fooService;
}
@GetMapping
public BarResponse getFoo() {
return fooService.fooRequest(...)
}
}
// for @GrpcScope
@GrpcController
public class FooGrpcController {
private final FooService fooService;
@Autowired
public FooGrpcController(@Qualifier("GRPC_SERVICE") FooService fooService) {
this.fooService = fooService;
}
public BarResponse getFoo() {
return fooService.fooRequest(...)
}
}
我將 controller 類更改為具有@Autowired
構造函數而不是字段。 這是推薦的用法(來源: Spring @Autowire on Properties vs Constructor )
我個人也更喜歡盡可能擁有自己的@Bean
方法,因為它給了我更多的控制權。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.