WebApplication 的 Wicket 序列化问题

Wicket serialization issue with WebApplication

我将继续使用 WebSocketBehavior 记录行为。它目前将正确的数据记录到控制台,但也会抛出一个可怕的序列化错误。这是因为我提供 WicketApplication 本身作为行为的构造函数参数。我试过将它传递给我的会话对象并使用它来获取 WebApplication,但它始终 returns 为空。广播对象需要应用程序才能正常运行。我的问题是如何在避免讨厌的序列化错误的同时为行为提供 WebApplication?这是我的行为 class:

    public class LogWebSocketBehavior extends WebSocketBehavior implements Serializable {

private static final long serialVersionUID = 1L;

private Console console;
private Handler logHandler;
private Model<LogRecord> model = new Model<>();
private WebApplication application;

public LogWebSocketBehavior(Console console, WebApplication application) {
    super();
    configureLogger();
    this.console = console;
    this.application = application;


}

private void configureLogger() {

    Enumeration<String> list = LogManager.getLogManager().getLoggerNames();

    list.hasMoreElements();

    Logger l = Logger.getLogger(AppUtils.loggerName);
    l.addHandler(getLoggerHandler());

}

@Override
protected synchronized void onPush(WebSocketRequestHandler handler, IWebSocketPushMessage message) {
    LogRecord r = model.getObject();
    sendRecordToConsole(handler, r);
}

private Handler getLoggerHandler() {
    return new LogHandler() {

        private static final long serialVersionUID = 1L;

        @Override
        public void publish(LogRecord record) {
            model.setObject(record);

            sendToAllConnectedClients("data");
        }
    };
}

private synchronized void sendToAllConnectedClients(String message) {

        IWebSocketConnectionRegistry registry = new SimpleWebSocketConnectionRegistry();
        WebSocketPushBroadcaster b = new WebSocketPushBroadcaster(registry);


        b.broadcastAll(application, new Message());

}

private void sendRecordToConsole(WebSocketRequestHandler handler, LogRecord r) {

    Level level = r.getLevel();

    if (level.equals(Level.INFO)) {
        console.info(handler, new SimpleFormatter().formatMessage(r));
    } else {
        console.error(handler, new SimpleFormatter().formatMessage(r));
    }
}

class Message implements IWebSocketPushMessage {

    public Message() {

    }

}

}

这是用于显示消息的面板:

public class FooterPanel extends Panel {

private static final long serialVersionUID = 1L;

private Form form;
private Console console;

public FooterPanel(String id) {
    super(id);
}

@Override
public void onInitialize() {
    super.onInitialize();
    form = new Form("form");
    form.add(console = getConsole("feedback_console"));
    console.setOutputMarkupId(true);
    form.setOutputMarkupId(true);
    add(form);

    add(getLoggingBehavior());

}

private Console getConsole(String id) {
    return new Console(id) {

        private static final long serialVersionUID = 1L;

    };
}

private WebSocketBehavior getLoggingBehavior() {

    return new LogWebSocketBehavior(console, this.getWebApplication());

}

}

我更新了我的行为如下:

    public class LogWebSocketBehavior extends WebSocketBehavior implements Serializable {

private static final long serialVersionUID = 1L;

private Console console;
private Handler logHandler;
private Model<LogRecord> model = new Model<>();

public LogWebSocketBehavior(Console console) {
    super();
    configureLogger();
    this.console = console;

}

private void configureLogger() {

    Enumeration<String> list = LogManager.getLogManager().getLoggerNames();

    list.hasMoreElements();

    Logger l = Logger.getLogger(AppUtils.loggerName);
    l.addHandler(getLoggerHandler());

}

@Override
protected synchronized void onPush(WebSocketRequestHandler handler, IWebSocketPushMessage message) {
    LogRecord r = model.getObject();
    sendRecordToConsole(handler, r);
}

private Handler getLoggerHandler() {
    return new LogHandler() {

        private static final long serialVersionUID = 1L;

        @Override
        public void publish(LogRecord record) {
            model.setObject(record);

            sendToAllConnectedClients("data");
        }
    };
}

private synchronized void sendToAllConnectedClients(String message) {

    WebApplication application = WebApplication.get();
    IWebSocketConnectionRegistry registry = new SimpleWebSocketConnectionRegistry();
    WebSocketPushBroadcaster b = new WebSocketPushBroadcaster(registry);

    b.broadcastAll(application, new Message());

}

private void sendRecordToConsole(WebSocketRequestHandler handler, LogRecord r) {

    Level level = r.getLevel();
    String message = AppUtils.consoleDateTimeFormat.format(LocalDateTime.now()) + " - " + AppUtils.LogFormatter.formatMessage(r);
    if (level.equals(Level.INFO)) {
        console.info(handler, message);
    } else {
        console.error(handler, message);
    }
}

class Message implements IWebSocketPushMessage {

    public Message() {

    }

}

}

