在EJB 3.1中控制CDI启动

6

我是新手,也是CDI世界的新手,在工作中我得到的第一个任务是找出一种控制CDI上传的方法。

我们同时使用了 EJB 3.1CDI 1.0,因为它们由不同的容器控制,所以我们可以使用 @Startup@Singleton 注解来控制 EJB 管理的 Bean 的上升顺序。

但是,我在类中声明的 @Inject CDI bean 却是 null,因为 CDI 容器尚未启动。

我已经试了好几天了,寻找解决方案,但我在这里找到的一个解决方案(链接)仍然是 null。

我们使用的是 Java EE 6,并在 WebSphere Application Server 8 上运行应用程序。

请问,如果您能帮助我找到一种无论 EJB 如何都能控制 CDI 上传的方法,那就太好了。

以下是示例代码:

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;

@Singleton
@Startup
public class BaseStartupLoader{


/**
 * Default constructor. 
 */
@Inject @MyStartup
BaseStartUp myStartup;

private static Logger m_logger = LoggerFactory.getLogger(BaseStartupLoader.class);
public BaseStartupLoader() {

}

@PostConstruct
public void init(){

    String applicationName = null;

    try {

            applicationName = myStartup.getClass().getName();
            myStartup.load();

    } catch (IllegalAccessException e) {
        m_logger.error("Faild to load data into preload system. "+e);               
    } catch (InstantiationException e) {
        m_logger.error("Faild to load data into preload system. "+e);               
    } catch (ClassNotFoundException e) {
        m_logger.error("Faild to load data into preload system - Class "+ applicationName + "Not found. "+e);               
    }
  }
}

这里是BaseStartup接口:

public interface BaseStartUp {
public void load() throws IllegalAccessException, InstantiationException, ClassNotFoundException;
}  

资格和实现:

@Retention(RetentionPolicy.RUNTIME)
@Target ({ElementType.PARAMETER, ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
@Qualifier 
@Dependent
public @interface MyStartup {   
}


@MyStartup
public class MyStartUpLoader implements BaseStartUp {

    @Inject
    SomeConfigLoader config;

    @Override
    public void load() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
    conifg.init();      
}   
}

你能添加一些示例代码来说明吗? - Aksel Willgert
我已经编辑了问题并添加了代码示例。 - tomerne
只是好奇,'受控上传'与问题的其他部分有什么关系? - Mike Braun
我正在尝试控制CDI的起始点。我使用“上传”一词来描述容器在服务器启动时的起始点。 - tomerne
3个回答

5
经过大量研究,我从IBM的人那里得到了一些帮助,因为我们正在使用WebSphere应用服务器,所以我可以在管理控制台中添加一个称为:"com.ibm.ws.cdi.immediate.ejb.start" = true 的JVM属性,并确保一旦我到达我创建的@Startup bean中的EJB @PostConstruct方法,CDI容器就已经启动并注入了。它起作用了!以下是IBM网站上的问题和解决方案链接:http://www-01.ibm.com/support/docview.wss?uid=swg1PM62774

请注意,这会更改类加载器的某些内容,导致 JPA 提供程序从 Eclipse Link 更改为 OpenJPA(在 WebSphere 8.5.5.4 下找到)。 - Pool

3

也许需要仔细检查应用程序中所有需要启用CDI的地方是否已经启用了CDI。尝试将以下代码添加到BaseStartupLoader中进行实验:

@Singleton
@Startup
public class BaseStartupLoader {

    @Inject @MyStartup
    BaseStartUp myStartup;

    @Inject
    private InjectionTest test;


    public static class InjectionTest {}
}

如果在@PostConstruct中,test变量的值为null,则很可能是BaseStartupLoader所在的jar包未启用CDI(上下文和依赖注入)。例如,如果BaseStartupLoader位于名为orange.jar的jar包中,而MyStartUpLoader位于名为yellow.jar的jar包中,则这两个文件必须同时存在:
  • orange.jar!/META-INF/beans.xml
  • yellow.jar!/META-INF/beans.xml
如果通过META-INF/beans.xml正确启用了两个jar包中的CDI,那么这可能是容器的一个错误。在启用CDI的jar包中,在调用@PostConstruct之前,所有@Inject点都需要被完成。这一点不论是否使用@Startup,并且其中一个bean恰好是EJB,都是必须遵守的规则。

静态内部类注入是一个很棒的技巧!感谢分享这个提示。 - Mike Braun
谢谢您的快速回复,我已经完成了您的测试,确实在@PostConstruct中变量为空,此外,jars文件存在于META-INF/beans.xml中,但真正的问题是CDI容器尚未初始化,而EJB容器已经启动,我在网上找到了一个解决方案-使用start-on-load Servlet来强制先启动CDI容器再启动EJB。但这个解决方案对我们来说不好(我们不想在后端使用WAR文件)。如果有人有其他想法,我很乐意听取建议... - tomerne

0

看看DeltaSpike。有一个CDI控制模块,现在应该可以做到你想要的。我相信Java EE 7也会解决这个问题。


你没看错,我发现这个问题将在CDI 1.1版本中得到解决,但是我仍然很惊讶地发现除了Servlet的load-on-startup方法之外没有其他有效的解决方案。 - tomerne

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