CDI是传递服务的最佳方式

3

我有几个类似的服务:

@Singleton
public SimpleService {
    ...
}

我有一个@ViewScoped的Managed Bean,应该创建一些复杂的对象。这些对象应该执行业务逻辑。我需要将这些服务传递给这个对象。

Managed Bean示例:

@ManagedBean
@ViewScoped
public class ExampleBean {
    @Inject
    private SimpleService simpleService;

    ...
    public void customLogic() {
        // in this method I should create complex object which should have services and some data.
        // current implementation
        ComplexObject object = new ComplexObject(SimpleService simpleService, ...)
    }
}

使用 @Inject 注解将服务注入到托管的 Bean 中。为了创建这些对象,我使用构造函数并将这些服务作为参数传递。问题是:是否有更好的解决方案,而不是在构造函数中传递服务?


在IoC环境中,您必须将数据与服务分离。您需要具有可注入组件来“构建”您的数据。 - maress
你使用注入的方式不太清楚,请问能否贴出相关代码部分? - prmottajr
@maress,谢谢,我会检查一下我的逻辑来创建可注入组件。 - TestName
@prmottajr 对于向托管Bean注入服务,我有以下代码: 托管Bean public class ManagedBean {Inject SimpleService service;} - TestName
1
@Трубецкой 使用inject应该就足够了,这就是使用CDI的目的,你不需要将这些对象传递给构造函数,如果你能编辑问题并添加用于传递参数的代码,那么帮助你会更容易。 - prmottajr
@prmottajr,我编辑了这个问题。 - TestName
2个回答

3

你可以:

  • 通过方法注入:
    private MyService myService;
@Inject public void setMyService(MyService ms) { this.myService = ms; }
  • 通过字段注入:
    @Inject
    private MyService myService;   
  • 通过 CDI 获取引用(不推荐,除非在高级用例中):
    ...
    MyService myService = CDI.current().select(MyService.class).get();
    ...
  • 通过 BeanManager 获取引用(不推荐,除非在高级用例或 CDI 1.0 中):
    ...
    BeanManager beanManager = CDI.getBeanManager(); // 你可以通过其他几种方法获取 BeanManager 引用,这里我使用 CDI 简化了操作
    MyService myService = beanManager.getReference(MyService.class);
    ...
  • 如果您的@Singleton注释是javax.ejb.Singleton而不是javax.inject.Singleton,那么您的bean实际上是一个EJB,您也可以使用任何允许您访问EJB的机制,例如@Resource注释或通过JNDI上下文。

个人而言,我倾向于通过方法注入,因为我发现这通常是最灵活的选项。在我看来,它也是最“可移植”的到其他框架(例如:Spring)

请记住,当您使用CDI.current()BeanManager方法获取@Dependentbean时,您需要负责在完成后手动销毁获取的bean,以避免this CDI-related memory leak。使用CDI.current()很容易,只需保存Instance引用并在之后调用即可:

...
Instance<MyService> msInstance = CDI.current().select(MyService.class);
MyService myService = msInstance.get();
...
msInstance.destroy(myService);
...

BeanManager 方法过于底层,只应在 CDI 1.0 环境中使用(当时还不存在 CDI 类)。您可以阅读链接的 StackOverflow 问题了解更多详情。


1
请注意,当使用方法进行注入时,您不仅限于单个参数的方法,您还可以使用多个参数的方法一次性注入多个 bean。 - gpeche
@Трубецкой 在编辑问题后,我发现我的答案实际上有点离题。供您参考,prmottajr的答案看起来很合适。 - gpeche

2
你所做的是完全正确的。你使用ManagedBean作为桥梁来注入服务,然后将注入的变量传递给需要服务的ComplexObject。
唯一需要考虑的限制是,ComplexObject类是否可以成为一个ManagedBean本身?这样你就可以直接在它上面注入所有东西了,但如果不可能,你可以使用bean来实现。
我更喜欢提到的按字段注入选项,因为我认为它更易读。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接