英文:
micronaut @RequestScope - not creating bean per incoming http-request
问题
我有一个类,如下所示的RequestScope bean:
@RequestScope
class RequestContext {
private String requestId;
private String traceId;
private String authorisedId;
private String routeName;
// 其他字段
@Inject RequestContext(SecurityContext securityContext) {
this.requestId = UUID.randomUUID().toString();
if(securityService.getAuthentication().isPresent()){
this.authorisedId = (securityService
.getAuthentication().get()).getUserId().toString();
}
}
/* 在控制器方法拦截器中更新 */
public void updateRouteName(String name){
this.routeName = name;
}
}
这个想法是创建一个对象,其中包含在整个应用程序中可访问的REST请求级别的自定义数据,这个对象的范围显然应该限定在当前请求内。例如,这可以用于日志记录 - 每当开发人员从应用程序记录任何内容时,一些请求的元数据也会随之传递。
我不清楚@RequestScope
bean 到底是什么:
从其定义中 - 我的假设是它会在每个新的http请求中被创建,并且相同的实例会在该请求的生命周期内共享。
Micronaut 何时构造它?它是不可变的吗?
在多个请求之间,我可以看到相同的 requestId(预期每个请求都会有一个新的UUID)。
这是否是使用@RequestScope
bean的正确用例?
英文:
I have a class the following class as 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;
}
The idea is to have an object containing the REST request level custom data accessible across the application, the scope of the this obviously should be within the current request. This can be used for say.. logging - whenever devs log anything from the application, some of the request meta data goes with it.
I am not clear what the @RequestScope bean really is:
From its definition - my assumption is it is created for every new http-request and same instance is shared for the life of that request.
when is it constructed by Micronaut ? Is it immutable ?
Across multiple requests I can see the same requestId ( expecting new UUID for every request)
Is it the right use-case for @RequestScope bean?
答案1
得分: 3
我遇到了关于@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 = // 从Http请求获取的id
}
}
@Singleton
class GetRequestScopeBeanHere(
private val requestScopeBean: Provider<RequestScopeBean>
) {
fun getIdFromRequestScopeBean() {
println(requestScopeBean.get().id)
}
}
在这个示例中,在执行任何控制器之前,我的过滤器(SetRequestScope
)被调用,这将设置requestScopeBean.id
,但关键是请求作用域bean必须包装在javax.inject.Provider
中,否则设置字段不起作用。
在后续操作中,当调用GetRequestScopeBeanHere::getIdFromRequestScopeBean
时,它将可以访问之前设置的requestScopeBean.id
。
这是Micronaut的意图:
https://github.com/micronaut-projects/micronaut-core/issues/1615
英文:
I was running into an issue regarding @RequestScope
so I'll post an answer here for others.
I was trying to inject a @RequestScope
bean into an HTTP filter, set a value in the bean, and then read it later from another bean. For example
@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)
}
}
In this example before any controller is executed my filter (SetRequestScope
) is called, this will set requestScopeBean.id
but the key is that the request scope bean must be wrapped in a javax.inject.Provider
, otherwise setting the field won't work.
Down the line, when GetRequestScopeBeanHere::getIdFromRequestScopeBean
is called it'll have access to the requestScopeBean.id
set earlier
This is intentional by Micronaut:
https://github.com/micronaut-projects/micronaut-core/issues/1615
答案2
得分: 1
> 何时由Micronaut构造?
@RequestScope
的bean是在请求处理过程中创建的,在第一次需要该bean时。
> 它是不可变的吗?
可以是。当你编写类时,你可以决定bean是否可变。如你的示例中所写,RequestContext
是可变的。如果删除updateRouteName
方法,该bean将是不可变的。
> 这是使用@RequestScope
bean的正确用例吗?
我认为不是,但这实际上是一个基于观点的问题。
编辑:基于下面的评论添加
请查看项目:https://github.com/jeffbrown/rscope。
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());
}
}
package rscope;
import io.micronaut.runtime.http.scope.RequestScope;
@RequestScope
public class DemoBean {
public DemoBean() {
}
public int getBeanIdentity() {
return System.identityHashCode(this);
}
}
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 {
// 这些将包含处理这些请求的DemoBean的标识
String firstResponse = client.toBlocking().retrieve("/doit");
String secondResponse = client.toBlocking().retrieve("/doit");
assertTrue(firstResponse.matches("^Bean identity: \\d*$"));
assertTrue(secondResponse.matches("^Bean identity: \\d*$"));
// 如果将DemoBean修改为@Singleton而不是
// @RequestScope,这将失败,因为相同的实例
// 将用于两个请求
assertNotEquals(firstResponse, secondResponse);
}
}
英文:
> when is it constructed by Micronaut ?
A @RequestScope
bean is created during request processing, the first time the bean is needed.
> Is it immutable ?
It could be. You get to decide if the bean is mutable or not when you write the class. As written in your example, RequestContext
is mutable. If you remove the updateRouteName
method, that bean would be immutable.
> Is it the right use-case for @RequestScope bean?
I don't think so, but that is really an opinion based question.
EDIT: Based On Comments Added Below
See the project at https://github.com/jeffbrown/rscope.
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());
}
}
package rscope;
import io.micronaut.runtime.http.scope.RequestScope;
@RequestScope
public class DemoBean {
public DemoBean() {
}
public int getBeanIdentity() {
return System.identityHashCode(this);
}
}
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);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论