【问题标题】:How to make Spring play nice with Wicket? (ContextLoaderListener problem)如何让 Spring 与 Wicket 一起玩得更好? (ContextLoaderListener问题)
【发布时间】:2011-06-28 10:19:04
【问题描述】:

据我所知,根据我找到的说明(如 thisthis too),我需要在 web.xml 中使用这个才能让 Spring 工作:

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

在我的 Wicket 应用程序类中,我有:

public class MyApplication extends WebApplication {

    @Override
    protected void init() {
        super.init();    
        addComponentInstantiationListener(new SpringComponentInjector(this));
    }

    @Override
    public Class<? extends Page> getHomePage() {
        return HelloWorldPage.class;
    }
}

问题是,每当我在 web.xml 中有 ContextLoaderListener 时,Wicket 就不会启动。我只会收到 404 错误(或空白页),控制台输出如下:

SEVERE: Error listenerStart
Jun 28, 2011 12:49:04 PM org.apache.catalina.util.SessionIdGenerator createSecureRandom
INFO: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [1,973] milliseconds.
Jun 28, 2011 12:49:04 PM org.apache.catalina.core.StandardContext startInternal
SEVERE: Context [] startup failed due to previous errors
Jun 28, 2011 12:49:04 PM org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
SEVERE: The web application [] registered the JDBC driver [org.hsqldb.jdbc.JDBCDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
Jun 28, 2011 12:49:04 PM org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
SEVERE: The web application [] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
Jun 28, 2011 12:49:04 PM org.apache.catalina.startup.HostConfig deployDirectory

我正在使用两个框架的最新版本(Wicket 1.4.17 和 Spring 3.0.5)和 Tomcat 7 来运行它们(Tomcat 6 也会发生同样的事情)。另外,我在 WEB-INF/lib 中有以下 jars。缺少什么或太多?

antlr-2.7.6.jar                        log4j-1.2.16.jar              spring-web-3.0.5.jar
commons-collections-3.1.jar            mysql-connector-5.1.10.jar    slf4j-api-1.6.1.jar
dom4j-1.6.1.jar                        spring-beans-3.0.5.jar        slf4j-log4j12-1.6.1.jar
guava-r09.jar                          spring-context-3.0.5.jar      wicket-1.4.17.jar
hibernate-3.6.5.jar                    spring-core-3.0.5.jar         wicket-auth-roles-1.4.17.jar
hibernate-jpa-2.0-api-1.0.0.Final.jar  spring-jdbc-3.0.5.jar         wicket-datetime-1.4.17.jar
hsqldb.jar                             spring-orm-3.0.5.jar          wicket-ioc-1.4.17.jar
javassist-3.12.0.GA.jar                spring-test-3.0.5.jar         wicket-spring-1.4.17.jar
jta-1.1.jar                            spring-transaction-3.0.5.jar  wicketstuff-annotation-1.4.17.2.jar

web.xml 的其余部分(我尝试使用 servlet 和过滤器设置 Wicket;没有区别):

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">

    <display-name>My App</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <context-param>
        <param-name>configuration</param-name>
        <param-value>development</param-value>
    </context-param>

    <filter>
        <filter-name>MyApp</filter-name>
        <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
        <init-param>
            <param-name>applicationClassName</param-name>
            <param-value>com.acme.MyApplication</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>MyApp</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

     <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

</web-app>

谷歌搜索我找到了someone with the same problem,但没有解决方案。

有趣的是,我之前曾让 Spring 和 Wicket 很好地协同工作,而且设置几乎相同。有什么想法吗?

【问题讨论】:

    标签: java spring tomcat wicket


    【解决方案1】:

    这是我项目的配置:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
        version="2.4">
    
        <!-- Spring context config location(s) -->
        <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext.xml
        </param-value>
        </context-param>  
    
        <display-name>afrodite</display-name>
    
        <!-- used by Log4jConfigListener -->
        <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>afrodite.root</param-value>
        </context-param>     
    
        <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>/WEB-INF/log4j.properties</param-value>
        </context-param>   
    
        <filter>
        <filter-name>openSessionInView</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
        </filter>
    
        <filter>
        <filter-name>afrodite-app</filter-name>
        <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
        <init-param>
            <param-name>applicationClassName</param-name>
            <param-value>info.afrodite.wicket.AfroditeApplication</param-value>
        </init-param>
        <init-param>
            <param-name>configuration</param-name>
            <param-value>DEPLOYMENT</param-value>
        </init-param>
        </filter>    
    
        <!-- open session should be above the wicket filter -->
        <filter-mapping>
        <filter-name>openSessionInView</filter-name>
        <url-pattern>/app/*</url-pattern>
        </filter-mapping>     
    
        <filter-mapping>
        <filter-name>afrodite-app</filter-name>
        <url-pattern>/app/*</url-pattern>
        </filter-mapping>           
    
        <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
        </listener>
    
        <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        <servlet>
        <servlet-name>afrodite-api</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
        </servlet>
    
        <servlet-mapping>
        <servlet-name>afrodite-api</servlet-name>
        <url-pattern>/api/*</url-pattern>
        </servlet-mapping>    
    
        <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        </welcome-file-list>
    
    </web-app>
    

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      请检查 contextConfigLocationparam-value 应该是 classpath*:applicationContext.xml。请在我的示例中检查侦听器配置。希望我能帮上忙!

      这是我的 web.xml 配置,效果很好:

      <?xml version="1.0" encoding="ISO-8859-1"?>
      <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
           version="2.4">
      
          <display-name>mywebapp</display-name>
      
          <filter>
              <filter-name>springRequestContextFilter</filter-name>
              <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
          </filter>
      
          <context-param>
              <param-name>contextConfigLocation</param-name>
              <param-value>
                  classpath*:applicationContext.xml
              </param-value>
          </context-param>
      
          <listener>
              <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
          </listener>
          <listener>
              <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
          </listener>
      
          <filter>
              <filter-name>wicket.mywebapp</filter-name>
              <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
              <init-param>
                  <param-name>applicationClassName</param-name>
                  <param-value>com.company.example.web.MyApplication</param-value>
              </init-param>
          </filter>
      
              <!-- Enables Spring Security -->
          <filter>
              <filter-name>filterChainProxy</filter-name>
              <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
          </filter>
      
          <filter-mapping>
            <filter-name>filterChainProxy</filter-name>
            <url-pattern>/*</url-pattern>
          </filter-mapping>
      
       <filter-mapping>
        <filter-name>wicket.mywebapp</filter-name>
          <url-pattern>/*</url-pattern>
       </filter-mapping>
      
      </web-app>
      

      【讨论】:

      • 谢谢。我不认为classpath:applicationContext.xml 是问题所在;这以前对我有用,我已经仔细检查了 applicationContext.xml 可以在结果战争的类路径中找到。
      • 除此之外,我的配置的主要区别似乎是RequestContextListenerRequestContextFilter 的使用。我尝试添加这些但结果相同:只要存在ContextLoaderListener,Wicket 就不会启动。顺便说一句:这里缺少springRequestContextFilter 的过滤器映射。
      【解决方案3】:

      编辑:后来我意识到这里的根本问题很可能是缺少日志配置。在我们的例子中(使用 SLF4J 和 log4j),在 log4j.properties 添加适当的配置后,库记录的所有类型的警告和错误都变得可见,即使使用 Tomcat。


      我尝试了 Jetty 而不是 Tomcat,并开始收到更好的错误消息。结果发现缺少几个库——我已经使用的一些库需要的东西。

      2011-06-28 15:57:01.879:WARN::Unable to reach node goal: started
      java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
          at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:184)
          at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
          at org.eclipse.jetty.server.handler.ContextHandler.startContext(ContextHandler.java:640)
      

      有些库显然需要公共日志记录,这是我添加的。下一个:

      java.lang.NoClassDefFoundError: org/springframework/asm/ClassVisitor
          at org.springframework.context.support.AbstractRefreshableApplicationContext.customizeBeanFactory(AbstractRefreshableApplicationContext.java:218)
      

      添加了 spring-asm。下一个:

      org.springframework.beans.factory.BeanDefinitionStoreException: 
        Unexpected exception parsing XML document from class path resource [applicationContext.xml]; 
        nested exception is java.lang.NoClassDefFoundError: org/springframework/aop/config/AopNamespaceUtils
      

      添加了 spring-aop。接下来有点不那么直截了当:

      org.springframework.beans.factory.BeanDefinitionStoreException: 
        Unexpected exception parsing XML document from class path resource [applicationContext.xml]; 
        nested exception is java.lang.NoClassDefFoundError: org/aopalliance/intercept/MethodInterceptor
      

      Spring blog comments 中发现有关 aopalliance 缺失的讨论。显然它已经完全从spring-aop中删除了,你需要得到aopalliance.jar from sourceforge

      (我认为这种沼泽是最糟糕的 Java EE:我不知道 spring-asmspring-aop 更不用说 aopalliance 做了什么,但显然我需要它们。:-P)

      所以,添加了 aopalliance.jar。后来我还需要添加spring-expression和cglib-2.2(Hibernate自带)。

      在那之后,我的 Spring/Hibernate 持久层配置的一些问题仍然存在,但它们超出了这个问题的范围。否则 Wicket 和 Spring 现在可以很好地工作(例如,用于在 Wicket 页面上注入服务层对象)。

      我想这其中的一个寓意是,在某些情况下,Tomcat 会吃掉有用的错误消息,而 Jetty 可能更适合调试。此外,使用 Maven 可能会在一定程度上帮助解决依赖地狱问题(但也不是没有问题)。

      【讨论】:

      • 我觉得maven依赖管理是一个非常好的东西。我总是使用 maven 项目进行 java 开发。我很高兴您的应用程序有效。祝你有美好的一天!
      • 糟糕的 tomcat 服务器,不适合你! :) 由于您已经使用 slf4j,我建议您使用 jcl-over-slf4j 而不是 commons-logging。它实现了相同的接口/类,但将调用重定向到 slf4j 管道。这样一来,您的“日志架构”(如今日志已成为一门科学)将更加简洁,并且您将避免一些已知的公共日志类加载器问题。
      猜你喜欢
      • 1970-01-01
      • 2014-01-06
      • 1970-01-01
      • 2014-10-02
      • 2013-10-23
      • 1970-01-01
      • 2020-04-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多