我们有一个用Java制作的Web应用程序,它使用struts2,spring和JasperReport。此应用程序在glassfish 4.0上运行。
应用程序的库位于WEB-INF / lib文件夹中,并且在glassfish中安装了4个以上的库,而不是使用相同的库。
Glassfish配置为使用1024mb用于堆空间,512m用于permgen,当我使用每个应用程序库时,大部分内存消耗都在struts操作和spring aop类中(使用netbeans profiler)。
我们遇到的问题是每个应用程序在类加载器中拥有库所消耗的内存量,因为它很高并且会生成PermGen错误,我们也注意到应用程序运行速度越慢,用户就越多。
因为我们尝试使用共享库,将它放在domain1 / lib文件夹中,发现使用单个部署的应用程序,加载时间和内存消耗要低得多,并且应用程序通常运行得更快。但是当我们在服务器上部署其余的应用程序时,只有第一个加载的应用程序运行良好,其余的在我们调用struts2动作时出错。 我们认为这是因为每个应用程序在struts2和log4j上的设置略有不同。
我们还试图在glassfish上只放置某些库并在应用程序中只留下struts2,但它显示了InvocationTargetException错误,因为所有库都依赖于来自apache-common的lib,如果我们将这些lib放在一个地方或另一个地方就没关系。此外,如果我们将它放在两个地方,应用程序都无法启动。
答案 0 :(得分:3)
使用共享库是否有任何特殊设置或最佳做法?有没有办法使用共享库,但每个应用程序加载设置?或者我们必须更改设置以使它们完全相同?
这些实际上是有趣的问题......我不使用GlassFish,according to the documentation:
特定于应用程序的类加载
[...] 您可以指定模块或特定于应用程序的库类[...]使用带有
--libraries
选项的asadmin deploy命令并指定逗号分隔的路径 [...]规避类加载器隔离
由于每个应用程序或单独部署的模块类加载器Universe都是隔离的,因此应用程序或模块无法从其他应用程序或模块加载类。这可以防止不同应用程序或模块中两个类似命名的类相互干扰。
为了规避由多个应用程序访问的库,实用程序类或单独部署的模块的此限制,您可以通过以下方式之一包含所需类的相关路径:
- 使用Common Class Loader
- 跨群集共享库
- 在另一个应用程序中打包一个应用程序的客户端JAR
使用Common Class Loader
要使用Common类加载器,请将JAR文件复制到
domain-dir/lib
或as-install/lib
目录中,或将.class文件(以及其他所需文件,例如.properties文件)复制到{{ 1}}目录,然后重启服务器。使用Common类加载器使部署在共享相同配置的服务器上的所有应用程序或模块都可以访问应用程序或模块。但是,此可访问性不会扩展到应用程序客户端。有关更多信息,请参阅将库与应用程序客户端一起使用。 [...]
然后我会尝试:
domain-dir/lib/classes
,domain1/lib
,然后运行
domain1/lib/applibs
隔离Struts2库类加载,同时将其余的保持在Common Classloader的控件下。
$ asadmin deploy --libraries struts2-core-2.3.15.2.jar FooApp1.war
$ asadmin deploy --libraries struts2-core-2.3.15.2.jar FooApp2.war
,domain1/lib
下放置Struts2 jar,使用不同名称的不同副本,例如在jar名称附加_appname 然后运行
domain1/lib/applibs
通过异化(模拟)它们的不同版本来防止共享库。
希望有所帮助,请告诉我上述部分是否有效。
答案 1 :(得分:0)
我敢打赌,将lib放在lib /或lib / ext下将无法解决您的性能问题。您没有写任何关于应用程序或服务器设置的内容,例如应用程序的大小,可用的Heap和PermGen空间,但是我建议每个应用程序使用单独的库。
如果将lib放在服务器目录中,它们将在所有应用程序之间共享。您将松开选项,仅将您的一个应用程序升级到新框架或删除其中任何一个。您的部署将绑定到特定的服务器体系结构。
你写的并没有解决你的问题,它甚至可能会引发新问题。
我建议投入几个小时调整服务器。如果它以默认值运行,请分配更多PermGen和HeapSpace。
如果这没有帮助,你应该深入分析出现了什么问题。共享库可能是一个解决方案,但您还不知道问题。 IBM提供了一些很酷的免费工具来分析堆转储,这可能是一个很好的起点。
答案 2 :(得分:0)
您可以尝试创建所谓的skinny WAR。将所有WAR包装在EAR中,并将所有常见JAR从WEB-INF/lib
移动到EAR中的lib/
文件夹(不要忘记在<library-directory>
中设置application.xml
)
答案 3 :(得分:0)
我来到这里寻找有关安装在多个应用程序或项目之间共享的库的指导。我非常失望地看到,公认的做法倾向于将每个共享库的副本安装到每个项目中。因此,如果您有十个Web应用程序,所有这些都使用,例如:例如,httpcomponents-client,mysql-connector-java等,那么你的安装包含每个的十个副本。
这种行为让我痛苦地想起了那种激励我放弃大型机而转向PC的思维方式;我的想法似乎是&#34;我不关心我的应用程序消耗了多少资源。事实上,我希望能够吹嘘自己的资源是什么。&#34;对不起,拜托,当我投掷时。
库公开的界面是一个不可变的合约,在开发人员的突发奇想
这个概念称为向后兼容性。如果你打破它,你可以创建一个新界面。
我知道至少有两种类型的接口符合这些规则的字母和精神。
到目前为止,最古老的是 IBM System / 370系统库。您可能拥有Foo
和Foo2
,其中后者延伸和/或以某种方式违反了Foo
界面所签订的合同,使其不兼容。
从贝尔实验室Unix项目开始,标准C运行时库已遵守上述规则。
虽然它更新, Microsoft COM接口规范强制执行相同的规则。
值得赞扬的是,微软通常也会遵循 Win32 API 中的规则,尽管该API中有一些例外。在某种程度上,他们使用.NET框架向后退,它似乎非常谨慎地遵循它急切寻求替代的Java环境的脚步。
自1978年以来,我一直在使用库,我的理解是将代码放入库中的目的是使其可重用。虽然在每个应用程序中维护库代码的副本消除了为每个新项目再次实现它的需要,但它使升级变得非常复杂,因为您现在有十个(或更多)库的副本,每个副本都必须更新。
如果库遵守接口是不可变合同的规则,为什么它们不应该存在于共享库目录中,就像它所在的{@>系统库一样{{ 1}}目录,主机上运行的所有内容共享标准C运行时库,Zlib等的单个副本。
让我很失望。