然后我又回到了最初的问题,即以下错误:

错误 - ErrorLogger - 作业(report.DB5E002E046235586592E7E984338DEE3:653 抛出异常。 org.quartz.SchedulerException:

作业引发了未处理的异常。 [请参阅嵌套异常:org.apache.wicket.WicketRuntimeException:没有应用程序附加到当前线程 DefaultQuartzScheduler_Worker-1] 在 org.quartz.core.JobRunShell.run(JobRunShell.java:213)

at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)

原因:org.apache.wicket.WicketRuntimeException:当前线程没有附加应用程序DefaultQuartzScheduler_Worker-1 在 org.apache.wicket.Application.get(Application.java:236)

at org.apache.wicket.protocol.http.WebApplication.get(WebApplication.java:160)

at eb.wicket.behaviors.LogWebSocketBehavior.sendToAllConnectedClients(LogWebSocketBehavior.java:77)

at eb.wicket.behaviors.LogWebSocketBehavior.access0(LogWebSocketBehavior.java:29)

at eb.wicket.behaviors.LogWebSocketBehavior.publish(LogWebSocketBehavior.java:70)

终于按预期工作了。这是行为 class:

public class LogWebSocketBehavior extends WebSocketBehavior implements Serializable {

private static final long serialVersionUID = 1L;

private Console console;
private Model<LogRecord> model = new Model<>();

public LogWebSocketBehavior(Console console) {
    super();
    configureLogger();
    this.console = console;

}

private void configureLogger() {

    Enumeration<String> list = LogManager.getLogManager().getLoggerNames();

    list.hasMoreElements();

    Logger l = Logger.getLogger(AppUtils.loggerName);
    l.addHandler(getLoggerHandler());

}

@Override
protected synchronized void onPush(WebSocketRequestHandler handler, IWebSocketPushMessage message) {
    LogRecord r = model.getObject();
    sendRecordToConsole(handler, r);
}

private Handler getLoggerHandler() {
    return new LogHandler() {

        private static final long serialVersionUID = 1L;

        @Override
        public void publish(LogRecord record) {
            model.setObject(record);

            sendToAllConnectedClients("data");
        }
    };
}

private synchronized void sendToAllConnectedClients(String message) {

    IWebSocketConnectionRegistry registry = new SimpleWebSocketConnectionRegistry();
    WebSocketPushBroadcaster b = new WebSocketPushBroadcaster(registry);
    b.broadcastAll(Application.get("eb.wicket.MyWicketFilter"), new Message());

}

private void sendRecordToConsole(WebSocketRequestHandler handler, LogRecord r) {

    Level level = r.getLevel();
    String message = AppUtils.consoleDateTimeFormat.format(LocalDateTime.now()) + " - " + AppUtils.LogFormatter.formatMessage(r);
    if (level.equals(Level.INFO)) {
        console.info(handler, message);
    } else {
        console.error(handler, message);
    }
}

class Message implements IWebSocketPushMessage {

    public Message() {

    }

}

}

与其保留对应用程序的引用,不如在需要时查找它:Application.get()

更新您的问题后我们可以看到:

 Caused by: org.apache.wicket.WicketRuntimeException: 
 There is no application attached to current thread DefaultQuartzScheduler_Worker-1

这就解释了 - 这是一个由 Quartz 启动的线程,它不是一个 http 线程。

克服这个问题的唯一方法是使用 Application.get(String)。该值应该是在 web.xml.

中指定为 <filter-name> 值的应用程序名称 (Application#getName())

您可以通过这种方式获取 Application 实例,但无法对 Session and/or RequestCycle 执行相同的操作,以防您也需要它们。