如何使用 CDI 使单例实例随处可见?

How to make an singleton instance visible everywhere using CDI?

我有申请。每个用户对应实体"Client"。在会话期间,用户使用他的实体。

我有 JAX-RS + EJB 应用程序。我希望这个实体在所有服务中都可见并作为一个单例使用。我想用CDI来实现。

首先,用户登录到应用程序。登录后,我想从base中获取它的entity,并赋值给一个singleton,但是没有成功。我尝试了 @Singleton 注释(javax.inject)、@SessionScoped@ApplicationScoped

我该怎么做?

//Entity
@Entity
@SessionScope //or @Singlton/@ApplicationScope
class Client { fields }

//login service
@Inject 
Client client;
//After login I want to assign an entity from db[cleintEntity] 
//to entity which is available everywhere[client]
client = clientEntity;

我想这样做:

//some ejb
@Inject
Client client;
//use entity

我不想在整个应用程序中将 link 传输到实例,但我希望它在使用 CDI 的任何地方都可用。

或者我是否需要创建一个单独的 ClientDAO,这将是我的单身人士?

根据您的评论,您必须使用 @SessionScope。如果您想为所有用户使用一个实例,则可以使用 @Singleton@ApplicationScope

解决您的问题:

  1. 你想在用户登录时实例化Client。所以当你在登录服务时,这个对象还没有实例化,所以你不能@Inject 它进入您的登录服务,您应该记得删除 @Inject 注释。

  2. 您需要使用@Produces注解。当您想控制实例化 class 的方式时使用此注释。当 CDI 容器要查找 Client class 的实现时,如果它找到 returns Client 并且具有 @Produces 注释的方法,它会调用该方法而不是仅仅实例化 Client 本身。你应该做你的登录业务,然后创建一个 Client 的实例并将它作为成员变量存储在你的登录服务中。然后在这个class which returns that client object中添加一个方法,并用@Produces注释该方法。您的登录服务的最终结构将如下所示:

    @SessionScope
    public class LoginService {
        private Client client;

        public void login(String username, String password) {
            //  implement login business

            //  if login is successful
            client = clientEntity;
        }

        @Produces
        @SessionScope
        public Client clientProducer() {
            return this.client;
        }
    }

您还可以将 @Produces 注释放在字段顶部。在这种情况下,CDI 容器将使用存储在该字段上的值而不是调用方法。

    @SessionScope
    public class LoginService {
        @Produces
        @SessionScope
        private Client client;

        public void login(String username, String password) {
            //  implement login business

            //  if login is successful
            client = clientEntity;
        }
    }

当然这应该被认为是一种伪代码。我不知道你们公司的所有细节。也许您实现逻辑的方式是完全错误的;)。但是要解决这个具体问题,@Produces 应该可以。