簡體   English   中英

根據 Spring 中的 @Scope 動態地 @Autowire bean

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM