【问题标题】:Jetty scavenging sessions error with view-scoped beans视图范围 bean 的 Jetty 清理会话错误
【发布时间】:2015-02-23 16:28:57
【问题描述】:

我正在尝试将 Tomcat 应用程序移植到 JettyRunner 9.2 我想将我的应用程序移动到 Heroku,因此我需要使用嵌入式服务器或 JettyRunner 来启动它。我认为 JettyRunner 是最简单的,因为我可以保留 WAR 格式,并在必要时轻松移植。

任何帮助将不胜感激。如果我不能很快让它工作,我可以尝试嵌入式 Tomcat,或者查看不需要我更改容器的托管。

如果使用 Jetty 的其他方法 - 也许嵌入式 Jetty 会更容易,请告诉我并指出一些细节。

所以,对于应用行为。该应用程序似乎可以正常移植并且可以正常启动,但是登录时出现错误。这是一个例外

2014-12-26 05:18:21.189:WARN:oejs.session:org.eclipse.jetty.server.session.HashSessionManager@69f63d95Timer: Problem scavenging sessions
java.lang.NullPointerException
    at com.sun.faces.application.view.ViewScopeContextManager.destroyBeans(Unknown Source)
    at com.sun.faces.application.view.ViewScopeContextManager.sessionDestroyed(Unknown Source)
    at com.sun.faces.application.view.ViewScopeManager.sessionDestroyed(Unknown Source)
    at com.sun.faces.application.WebappLifecycleListener.sessionDestroyed(Unknown Source)
    at com.sun.faces.config.ConfigureListener.sessionDestroyed(Unknown Source)
    at org.eclipse.jetty.server.session.AbstractSessionManager.removeSession(AbstractSessionManager.java:772)
    at org.eclipse.jetty.server.session.AbstractSession.timeout(AbstractSession.java:302)
    at org.eclipse.jetty.server.session.HashSessionManager.scavenge(HashSessionManager.java:358)
    at org.eclipse.jetty.server.session.HashSessionManager$Scavenger.run(HashSessionManager.java:84)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

这是我的 jetty 和 jsf 依赖项:

    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-server</artifactId>
        <version>9.2.6.v20141205</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-servlet</artifactId>
        <version>9.2.6.v20141205</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.faces</artifactId>
        <version>2.2.9</version>
    </dependency>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>

这是我的 pom 的 maven jetty 插件部分:

        <plugin>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-maven-plugin</artifactId>
          <version>${org.eclipse.jetty.version}</version>
            <configuration>
                <webApp>
                    <overrideDescriptor>src/main/webapp/WEB-INF/jetty-web-override.xml</overrideDescriptor>
                </webApp>
                <contextXml>src/main/webapp/WEB-INF/jetty-context.xml</contextXml>
            </configuration>
        </plugin>

我的 web.xml 中的侦听器

<listener>
    <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>
<listener>
    <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>

jetty-web-override.xml

<web-app version="3.0" 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/web-app_3_0.xsd">

<listener>
    <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>

<resource-env-ref>
    <resource-env-ref-name>BeanManager</resource-env-ref-name>
    <resource-env-ref-type>
        javax.enterprise.inject.spi.BeanManager
    </resource-env-ref-type>
</resource-env-ref>

jetty-env.xml

    <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure id="webAppCtx" class="org.eclipse.jetty.webapp.WebAppContext">
    <New id="BeanManager" class="org.eclipse.jetty.plus.jndi.Resource">

    <Arg>
        <Ref id="webAppCtx"/>
    </Arg>
    <Arg>BeanManager</Arg>
    <Arg>
        <New class="javax.naming.Reference">
            <Arg>javax.enterprise.inject.spi.BeanManager</Arg>
            <Arg>org.jboss.weld.resources.ManagerObjectFactory</Arg>
            <Arg/>
        </New>
    </Arg>
</New>
</Configure>

最后,jetty.context:

<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" 

"http://www.eclipse.org/jetty/configure.dtd">

<Configure class="org.eclipse.jetty.webapp.WebAppContext">

<Set name="serverClasses">
    <Array type="java.lang.String">
        <Item>-org.eclipse.jetty.servlet.ServletContextHandler.Decorator</Item>
    </Array>
</Set>
</Configure>

【问题讨论】:

  • Stacktrace 中的 NPE 似乎是 Glassfish / Faces 问题。
  • 是 - 可能与 View Scoped beans 有关 - 但尚未找到任何相关内容

标签: maven jsf heroku jetty cdi


【解决方案1】:

我刚刚做了以下解决方法。 我正在使用 Jetty 9.2、CDI 1.2(焊接)和 Mojarra 2.28。

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import javax.enterprise.inject.spi.CDI;
import javax.faces.FacesException;
import javax.faces.context.ExternalContext;
import javax.faces.context.ExternalContextFactory;
import javax.faces.context.ExternalContextWrapper;

