簡體   English   中英

micronaut @RequestScope - 不為每個傳入的 http 請求創建 bean

[英]micronaut @RequestScope - not creating bean per incoming http-request

我有一個 class 下面的 class 作為 RequestScope bean:

@RequestScope
class RequestContext {

  private String requestId;
  private String traceId; 
  private String authorisedId; 
  private String routeName; 
    
  // few more fields 

  @Inject RequestContext(SecurityContext securityContext) {
        this.requestId = UUID.randomUUID().toString();
        if(securityService.getAuthentication().isPresent()){
          this.authorisedId = (securityService
                              .getAuthentication().get()).getUserId().toString();
    }
  }
  
  /* to be updated in controller method interceptors */ 
  public void updateRouteName(String name){
      this.routeName = name; 
  }

這個想法是讓 object 包含跨應用程序可訪問的 REST 請求級別自定義數據,顯然 scope 應該在當前請求中。 這可以用於 say.. 日志記錄 - 每當開發人員從應用程序記錄任何內容時,一些請求元數據就會隨之而來。

我不清楚 @RequestScope bean 到底是什么:

根據它的定義——我的假設是它是為每個新的 http 請求創建的,並且在該請求的生命周期內共享相同的實例。

它是什么時候由 Micronaut 構建的? 它是不可變的嗎?

在多個請求中,我可以看到相同的requestId (每個請求都需要新的 UUID)

它是@RequestScope bean 的正確用例嗎?

我遇到了一個關於@RequestScope的問題,所以我會在這里為其他人發布一個答案。

我試圖將@RequestScope bean 注入 HTTP 過濾器,在 bean 中設置一個值,然后稍后從另一個 bean 讀取它。 例如

@RequestScope
class RequestScopeBean() {
    var id: Int? = null
}


@Filter
class SetRequestScopeBeanHere(
    private val requestScopeBean: Provider<RequestScopeBean>
) {

    override fun doFilterOnce(request: HttpRequest<*>, chain: ServerFilterChain): Publisher<MutableHttpResponse<*>> {
        requestScopeBean.get().id = // id from Http Request
    }
}


@Singleton
class GetRequestScopeBeanHere(
    private val requestScopeBean: Provider<RequestScopeBean>
) {

    fun getIdFromRequestScopeBean() {
        println(requestScopeBean.get().id)
    }
}

在這個例子中,在執行任何 controller 之前,我的過濾器( SetRequestScope )被調用,這將設置requestScopeBean.id但關鍵是請求 scope bean 必須包裝在javax.inject.Provider中,否則設置字段將不起作用.

接下來,當調用GetRequestScopeBeanHere::getIdFromRequestScopeBean時,它將可以訪問之前設置的requestScopeBean.id

這是 Micronaut 故意的: https://github.com/micronaut-projects/micronaut-core/issues/1615

它是什么時候由 Micronaut 構建的?

@RequestScope bean 在請求處理期間創建,第一次需要 bean 時。

它是不可變的嗎?

它可能是。 當您編寫 class 時,您可以決定該 bean 是否可變。如示例中所寫, RequestContext是可變的。 如果刪除updateRouteName方法,則該 bean 將是不可變的。

它是@RequestScope bean 的正確用例嗎?

我不這么認為,但這確實是一個基於意見的問題。

編輯:基於下面添加的評論

https://github.com/jeffbrown/rscope查看該項目。

https://github.com/jeffbrown/rscope/blob/2935a4c1fc60f350198d7d3c1dbf9a7eedd333b3/src/main/java/rscope/DemoController.java

package rscope;

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

@Controller("/")
public class DemoController {

    private final DemoBean demoBean;

    public DemoController(DemoBean demoBean) {
        this.demoBean = demoBean;
    }

    @Get("/doit")
    public String doit() {
        return String.format("Bean identity: %d", demoBean.getBeanIdentity());
    }
}

https://github.com/jeffbrown/rscope/blob/2935a4c1fc60f350198d7d3c1dbf9a7eedd333b3/src/main/java/rscope/DemoBean.java

package rscope;

import io.micronaut.runtime.http.scope.RequestScope;

@RequestScope
public class DemoBean {
    public DemoBean() {
    }

    public int getBeanIdentity() {
        return System.identityHashCode(this);
    }
}

https://github.com/jeffbrown/rscope/blob/2935a4c1fc60f350198d7d3c1dbf9a7eedd333b3/src/test/java/rscope/DemoControllerTest.java

package rscope;

import io.micronaut.http.client.RxHttpClient;
import io.micronaut.http.client.annotation.Client;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;

import javax.inject.Inject;

import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

@MicronautTest
public class DemoControllerTest {

    @Inject
    @Client("/")
    RxHttpClient client;

    @Test
    public void testIndex() throws Exception {
        // these will contain the identity of the the DemoBean used to handle these requests
        String firstResponse = client.toBlocking().retrieve("/doit");
        String secondResponse = client.toBlocking().retrieve("/doit");

        assertTrue(firstResponse.matches("^Bean identity: \\d*$"));
        assertTrue(secondResponse.matches("^Bean identity: \\d*$"));

        // if you modify DemoBean to be @Singleton instead of
        // @RequestScope, this will fail because the same instance
        // will be used for both requests
        assertNotEquals(firstResponse, secondResponse);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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