如何在不传递ID的情况下确定在哪个Java Applet上下文中运行?
我是开发相当大的Swing Java Applet团队的成员。我们的大多数代码都是旧代码,并且有大量的单例引用。我们将所有这些都捆绑到一个"应用程序上下文"单例中。现在,我们需要创建一种方法来分离共享上下文(在当前显示的所有小程序之间共享)和非共享上下文(特定于当前显示的每个小程序)。
但是,我们在调用单例的每个位置都没有ID,也不想将ID传播到所有位置。识别我们在哪个applet上下文中运行的最简单方法是什么? (我已经尝试弄乱了类加载器,线程组,线程ID ...到目前为止,我什么也找不到使我能够标识调用源的信息)。
解决方案
回答
如果我对理解正确,那么想法是为每个调用者对象或者"上下文"获得一个不同的"单例"对象。
我们可以做的一件事是创建一个线程局部全局变量,在其中写入当前上下文的ID。 (可以使用AOP完成。)然后在单例获取程序中,从线程本地获取上下文ID,以用作调用上下文的正确"单例"实例的键。
关于AOP,在applet中使用它应该没有问题,因为取决于切入点,建议是在编译时编织的,并且JAR已添加到运行时依赖项中。因此,在运行时不应保留AOP的任何特殊证据。
回答
@Hugo关于threadlocal:
我考虑过这种解决方案。但是,从实验中,我发现该方法存在两个问题:
- 共享线程(服务器连接等)有问题。尽管可以通过特别注意这些线程来解决此问题(它们全部在我的控制之下,并且与传统代码几乎是隔离的)。
- EDT线程在所有小程序之间共享。我没有找到一种方法来强制为每个小程序创建一个新的EDT线程。这意味着EDT的threadlocal将在小程序之间共享。我不知道该如何解决。有什么建议吗?
回答
单身人士是邪恶的,我们期望什么? ;)
也许最全面的方法是将小程序的大部分加载到不同的类加载器中(使用java.net.URLClassLoader.newInstance)。然后使用WeakHashMap将类加载器与小程序关联。如果我们可以将大多数代码拆分为一个通用的类加载器(作为每个小应用程序类加载器的父级)和普通的小应用程序代码库,那将更快,但工作更多。
其他技巧:
如果有权访问任何组件,则可以重复使用Component.getParent或者SwingUtilities.getRoot。
如果我们在每个小应用程序实例线程中,则可以设置一个ThreadLocal。
从EDT中,我们可以从队列(java.awt.EventQueue.getCurrentEvent())中读取当前事件,并可能从中找到一个组件。或者,使用重写的dispatchEvent方法推送EventQueue。