6

我正在使用 logback/slf4j 来处理我的应用程序中的日志记录。在我开始使用 EJB 之前,一切都运行良好。一旦我将无状态 EJB 添加到我的应用程序中,记录器就会开始忽略我的 logback.xml 并停止使用我的附加程序。我切换到编程记录器配置以查看问题所在,现在当我尝试在 EJB 中使用记录器时出现以下错误:

org.slf4j.impl.JDK14LoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext

源于以下行:

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();

是否需要任何特殊配置才能让 logback 与 EJB 一起使用?如果重要的话,我将部署在 glassfish v3 上。

4

4 回答 4

9

这看起来非常接近此线程中描述的问题,我怀疑存在类似的类加载问题。由于 logback 加载的方式logback.xml(更准确地说是它检索 a 的方式ClassLoader),它可能无法获取其配置文件并回退到 default BasicConfiguration

不确定如何打包代码,但建议的解决方法是将其包含logback.xml在 EAR 库中。如果您没有使用 EAR 打包,请尝试识别用于查看logback.xml文件放置位置的类加载器。

最后,这可能是 logback 中的问题。虽然没有检查他们的问题跟踪器。

更新:如果您使用战争包装,请尝试将 GlassFish 配置为在委托之前首先使用子类加载器。在sun-web.xml

<sun-web-app>
  <class-loader delegate="false"/>
</sun-web-app>


更新:我在我这边做了一个小测试......我无法重现你的问题。我为具有以下结构的 Java EE 6 webapp 创建了一个项目:

