You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AsynchronousPageStore时Apache Wicket页面存储错误求助

问题:使用AsynchronousPageStore时出现session属性异步修改错误

操作步骤与代码实现

1. 自定义McAsynchronousDiskPageStore子类

public class McAsynchronousDiskPageStore extends DiskPageStore
{
    public McAsynchronousDiskPageStore()
    {
        super( PortalApp.this.getName(), PortalApp.this.getStoreSettings().getFileStoreFolder(), Bytes.kilobytes( 40000));
    }

    @Override
    public boolean canBeAsynchronous(IPageContext context)
    {
        return true;
    }
}

2. 自定义CustomPageStoreManager继承AsynchronousPageStore

public class CustomPageStoreManeger extends AsynchronousPageStore
{
    private final IPageStore delegate;

    public CustomPageStoreManeger(IPageStore delegate)
    {
        super( delegate, 100);
        this.delegate = delegate;
    }

    @Override
    public void destroy()
    {
        Logger.getLogger( this).logInfo( " page store Size" + ((IPersistentPageStore)delegate).getTotalSize());
    }

    @Override
    public void addPage(IPageContext context, IManageablePage page)
    {
        if( INotPersistentPage.class.isAssignableFrom( page.getClass()))
        {
            Logger.getLogger( this).debug( " ignoring page persitence" + page.getClass());
        }
        else
        {
            super.addPage( context, page);
        }
    }
}

3. WicketApplication配置

setPageManagerProvider( new DefaultPageManagerProvider( this)
{
    @Override
    protected IPageStore newPersistentStore()
    {
        return new CustomPageStoreManeger( new McAsynchronousDiskPageStore());
    }
});

错误日志

09:31:44,699 ERROR [AsynchronousPageStore$PageAddingRunnable] (Wicket-AsyncPageStor) An error occurred while saving asynchronously 'PendingAdd [sessionId=6A4jzJpJbU8YMgb9J-_npsnLGsywu6xi0jJmkAiY, pageId=7, pageClass=org.apache.wicket.pageStore.SerializedPage]': org.apache.wicket.WicketRuntimeException: session attribute can not be changed asynchronuously
    at deployment.xx-12.0.ear//org.apache.wicket.pageStore.AsynchronousPageStore$PendingAdd.getSessionAttribute(AsynchronousPageStore.java:198)
    at deployment.xx-12.0.ear//org.apache.wicket.pageStore.AsynchronousPageStore$PendingAdd.getSessionAttribute(AsynchronousPageStore.java:201)
    at deployment.xx-12.0.ear//org.apache.wicket.pageStore.AbstractPersistentPageStore.getSessionIdentifier(AbstractPersistentPageStore.java:149)
    at deployment.xx-12.0.ear//org.apache.wicket.pageStore.AbstractPersistentPageStore.canBeAsynchronous(AbstractPersistentPageStore.java:76)
    at deployment.xx-12.0.ear//org.apache.wicket.pageStore.AsynchronousPageStore.addPage(AsynchronousPageStore.java:369)
    at deployment.xx-12.0.ear.web.war/xxx.PortalApp$CustomPageStoreManeger.addPage(PortalApp.java:206)
    at deployment.xx-12.0.ear//org.apache.wicket.pageStore.AsynchronousPageStore$PageAddingRunnable.run(AsynchronousPageStore.java:292

问题分析与解决

核心问题

错误提示「session attribute can not be changed asynchronuously」的根源是:异步保存页面时,AbstractPersistentPageStore.getSessionIdentifier()尝试从IPageContext获取会话属性,但异步线程中无法安全访问/修改绑定到请求线程的Wicket会话可变状态,触发异常。

同时你的CustomPageStoreManager继承AsynchronousPageStore属于冗余操作——AsynchronousPageStore本身是装饰器模式,用来包装IPageStore实现,无需继承扩展。

修复步骤

1. 修正McAsynchronousDiskPageStore

确保canBeAsynchronous()方法不触发会话属性访问逻辑,直接返回判断结果:

public class McAsynchronousDiskPageStore extends DiskPageStore
{
    // 提供带参数的构造方法,避免硬编码依赖PortalApp
    public McAsynchronousDiskPageStore(String appName, File storeFolder, Bytes maxSize)
    {
        super(appName, storeFolder, maxSize);
    }

    @Override
    public boolean canBeAsynchronous(IPageContext context)
    {
        // 直接返回true,跳过父类中访问会话属性的逻辑
        return true;
    }
}

2. 简化PageStore配置,移除冗余子类

直接使用AsynchronousPageStore包装自定义DiskPageStore,在匿名内部类中实现扩展逻辑:

setPageManagerProvider(new DefaultPageManagerProvider(this) {
    @Override
    protected IPageStore newPersistentStore() {
        DiskPageStore delegate = new McAsynchronousDiskPageStore(
            getName(), 
            getStoreSettings().getFileStoreFolder(), 
            Bytes.kilobytes(40000)
        );
        return new AsynchronousPageStore(delegate, 100) {
            @Override
            public void addPage(IPageContext context, IManageablePage page) {
                if (INotPersistentPage.class.isAssignableFrom(page.getClass())) {
                    Logger.getLogger(this).debug("ignoring page persitence " + page.getClass());
                } else {
                    super.addPage(context, page);
                }
            }

            @Override
            public void destroy() {
                super.destroy();
                Logger.getLogger(this).logInfo("page store Size " + ((IPersistentPageStore)delegate).getTotalSize());
            }
        };
    }
});

3. 原理说明

AsynchronousPageStore将页面保存操作放入异步线程执行,但Wicket会话默认绑定到请求线程,异步线程中无法安全访问会话的可变属性。AbstractPersistentPageStore的默认canBeAsynchronous()实现会尝试获取会话标识符,触发会话属性访问,因此必须自定义该方法,避免任何会话相关操作。

内容的提问来源于stack exchange,提问作者Farabi Abdelwahed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 21:15:34