使用 CDI 将 Logger 注入 Ejb

Posted

技术标签:

【中文标题】使用 CDI 将 Logger 注入 Ejb【英文标题】:Injecting a Logger into an Ejb using CDI 【发布时间】:2012-10-21 06:24:45 【问题描述】:

我很难将我认为是一项简单的任务放在一起。 我有一个无状态单例 Bean,我将把它用作我的应用程序的“加载器”。 bean 包含在一个 Jar (loader.jar) 文件中,并位于我的 EAR 的 lib 文件夹中。

在 EAR 的根目录中存在另一个 jar,其中包含将由我的应用程序使用的无状态会话 Bean 的实现。

然后我创建了一个小型记录器类,它实际上包装了 log4j:



    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    import javax.enterprise.context.RequestScoped;
    import javax.enterprise.inject.Produces;
    import javax.enterprise.inject.spi.InjectionPoint;
    import javax.inject.Named;

    import org.apache.log4j.Logger;

    public class LoggerFactory 
        private Logger logger;

        public LoggerFactory()
            logger = Logger.getLogger(this.getClass().getName());
        

        @Produces Logger getLogger(InjectionPoint caller)
            return Logger.getLogger(caller.getMember().getDeclaringClass().getName());
        
    

然后我把它放在一个罐子里,我把它命名为 utils.jar。在这个 jar 中,按照 CDI 规范,我在 META-INF 文件夹中创建了一个空 beans.xml 文件。 utils.jar 位于我的 EAR 的 lib 文件夹中。

现在,在我之前提到的无状态 Singleton Bean(加载器)中

我只写了这个



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

    import org.apache.log4j.Logger;

    @Startup
    @Singleton
    public class Core 
        @Inject 
        private Logger logger;

        @PostConstruct
        void init()
            logger.info("Core started");
        
    

当我在 glassfish 3.1.2 上部署我的应用程序时,我在 Loader bean 中第一次调用 logger 时得到一个普通的 NPE。这让我认为 CDI 调用根本没有发生,但我真诚地无法理解我做错了什么。

目前我的EAR结构如下:



       EAR
         |
         +---lib
         |     +--loader.jar
         |     +--utils.jar
         |     +--log4j.xx.jar
         |
         +--MyStatelessSessionBean.jar

非常感谢您的帮助

【问题讨论】:

【参考方案1】:

您的文本和您的 EAR 结构之间存在一些不一致,即您谈论的是 utils.jar,但您的 EAR 结构图中没有这样的 .jar。

尽管如此,您提到您的@EJB 被打包在loader.jar 中,而loader.jar 又位于您EAR 的/lib 文件夹中。由于loader.jar 是您的ejb-jar,因此它不应位于/lib 之下,而应位于您EAR 的顶层。

application.xml

<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" version="6">
    <module>
        <ejb>loader.jar</ejb>
    </module>
    ...
    <library-directory>lib</library-directory>
</application>

希望这能解决您的问题。

【讨论】:

谢谢,我马上更新了问题。实际上,我将拥有两个 EJB,一个无状态会话 bean (MyStatelessSessionBean.jar) 和我的单例无状态 bean (loader.jar)。我将尝试尝试此设置并尽快发回此处。非常感谢您的帮助! 真正解决问题的方法是将我的加载器打包到一个动态 Web 应用程序中(从而将其移动到 EAR 根级别)并将我的 utils.jar 库留在 EAR/lib 文件夹中。实际上 application.xml 是可选的,为了简单起见,我暂时不考虑它。我将尝试创建一个 jar 打包的加载器,但目前我将继续使用 war 打包的加载器。感谢您的支持! 任何一种存档类型都应该可以工作,你说得对,application.xml 是可选的。很高兴它有所帮助。

以上是关于使用 CDI 将 Logger 注入 Ejb的主要内容,如果未能解决你的问题,请参考以下文章

EJB 的 CDI 生产者

我可以使用带有 CDI 的 EJB 无状态 Bean 来维护用户会话吗?

CDI Features

JSF、CDI 和 EJB 容器:应该使用它们的哪种组合?

如何使用 CDI 进行方法参数注入?

我是不是还需要在 CDI bean 上使用 EJB @Clustered 来进行分布式应用程序