使用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
相关产品推荐
相关产品推荐