import com.sun.faces.util.Util;

public class CDIViewScopeFixExternalContextFactory extends ExternalContextFactory{

private final ExternalContextFactory wrapped;

public CDIViewScopeFixExternalContextFactory(ExternalContextFactory wrapped){
    this.wrapped = wrapped;
}

@Override
public ExternalContext getExternalContext(Object context, Object request,
        Object response) throws FacesException {
    ExternalContext externalContext = getWrapped().getExternalContext(context, request, response);
    CDIViewScopeWorkaround wrapper = new CDIViewScopeWorkaround(externalContext);
    return wrapper;
}


@Override
public ExternalContextFactory getWrapped() {
    return this.wrapped;
}

private static class CDIViewScopeWorkaround extends ExternalContextWrapper{

    private static String CDI_KEY;
    static {
        try {
            Field f = Util.class.getDeclaredField("CDI_AVAILABLE_PER_APP_KEY");
            f.setAccessible(true);
            CDI_KEY  = (String) f.get(null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    private final ExternalContext wrapped;

    public CDIViewScopeWorkaround(ExternalContext wrapped){
        this.wrapped = wrapped;
    }


    @Override
    public ExternalContext getWrapped() {
        return wrapped;
    }

    @Override
    public Map<String, Object> getApplicationMap() {
        MapFix mapFix = new MapFix(super.getApplicationMap());
        return mapFix;
    }
}

private static class MapFix extends MapWrapper<String,Object>{

    public MapFix(Map<String, Object> delegate) {
        super(delegate);
    }

    @Override
    public Object get(Object key) {
        if(CDIViewScopeWorkaround.CDI_KEY.equals(key)){
            return CDI.current().getBeanManager();
        }
        return super.get(key);
    }
}


private static class MapWrapper<K,V> implements Map<K,V>{

    private Map<K,V> delegate;

    public int size() {
        return delegate.size();
    }

    public boolean isEmpty() {
        return delegate.isEmpty();
    }

    public boolean containsKey(Object key) {
        return delegate.containsKey(key);
    }

    public boolean containsValue(Object value) {
        return delegate.containsValue(value);
    }

    public V get(Object key) {
        return delegate.get(key);
    }

    public V put(K key, V value) {
        return delegate.put(key, value);
    }

    public V remove(Object key) {
        return delegate.remove(key);
    }

    public void putAll(Map<? extends K, ? extends V> m) {
        delegate.putAll(m);
    }

    public void clear() {
        delegate.clear();
    }

    public Set<K> keySet() {
        return delegate.keySet();
    }

    public Collection<V> values() {
        return delegate.values();
    }

    public Set<java.util.Map.Entry<K, V>> entrySet() {
        return delegate.entrySet();
    }

    public boolean equals(Object o) {
        return delegate.equals(o);
    }

    public int hashCode() {
        return delegate.hashCode();
    }

    public MapWrapper(Map<K,V> delegate){
        this.delegate = delegate;
    }
}
}

faces-config.xml

    <faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.ord/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_2.xsd"
    version="2.2">

    <application>
       …
    </application>

     <factory>
        <external-context-factory>your.package.CDIViewScopeFixExternalContextFactory</external-context-factory>
    </factory>
</faces-config>

【讨论】:

    【解决方案2】:

    我在 linux 系统上使用 7.0.55 tomcat 时遇到了同样的问题。 对我来说,JAVASERVERFACES-3450 不是问题,因为这张票指的是已经被销毁的视图范围 bean 的空实例。

    ViewScopeContextManager.destroyBeans(Unknown Source) 中的异常是由于 beanManager 的空实例而发生的。

    在 Windows 系统上使用 Tomcat 7.0.55,一切正常... :(

    【讨论】:

      【解决方案3】:

      这个问题是由 JSF 实现中的一个与 ViewScoped bean 相关的错误引起的,描述为 here 描述的错误在 JSF 2.29 和 2.28 中。该修复程序在 2.30 中,尚未发布。

      我尝试返回 2.2 层次结构中的版本。 2.27 及之前此错误消失,但 ViewScoped bean 中出现其他错误。

      看起来 View Scoped bean 在 jsf 2.2 中基本上被破坏了(据我所知),因此作为临时措施,我已将所有 View Scoped bean 更改为 Request Scoped。这样可以避免错误。

      【讨论】:

        猜你喜欢
        • 2012-08-28
        • 1970-01-01
        • 1970-01-01
        • 2013-04-28
        • 2018-08-02
        • 1970-01-01
        • 2012-10-28
        • 2012-03-16
        • 1970-01-01
        相关资源
        最近更新 更多