1

我有一个以下类作为 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; 
  }

这个想法是让一个对象包含跨应用程序可访问的 REST 请求级别的自定义数据,this 的范围显然应该在当前请求内。这可以用于说.. 日志记录 - 每当开发人员从应用程序记录任何内容时,一些请求元数据都会随之而来。

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

从它的定义来看 - 我的假设是它是为每个新的 http 请求创建的,并且在该请求的生命周期内共享相同的实例。

Micronaut 什么时候建造的?它是不可变的吗?

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

@RequestScope bean 的用例是否正确?

4

2 回答 2

1

Micronaut 什么时候建造的?

在请求处理期间创建一个@RequestScopebean,第一次需要该 bean。

它是不可变的吗?

它可能是。在编写类时,您可以决定 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);
    }
}
于 2020-09-01T17:26:15.450 回答
1

我遇到了一个问题,@RequestScope所以我会在这里为其他人发布答案。

我试图将@RequestScopebean 注入 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)
    }
}

在此示例中,在执行任何控制器之前,我的过滤器 ( SetRequestScope) 被调用,这将设置requestScopeBean.id但关键是请求范围 bean 必须包装在 a 中javax.inject.Provider,否则设置字段将不起作用。

下线,当GetRequestScopeBeanHere::getIdFromRequestScopeBean被调用时,它将requestScopeBean.id更早地访问集合

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

于 2021-08-26T19:23:31.337 回答