$ 树样本
样本
|-- pom.xml
`--src
    `--主要
        |-- 爪哇
        | `--com
        | `-- 堆栈溢出
        | `--q2418355
        | |-- SimpleEJB.java
        | `-- SimpleServlet.java
        |-- 资源
        | `--logback.xml
        `-- 网络应用
            |-- 元信息
            | `--清单.MF
            |-- 网络信息
            | `--库
            `-- index.jsp

我的 pom.xml 看起来像:

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
  xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.stackoverflow.q2418355</groupId>
  <artifactId>sample</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>sample Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-api</artifactId>
      <version>6.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.7</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>0.9.18</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.5.11</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.0.2</version>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.1-beta-1</version>
        <configuration>
          <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
      </plugin>
    </plugins>
    <finalName>sample</finalName>
  </build>
</project>

的代码SimpleEJB.java是:

package com.stackoverflow.q2418355;

import javax.ejb.Stateless;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Stateless
public class SimpleEJB {
    private static Logger logger = LoggerFactory.getLogger(SimpleEJB.class);

    public String sayHello(String name) {
        logger.debug(">> sayHello()");
        logger.debug("<< sayHello()");
        return "Hello " + name + "!!!";
    }
}

的代码SimpleServlet.java是:

package com.stackoverflow.q2418355;

import java.io.IOException;
import java.io.PrintWriter;

import javax.ejb.EJB;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = { "/SimpleServlet" })
public class SimpleServlet extends HttpServlet {
    @EJB
    SimpleEJB bean;

    private static Logger logger = LoggerFactory.getLogger(SimpleServlet.class);

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        logger.debug(">> doGet()");
        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("<h2>Serving at: " + request.getContextPath() + "</h2>");
        out.println("<h2>Invoking EJB: " + bean.sayHello("Duke") + "</h2>");
        out.println("</body></html>");
        logger.debug("<< doGet()");
    }
}

的代码index.jsp是:

<html>
<body>
<h2>Hello World!</h2>
Invoke the Servlet by clicking <a href="SimpleServlet">here</a>.
</body>
</html>

我的logback.xml样子:

<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <layout class="ch.qos.logback.classic.PatternLayout">
      <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
    </layout>
  </appender>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <File>/tmp/logs/testFile.log</File>
    <Append>true</Append>

    <layout class="ch.qos.logback.classic.PatternLayout">
      <Pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</Pattern>
    </layout>
  </appender>

  <logger name="com.stackoverflow.q2418355" level="TRACE"/>

  <root level="debug">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="FILE" />
  </root>
</configuration>

在调用 servlet 时,我logback.xml得到了正确加载,并且得到了以下跟踪(取自我的日志文件):

10913 [http-thread-pool-8080-(1)] DEBUG com.stackoverflow.q2418355.SimpleServlet - >> doGet()
10928 [http-thread-pool-8080-(1)] DEBUG com.stackoverflow.q2418355.SimpleEJB - >> sayHello()
10928 [http-thread-pool-8080-(1)] DEBUG com.stackoverflow.q2418355.SimpleEJB - << sayHello()
10932 [http-thread-pool-8080-(1)] DEBUG com.stackoverflow.q2418355.SimpleServlet - << doGet()

我也尝试过将 EJB 打包在它自己的 JAR 中并进行部署WEB-INF/lib并获得相同的结果,它可以正常工作。你能发现任何明显的区别吗?也许上传您的应用程序的简化版本(BTW 错误报告很可能需要)。

我在 Eclipse 3.5 下运行 GlassFish v3(使用 GlassFish v3 插件)。

于 2010-03-10T15:59:15.357 回答
6

org.slf4j.impl.JDK14LoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext异常表明 SLF4J 未绑定到 logback-classic 而是绑定到 slf4j-jdk14 。简而言之,logback 代码不应该受到责备,因为它没有被执行或调用。

看起来 GFv3 正在将 slf4j-jdk14.jar 导出到您的应用程序中,因此覆盖了您选择的日志记录后端,在这种情况下为 logback。这是应用服务器无意中将其选择强加给用户的场景之一。

如果 GFv3 确实将其 SLF4J 绑定强加给最终用户,那么这是一个 GFv3 问题,必须由 GFv3 开发人员解决。我可能是错的,但我认为他们认为最终用户不会想要除 java.util.logging 提供的任何其他日志记录功能,而是将 slf4j-jdk14 捆绑到 GFv3 中。用户需要联系他们并抱怨他们的假设不正确。他们也有可能意识到这个问题并且已经提供了解决方法......

于 2010-03-10T18:13:38.543 回答
1

这是几乎确切的相关代码:

登录 EJB:

@Stateless 
@Interceptors(LoggingInterceptor.class)
public class LoginEJB
{
    @PersistenceContext(unitName = "persistence")
    private EntityManager em;

    public User getUser(String username)
    {
        try
        {
            Query query = em.createQuery("Select u from User u where u.userName = '" + username + "'");
            User user = (User) query.getSingleResult();
            return user;
        } catch (NoResultException e)
        {
            return null;
        }

    }
}

我的日志记录代码所在的拦截器:

import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class LoggingInterceptor
{
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @AroundInvoke
    public Object logMethod(InvocationContext ic) throws Exception
    {

        logger.info("[{}] Entering - {}()", ic.getTarget().toString() , ic.getMethod().getName());
        try
        {
            return ic.proceed();
        } finally
        {
           logger.info("[{}] Exiting - {}()", ic.getTarget().toString() , ic.getMethod().getName());
        }
    }
}

logback.xml

<configuration scan="true">
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{HH:mm:ss.SSS} [%-5level] [%logger{36}] - %msg%n</Pattern>
        </layout>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>c:\ItamLogs\log.txt</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>c:\ItamLogs\Archive\log-%d{yyyy-MM-dd}.txt</FileNamePattern>
        </rollingPolicy>

        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>[%-5level] - %d{HH:mm:ss.SSS} [%logger{35}] - %msg%n</Pattern>
        </layout>
    </appender>

    <logger name="org.hibernate">
        <level value="WARN"/>
    </logger>

    <root level="DEBUG">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

jsf2.0 支持 bean。

@ManagedBean
public class LoginBacking extends AbstractBacking
{
    @NotEmpty(message = "User Name required.")
    private String username;
    @NotEmpty(message = "Password required.")
    private String password;
    @EJB
    private LoginEJB loginEJB;

    public String getPassword()
    {
        return password;
    }

    public void setPassword(String password)
    {
        this.password = password;
    }

    public String getUsername()
    {
        return username;
    }

    public void setUsername(String username)
    {
        this.username = username;
    }

    public String performLogin()
    {
        String result = "login";
        User user = loginEJB.getUser(username);

        if(null == user || !user.getPassword().equals(password))
        {
            this.getFacesContext().addMessage("login-form:button-submit", new FacesMessage("The User Name or Password entered is incorrect."));
            return result;
        }

        this.setCurrentUser(user);
        result = "success";
        return result;
    }
}

我有一个 jsf 页面

<span id="submit-button">
  <h:commandButton id="button-submit" value="Sign On" action="#{loginBacking.performLogin}" />
</span>

最后我的pom

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>


    <groupId>com.test</groupId>
    <artifactId>tester</artifactId>
    <version>1.0/version>

    <name>Code</name>

    <packaging>war</packaging>


    <repositories>
        <repository>
            <id>maven2-repository.dev.java.net</id>
            <name>Java.net Repository for Maven</name>
            <url>http://download.java.net/maven/2/</url>
        </repository>
        <repository>
            <snapshots />
            <id>codecaus</id>
            <name>codehaus</name>
            <url>http://repository.codehaus.org</url>
        </repository>
        <repository>
            <snapshots />
            <id>ibiblio</id>
            <url>http://www.ibiblio.org/maven2/</url>
        </repository>
        <repository>
            <id>jboss</id>
            <url>http://repository.jboss.com/maven2</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>jboss-snapshot</id>
            <url>http://snapshots.jboss.org/maven2</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>java.net.glassfish</id>
            <name>Repository hosting the jee6 artifacts</name>
            <url>http://download.java.net/maven/glassfish</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>jboss-plugins</id>
            <url>http://repository.jboss.com/maven2</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>jboss-snapshot-plugins</id>
            <url>http://snapshots.jboss.org/maven2</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

    <dependencies>
        <dependency>
            <groupId>javax.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>el-api</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.0.0.GA</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>bean-validator</artifactId>
            <version>3.0-JBoss-4.0.0.Beta3</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.extras</groupId>
            <artifactId>glassfish-embedded-all</artifactId>
            <version>3.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>6.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
        </dependency>


        <dependency>
            <groupId>javax.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- JPA -->

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>3.5.0-CR-2</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-annotations</artifactId>
            <version>3.5.0-CR-2</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-commons-annotations</artifactId>
            <version>3.2.0.Beta1</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>3.5.0-CR-2</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>3.5.0-CR-2</version>
        </dependency>

        <dependency>
            <groupId>postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>8.4-701.jdbc4</version>
        </dependency>


        <!-- logging -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>0.9.18</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>0.9.18</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.5.11</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>javax.persistence</artifactId>
            <version>2.0.0</version>
        </dependency>
    </dependencies>
    <properties>
        <netbeans.hint.deploy.server>gfv3ee6</netbeans.hint.deploy.server>
    </properties>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.6</source>
                        <target>1.6</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>2.0</version>
                </plugin>

            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.0</version>
            </plugin>
        </plugins>
    </build>
</project>

编辑:我也尝试将我的记录器更改为静态,没有变化。

于 2010-03-16T13:07:49.830 回答
0

基本上问题是应用程序服务器使用提供 slf4j 并且您尝试使用它会转到应用程序服务器 slf4j 绑定,而不是您自己想要的绑定。

不能只在 Glassfish 中使用 slf4j 绑定吗?

于 2010-03-10T19:23:30.537 回答