簡體   English   中英

在@Stateless 中注入@RequestScoped

[英]Inject @RequestScoped inside @Stateless

我正在嘗試在無狀態 object 中注入依賴於 object 的客戶端。我確實做到了,但我不確定它是如何工作的以及為什么工作,因為我不完全理解 JavaEE 依賴注入。 我有 3 個相關課程

  • BookmarkRepository - 從數據庫中獲取數據
  • RequestData - 我可能需要的用戶請求的所有相關信息
  • BookmarkEndpoint - REST 端點

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

我的問題:

  • @Inject 是否在每次調用 BookmarkEndpoint 的方法時觸發? 我雖然 @Inject 僅在首次創建 object 時觸發,但正如我們在 output 中看到的那樣,我們似乎正在處理相同的 object 並且每次調用它的方法時都會注入新的 RequestData object
  • 是否有可能兩個 HTTP 調用在同一時間獲得相同的@Statless object,然后一個客戶端的 RequestData 將因另一個客戶端 RequestData 而被壓縮
  • @Statless 什么時候創建,什么時候銷毀? 我看過很多主題,其中說“需要時創建”和“不需要時銷毀”。 那個的真實意義是什么。 如果我們信任我的 output 那么我的@Statless object 總是在 memory
  • BookmarkRepository 真的應該是 @Statless 因為我顯然有一個 state 對每個客戶端都是唯一的

在非常重要的一點上,您的問題丟失了:

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.

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