[英]Inject @RequestScoped inside @Stateless
我正在嘗試在無狀態 object 中注入依賴於 object 的客戶端。我確實做到了,但我不確定它是如何工作的以及為什么工作,因為我不完全理解 JavaEE 依賴注入。 我有 3 個相關課程
import java.util.UUID;
import javax.enterprise.context.RequestScoped;
@RequestScoped
public class RequestData {
private final UUID correlationId;
public RequestData() {
correlationId = UUID.randomUUID();
}
public UUID getCorrelationId() {
return correlationId;
}
}
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
public class BookmarkRepository {
@PersistenceContext
private EntityManager em;
@Inject
RequestData requestData;
@Override
public String test() {
StringBuilder sb = new StringBuilder();
String objectid = Integer.toString(System.identityHashCode(this));
String correlationId = requestData.getCorrelationId().toString();
sb.append(correlationId);
sb.append(" OBJECT ID: " + objectid);
return sb.toString();
}
}
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path("bookmarks")
public class BookmarkEndpoint {
@Inject
private BookmarkRepository bookmarkRepository;
@Inject
private RequestData requestData;
@GET
@Path("/test")
@Produces(MediaType.TEXT_PLAIN)
public Response testEndpoint() {
String outerCorelationId = requestData.getCorrelationId().toString();
sb.append(outerCorelationId);
String innerCorelationId1 = bookmarkRepository.test();
sb.append("\n" + innerCorelationId1);
String innerCorelationId2 = bookmarkRepository.test();
sb.append("\n" + innerCorelationId2);
return ResponseBuilder.createOkResponse(Response.Status.OK, finalMessage);
}
}
Output 當我用 2 個 HTTP 調用調用程序時
FIRST HTTP CALL
ba4ac8b9-8e3b-4632-9c5e-89fe9b6f2cc5
ba4ac8b9-8e3b-4632-9c5e-89fe9b6f2cc5 OBJECT ID: 717717270
ba4ac8b9-8e3b-4632-9c5e-89fe9b6f2cc5 OBJECT ID: 717717270
SECOND HTTP CALL
9f563047-3d8f-48f5-849d-9a0bf1df46ae
9f563047-3d8f-48f5-849d-9a0bf1df46ae OBJECT ID: 717717270
9f563047-3d8f-48f5-849d-9a0bf1df46ae OBJECT ID: 717717270
我的問題:
在非常重要的一點上,您的問題丟失了:
CDI 注入一個代理,就像一個路由器。 它不會注入實際的 object。如果您在getCorrelationId()
中放置一個斷點並查看堆棧跟蹤,您會看到有一個堆棧幀,其中某個時刻調用了 CDI 代理。
為什么這很重要?
這允許創建程序,其中 RequestScoped bean 可以注入 SessionScoped bean,反之亦然。 當調用代理上的 function 時,容器會將您路由到 class 的正確實例。 它從字面上查找並將 function 呼叫發送到正確的位置!
所以要回答你的問題:
@Inject 是否在每次調用 BookmarkEndpoint 的方法時觸發?
兩者都不。 @Inject
只是一個注解。 BookmarkEndpoint
注入了BookmarkRepository
的代理,它是BookmarkRepository
的子類,CDI 框架在運行時定義了這個子類。 BookmarkRepository
是一個無狀態的 EJB,因此它將有一個實例池。 代理將從池中挑選一個實例並調用它的方法。 由於BookmarkEndpoint
上沒有 CDI scope,我相信每個請求都會重新創建它(不要引用我的話,使用調試器)。 我們通常在所有 JAX-RS bean 上@ApplicationScoped
作為優化。
是否有可能兩個 HTTP 調用在同一時間獲得相同的@Statless object,然后一個客戶端的 RequestData 將因另一個客戶端 RequestData 而被壓縮
不。相反,無狀態 bean 被合並。 如果池中有可用的 bean,將同時處理兩個請求。 如果沒有可用的 bean,請求將阻塞,直到有一個實例可用。 池大小和超時是可調的,並且是容器特定的設置。
@Statless 什么時候創建,什么時候銷毀?
簡短的故事:bean 池在啟動時創建並在關閉時銷毀,除非您從 bean 中拋出異常,否則該實例將被銷毀。 完整解釋見這里: https://docs.oracle.com/javaee/6/tutorial/doc/giplj.html
BookmarkRepository 真的應該是 @Statless
@Stateless
絕對有效,但這不是必需的:你真的不需要池來做任何事情。 @Singleton @Lock(LockType.Read)
會更合適。 最好的是@ApplicationScoped @Transactional(TxType.Required)
因為它完全避免了 EJB
因為我顯然有一個 state 對每個客戶都是唯一的
你這樣做......但不是你想的那樣:記住以下是代理:
@Inject
RequestData requestData;
它會將您路由到綁定到當前請求的 bean 實例。 您的“狀態”由容器保存。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.