繁体   English   中英

使用类加载器破解单例-Java Web应用中的Multiton

[英]Hacking a singleton with classloaders - Multiton in a Java web app

我正在使用包含几个单例类的现有后端创建Web前端。 通过将用户对象传递给DataStore来初始化DataStore,这在桌面应用程序环境中很好,在桌面环境中,该应用程序在每台计算机上启动一次,但是在旨在满足多个用户的服务器端应用程序中无法使用。

数据库专家不愿更改服务层并删除这些单例以允许每个用户一个实例,或允许一个服务层对象的单个实例为多个用户提供服务。 这是有充分的理由的,桌面应用程序已经使用了10年,更改可能会对桌面应用程序产生严重的副作用。

我被要求调查使用类加载器来创建单例的多个实例。 我对这个想法一点都不满意,黑客单身似乎是一种不好的做法,但是更改服务层可能需要花费数月的时间。

我已经通过将我的应用程序的两个相同的WAR文件(具有不同的文件名)放入Tomcat中进行了测试。 Tomcat为每个Web应用程序都创建了一个类加载器,它们分别工作正常。 我仅在单例使用System.setProperty / System.getProperty时遇到问题,这是可以预期的,因为System类来自树中更高的类加载器。

为了在单个web应用程序中实现这种分离,它开始变得有点复杂。 似乎我必须为每个会话创建一个不同的类加载器,并使用该类加载器加载整个服务层中的所有类或仅加载单例及其依赖项的类。

当我正在考虑如何在Servlet的会话中使用这些对象时,就会出现问题。 因为每个Servlet在Tomcat中都有一个实例,所以从会话中获取对象并强制转换对象并不是一件容易的事。 例如,要从会话中获取DataStore对象,我将必须将其强制转换为由正确的ClassLoader加载的正确的DataStore类,因为由两个不同的ClassLoader加载的单个类算作两个完全独立的类。

我已经读到,如果不小心使用ClassLoader,可能会导致各种各样的内存泄漏问题。从声音上看,如果我有500个用户,则是很多类加载器和类加载器加载的类。 然后,我会不会对PermGen遇到问题?

我想从这个大的解释中,我确实有四个问题:

  1. 在Web应用程序中使用类加载器入侵单例。 创建潜在的数百个相同类的实例,这些实例被设计为单例。 那是一个可怕的主意吗? 太可怕了,我不应该考虑吗?
  2. 如果我绝对必须这样做,最好的方法是什么?
  3. 如果要获取对象并将其设置为会话,如何满足Servlet的转换要求?
  4. 我最终会遇到内存泄漏和PermGen空间的问题吗?

我真的很感谢任何建议。 谢谢 :)

  1. 这不是理想的,但我认为这并不可怕。 实际上,它并没有加载相同类的多个版本(甚至没有单例)一样糟糕,并且在复杂的应用程序服务器环境中,尤其是在具有OSGi的环境中,这种情况变得越来越普遍。

  2. 很难说哪种方法最好,但是首先,我将从创建Web应用程序类加载器的子类加载器开始。 安排将实现类加载到子类加载器(即具有单例的加载器)中,并可能使实现类实现从Web应用程序类加载器加载的接口。

  3. 通过从Web应用程序类加载器加载接口。 这基本上与应用程序服务器本身用来调用HttpServlet的方法相同:接口由服务器加载,因此它可以直接引用它,但是实现是在应用程序的子类加载器中进行的。 您只是为了自己的方便而创建了第二层接口/ Impl拆分。

  4. 如果将对子类加载器(或其加载的类,或这些类中的实例化对象)的引用存储在“父”类加载器中(例如,如果单例注册了一个MBean,则导致其泄漏),最终将导致内存泄漏。以在JVM范围的对象中被引用),但这与您没有创建子类加载器的情况没有什么不同。 如果要动态创建/销毁这些单例(因此是子类加载器),则必须注意不要将对这些子类加载器(或类/对象)的引用保留的时间不要超过必需的时间。 PermGen可能存在更多问题。 如果您可以使用Java 8来运行,那就已经不复存在了。 否则,您可能必须增加默认的PermGen大小,具体取决于您需要创建多少个此类装入器/单个装入器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM