是否可以在公共/共享上下文中使用 Spring 库?
我们有一个门户应用程序,其中包含一个主 Web 应用程序上下文和许多次要 Web 应用程序上下文 - 插件。目前(非常简单),Main 有自己的 spring 库,如果插件想要使用 spring,则也必须拥有它们。在公共/共享 tomcat 上下文中,只有驱动程序和接口。
如果将 spring 库移至与 spring 可能间接使用或可能使用 spring 的其他库相关的公共上下文,它会起作用吗?就像 hibernate 一样,因为应用程序正在使用 spring-tx 等。hibernate 也必须转移到公共/共享上下文吗?
您觉得怎么样,其他方面还有哪些?从 Spring 应用程序上下文的角度来看,这样会容易得多。
We have a portal application with one Main web app context and many minor web app contexts - plugins. Currently (very simplified) the Main one has own spring libraries and plugins would have to have them also if they wanted to use spring. In common/shared tomcat context there are just drivers and interfaces.
Would it work if spring libraries were moved to common context in regards to other libraries that spring might indirectly use or they might use spring ? Like hibernate, because the apps are using spring-tx etc. Would hibernate have to move to common/shared context too ?
What do you think, what are the other aspects ? From spring application context point of view it would be much easier like this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
@RichW 正确地指出,将 Spring 库放置在 Tomcat 的公共类加载器中是不好的做法。而且很有可能行不通。
Java 使用类加载器层次结构)。当请求类加载时,类加载器将递归地从其父类加载器请求该类,然后尝试使用它自己的类路径加载该类。此过程一直持续到根类加载器(称为引导类加载器)。通过这种方式,从父类加载器引用的类始终比层次结构中更下方的类加载器中引用的类具有优先级。
需要注意的是,在此过程中,类永远不会从子类加载器中加载。因此,Spring 所需的任何类也需要加载到公共类加载器中 - 包括 asm、log4j、commons-logging 和 cglib(所有这些都是 spring 所依赖的)。这将导致一系列问题:特别是,在公共类路径中包含公共日志记录是整个世界伤害
如果你真的成功启动了 Tomcat,那么在回收应用程序时你就会遇到内存泄漏的问题。在 tomcat 中,应用程序是使用传统的垃圾收集来卸载的,因此,如果有任何内容保存了对随后重新启动的应用程序内的类的引用,则该应用程序将不会获得垃圾收集。 Spring 和日志框架是保存类引用的主要候选者,因此在几次应用程序重新启动后,您可能会遇到 OOM 错误。
安全地执行此操作的唯一方法是考虑使用成熟的应用程序服务器(例如 JBoss AS)并将应用程序部署为 EAR。
@RichW is correct in stating that placing Spring libraries in Tomcat's common classloader is bad practice. And there's a good chance it won't work.
Java uses a classloader hierarchy). When a class load is requested, the classloader will recursively request the class from it's parent classloader before attempting to load the class using it's own classpath. This process continues up to the root classloader (know as the bootstrap classloader). In this way, classes referenced from a parent classloader always get priority over classes referenced in classloaders further down the hierarchy.
It's important to note that in this process classes are never loaded from a child classloader. Therefore any classes required by Spring would also need to be loaded into the common classloader - including asm, log4j, commons-logging and cglib (all of which spring depends on). This will lead to a whole host of problems: in particular, including commons-logging in the common classpath is a whole world of hurt
If you actually managed to get Tomcat started, then you would experience problems with memory leaks when recycling applications. In tomcat, applications are unloaded using conventional garbage collection, so if anything holds a reference to a class inside an application which has subsequently been restarted, that application will not get garbage collection. Spring and logging frameworks are prime candidates for holding references to classes so you will probably suffer from OOM errors after a few application restarts.
The only way to do this safely would be to consider using a full blown application server (such as JBoss AS) and deploy your application as an EAR.
如果您能够从 Tomcat 迁移到成熟的 Java EE 容器,那么可以选择将所有内容打包为 EAR 使用捆绑可选类机制。
然后,您可以将通用 JAR 从 WAR 和 WAR 中移出。进入 EAR 的顶层。
If you were able to move from Tomcat to a full-blown Java EE container then an option would be to package everything as an EAR using the Bundled Optional Classes mechanism.
You'd then move the common JARs out of the WARs & into the top level of the EAR.
是的,我知道这很诱人。是的,它可以工作。但是,有些人认为将特定于应用程序或特定于框架的库放在应用程序服务器的共享库文件夹中是一种不好的做法,我同意。
在我看来,网络应用程序应该包含自己的依赖项(应用程序 jar、框架 jar 等)。框架也有依赖性,通常需要多个具有特定版本的 jar。有时这些版本会发生变化,有时依赖关系会发生变化。随着时间的推移,共享库文件夹将成为罐子的厨房水槽,这可能会以不可预测的方式影响您的所有应用程序。
走共享库文件夹路线,你会获得一些初步的便利,但你失去的是选择:一次只影响一个网络应用程序的选择。我建议您将 jar 放在您的网络应用程序中,很好地包含并与其他网络应用程序分开。这将使它们更加可靠,并且您会发现框架升级更容易处理。从长远来看,你会更快乐,我向你保证。
Yes, I know it's tempting. Yes, it can work. But putting application-specific or framework-specific libraries in the shared libraries folder of an app server is considered by some to be a bad practice, and I agree.
In my opinion web-apps should contain their own dependencies (app jars, framework jars, etc.). Frameworks also have dependencies, often requiring multiple jars with particular versions. Sometimes these versions change, sometimes the dependencies change. Over time that shared library folder will become a kitchen sink for jars, and that will affect all your apps, perhaps in unpredictable ways.
Going the shared library folder route you gain some slight initial convenience, but what you lose is choice: the choice to only affect one web-app at a time. I recommend you keep your jars within your web-app, nicely contained and separate from the other web-apps. It will make them more reliable and you'll find framework upgrades easier to handle. You'll be happier in the long run, I promise you.