使用EJB3.1进行logback
我正在使用logback / slf4j来处理我的应用程序中的日志记录。 在我开始使用EJB之前,一切都运行良好。 一旦我将无状态EJB添加到我的应用程序,记录器就开始忽略我的logback.xml并停止使用我的appender。 我切换到程序化记录器配置以查看错误,现在当我尝试在EJB中使用我的记录器时,我收到以下错误:
org.slf4j.impl.JDK14LoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext
来自这条线:
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
是否需要任何特殊配置才能使回归与EJB一起使用? 如果重要的话,我正在使用glassfish v3进行部署。
这看起来非常接近此线程中描述的问题,我怀疑类似的类加载问题。 由于logback加载logback.xml
的方式(更确切地说是它检索ClassLoader
的方式),它可能无法获取其配置文件并回退到默认的BasicConfiguration
。
不确定如何打包代码,但建议的解决方法是将logback.xml
包含在EAR库中。 如果您没有使用EAR打包,请尝试识别用于查看logback.xml
文件放置位置的类加载器。
最后,这可能是回归中的问题。 但是没有检查他们的问题跟踪器。
更新:如果您使用war包装,请尝试将GlassFish配置为在委托之前首先使用子类加载器。 在 sun-web.xml
:
更新:我在我身边做了一点测试……我无法重现你的问题。 我已经为Java EE 6 webapp创建了一个项目,它具有以下结构:
$ tree sample 样品 | - pom.xml ` - src ` - 主要 | - java | ` - com | ` - stackoverflow | ` - q2418355 | | - SimpleEJB.java | ` - https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/SimpleServlet.java | - 资源 | ` - logback.xml ` - webapp | - META-INF | ` - MANIFEST.MF | - WEB-INF | ` - lib ` - index.jsp
我的pom.xml看起来像:
4.0.0 com.stackoverflow.q2418355 sample 1.0-SNAPSHOT war sample Maven Webapp http://maven.apache.org javax javaee-api 6.0 provided junit junit 4.7 test ch.qos.logback logback-classic 0.9.18 org.slf4j slf4j-api 1.5.11 org.apache.maven.plugins maven-compiler-plugin 2.0.2 1.6 1.6 org.apache.maven.plugins maven-war-plugin 2.1-beta-1 false sample
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 + "!!!"; } }
https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/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 = { "/https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/SimpleServlet" }) public class https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/SimpleServlet extends HttpServlet { @EJB SimpleEJB bean; private static Logger logger = LoggerFactory.getLogger(https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/SimpleServlet.class); @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { logger.debug(">> doGet()"); PrintWriter out = response.getWriter(); out.println(""); out.println("Serving at: " + request.getContextPath() + "
"); out.println("Invoking EJB: " + bean.sayHello("Duke") + "
"); out.println(""); logger.debug("<< doGet()"); } }
index.jsp
的代码是:
Hello World!
Invoke the Servlet by clicking here.
我的logback.xml
看起来像:
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n /tmp/logs/testFile.log true %-4relative [%thread] %-5level %logger{35} - %msg%n
我的logback.xml
被加载logback.xml
,并在调用servlet时得到以下跟踪(取自我的日志文件):
10913 [http-thread-pool-8080-(1)] DEBUG com.stackoverflow.q2418355.https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/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.https://stackoverflow.com/questions/2418069/logback-with-ejb3-1/SimpleServlet - << doGet()
我也尝试将EJB打包在自己的JAR中并部署在WEB-INF/lib
并得到相同的结果,它只是起作用。 你能发现任何明显的差异吗? 也许上传你的应用程序的简化版本(很可能是错误报告BTW所必需的)。
我在Eclipse 3.5(使用GlassFish v3插件)下运行GlassFish v3。
org.slf4j.impl.JDK14LoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext
exception显示SLF4J未绑定到logback-classic而是绑定到slf4j-jdk14。 简而言之,回归代码不应该受到责备,因为它没有被执行也没有被调用。
看起来GFv3正在将slf4j-jdk14.jar导出到您的应用程序中,从而覆盖了您选择的日志后端,在这种情况下是logback。 这是app服务器无意中对用户施加选择的场景之一。
如果GFv3确实对最终用户施加了SLF4J绑定,那么这是一个必须由GFv3开发人员解决的GFv3问题。 我可能错了,但我认为他们假设最终用户不希望任何其他日志记录function超出java.util.logging提供的function,只需在GFv3中捆绑slf4j-jdk14。 用户需要联系他们并抱怨他们的假设不正确。 他们也有可能意识到这个问题并且已经提供了解决方法……
基本上问题是应用程序服务器使用提供slf4j并且您尝试使用它会转到应用程序服务器slf4j绑定而不是您自己想要的绑定。
你不能只在Glassfish中使用slf4j绑定吗?
这里几乎是完全相关的代码:
登录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
%d{HH:mm:ss.SSS} [%-5level] [%logger{36}] - %msg%n c:\ItamLogs\log.txt c:\ItamLogs\Archive\log-%d{yyyy-MM-dd}.txt [%-5level] - %d{HH:mm:ss.SSS} [%logger{35}] - %msg%n
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页面
最后我的pom
4.0.0 com.test tester 1.0/version> Code war maven2-repository.dev.java.net Java.net Repository for Maven http://download.java.net/maven/2/ codecaus codehaus http://repository.codehaus.org ibiblio http://www.ibiblio.org/maven2/ jboss http://repository.jboss.com/maven2 true false jboss-snapshot http://snapshots.jboss.org/maven2 true true java.net.glassfish Repository hosting the jee6 artifacts http://download.java.net/maven/glassfish jboss-plugins http://repository.jboss.com/maven2 true false jboss-snapshot-plugins http://snapshots.jboss.org/maven2 true true javax.faces jsf-api 2.0 provided javax.servlet servlet-api 2.5 provided javax.el el-api 1.0 provided javax.validation validation-api 1.0.0.GA org.glassfish bean-validator 3.0-JBoss-4.0.0.Beta3 org.glassfish.extras glassfish-embedded-all 3.0 test javax javaee-api 6.0-SNAPSHOT junit junit 4.7 javax.faces jsf-api 2.0 provided org.hibernate hibernate-core 3.5.0-CR-2 org.hibernate hibernate-annotations 3.5.0-CR-2 org.hibernate hibernate-commons-annotations 3.2.0.Beta1 org.hibernate hibernate-entitymanager 3.5.0-CR-2 org.hibernate hibernate-c3p0 3.5.0-CR-2 postgresql postgresql 8.4-701.jdbc4 ch.qos.logback logback-core 0.9.18 ch.qos.logback logback-classic 0.9.18 org.slf4j slf4j-api 1.5.11 org.eclipse.persistence javax.persistence 2.0.0 gfv3ee6 org.apache.maven.plugins maven-compiler-plugin 1.6 1.6 org.apache.maven.plugins maven-war-plugin 2.0 org.apache.maven.plugins maven-war-plugin 2.0
编辑:我也尝试将我的记录器更改为静态,无变化。