java 在两个 WAR 之间共享应用程序上下文?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5394781/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sharing an application context between two WARs?
提问by Stefan Kendall
Is there a way to share an app-context between two deployed wars? One war needs to wire-in the services of another, and I don't know where to start with this.
有没有办法在两次部署的War之间共享应用程序上下文?一场War需要连接另一场War,我不知道从哪里开始。
回答by Richard J. Smith
Our team just had the same requirement--to share Spring beans between multiple WARs in Tomcat, and honestly, answers such as, "Don't do that," are not helpful.
我们的团队只是有相同的要求——在 Tomcat 中的多个 WAR 之间共享 Spring bean,老实说,诸如“不要那样做”之类的答案没有帮助。
The requirement stems from the fact that we have a multi-WAR application running on Tomcat, and all of the WARs need access to the same RDBMS for persisting information. We are using Spring and Hibernate to access the RDBMs, and all of the WARs share the same schema and ideally can use the same Hibernate SessionFactory and Spring transaction manager.
该要求源于这样一个事实:我们有一个多 WAR 应用程序在 Tomcat 上运行,并且所有 WAR 都需要访问相同的 RDBMS 以保存信息。我们使用 Spring 和 Hibernate 来访问 RDBM,并且所有 WAR 共享相同的模式,理想情况下可以使用相同的 Hibernate SessionFactory 和 Spring 事务管理器。
The answer on how to do it was posted here:
如何做到这一点的答案张贴在这里:
StackOverflow: Sharing ApplicationContext within EAR
StackOverflow:在 EAR 内共享 ApplicationContext
and to summarize, you do the following in your web.xml:
总而言之,您在 web.xml 中执行以下操作:
<context-param>
<param-name>parentContextKey</param-name>
<param-value>sharedContext</param-value>
</context-param>
<context-param>
<param-name>locatorFactorySelector</param-name>
<param-value>classpath:beanRefContext.xml</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:yourWarSpecificAppContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
where beanRefContext.xml contains:
其中 beanRefContext.xml 包含:
<beans>
<bean id="sharedContext" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>classpath:yourSharedAppContext.xml</value>
</list>
</constructor-arg>
</bean>
</beans>
This uses the Spring ContextSingletonBeanFactoryLocatorto expose and share the parent context (in this case using the name "sharedContext"). The shared context will be lazily loaded when the first WAR references it.
这使用 Spring ContextSingletonBeanFactoryLocator来公开和共享父上下文(在本例中使用名称“sharedContext”)。当第一个 WAR 引用它时,共享上下文将被延迟加载。
Whatever beans you reference in the shared context have to be accessible to all of the WARs, which means that they cannot be loaded from WEB-INF/classes or WEB-INF/lib within a specific WAR. They must be shared, either using an EAR file, or by putting the jars that contain the beans (and dependencies) in the Tomcat shared "lib" folder ($CATALINA_HOME/lib), which is what our team did.
您在共享上下文中引用的任何 bean 都必须可供所有 WAR 访问,这意味着它们不能从特定 WAR 中的 WEB-INF/classes 或 WEB-INF/lib 加载。它们必须共享,要么使用 EAR 文件,要么将包含 bean(和依赖项)的 jar 放在 Tomcat 共享的“lib”文件夹 ($CATALINA_HOME/lib) 中,这正是我们团队所做的。
Fair warning that if you use this approach, you are likely to have most of your JARs located in the shared lib folder and not in individual webapps. For our project, this made sense because most of the webapps share and access the same back-end services.
公平警告,如果您使用这种方法,您的大部分 JAR 可能位于共享的 lib 文件夹中,而不是位于单个 web 应用程序中。对于我们的项目,这是有道理的,因为大多数 web 应用程序共享和访问相同的后端服务。
Since the hardcore Tomcat developers are likely to object to putting lots of code into the Tomcat shared lib directory, I'll just enumerate some reasons why the other suggested answers might not work.
由于铁杆 Tomcat 开发人员可能反对将大量代码放入 Tomcat 共享库目录中,因此我将列举一些其他建议答案可能不起作用的原因。
- Using separate application contexts for each WAR would mean having multiple connection pools to the database, one for each WAR, and separate initialization of expensive Hibernate SessionFactory for each WAR, which increases server start time and memory consumption. More generally, it does not allow the state of shared back-end services to be shared across webapps running in the same Tomcat.
- Putting the persistence code into a separate WAR and using REST calls, at least in our case, is totally inconvenient for developers, and increases the path length to get to the database compared with direct calls to shared beans.
- 为每个 WAR 使用单独的应用程序上下文意味着有多个连接池到数据库,每个 WAR 一个,并且为每个 WAR 单独初始化昂贵的 Hibernate SessionFactory,这会增加服务器启动时间和内存消耗。更一般地说,它不允许在同一 Tomcat 中运行的 web 应用程序之间共享共享后端服务的状态。
- 将持久性代码放入单独的 WAR 并使用 REST 调用,至少在我们的例子中,对开发人员来说是完全不方便的,并且与直接调用共享 bean 相比,增加了到达数据库的路径长度。
回答by Jeff DQ
The general purpose of a web application container like tomcat is that each application is able to run independently (so you can stop and start individual apps without affecting others), which means that there has probably been a lot of effort put into their development specifically to prevent you from doing this. So even if you find a loophole, I would suggest against using it unless it is recommended or at least sanctioned by the designers.
像 tomcat 这样的 Web 应用程序容器的一般目的是每个应用程序都能够独立运行(因此您可以停止和启动单个应用程序而不会影响其他应用程序),这意味着他们的开发可能已经投入了大量精力专门用于阻止你这样做。所以即使你发现了一个漏洞,我也建议不要使用它,除非它被设计者推荐或至少得到批准。
I suggest you start looking for other solutions. For example:
我建议您开始寻找其他解决方案。例如:
- Do you really need to share the object instances? If they are stateless you may not need to, and you can simply run a copy of the context in each app.
- Can you separate the code that you're trying to share into a third WAR that exposes a rest service? Or maybe one of the existing WARs could act as the service.
- 你真的需要共享对象实例吗?如果它们是无状态的,您可能不需要,您只需在每个应用程序中运行上下文的副本。
- 您能否将您尝试共享的代码分成第三个公开休息服务的 WAR?或者,现有的 WAR 之一可以充当服务。
回答by ilker
There is an informative blog post I think you should check out: Using a shared parent application context in a multi-war Spring application
有一篇内容丰富的博客文章,我认为您应该查看:Using a shared parent application context in a multi-war Spring application
回答by moritz
There is maybe a way if you start an embedded jetty server and access both web apps from the class where you start and configure the jetty server.
如果您启动嵌入式码头服务器并从您启动和配置码头服务器的课程中访问两个 Web 应用程序,则可能有一种方法。
See:
看:
回答by mindas
You could possibly bind a context to JNDI if it doesn't exist.
如果上下文不存在,您可能会将其绑定到 JNDI。
The price for this is that each webapp's context somehow has to be aware that it might not be the primary.
这样做的代价是每个 webapp 的上下文都必须以某种方式意识到它可能不是主要的。
Also, you need to be really careful about race conditions, e.g.
此外,您需要非常小心竞争条件,例如
- first webapp starts, detects that there is no context
- first webapp starts to build the context
- second webapp starts, detects that there is no context
- second webapp starts to build the context
- first webapp finishes to build the context, binds it
- second webapp finishes to build the context, binds it
- congratulations, you have lost all beans from the context of the first webapp
- 首先webapp启动,检测到没有上下文
- 首先 webapp 开始构建上下文
- 第二个webapp启动,检测到没有上下文
- 第二个 webapp 开始构建上下文
- 第一个 webapp 完成构建上下文,绑定它
- 第二个 webapp 完成构建上下文,绑定它
- 恭喜你,你已经从第一个 webapp 的上下文中丢失了所有的 bean
回答by matt b
Do you need to share the runtimecontext, or do you want to just re-use bean definitions across the two applications?
您需要共享运行时上下文,还是只想在两个应用程序中重用 bean 定义?
If it is only the latter then you could easily extract the common Spring context XML files into some shared dependency, and just re-use the JAR across the two webapps. However if you need the beans/services in each application to talkto each other, you need a different option.
如果只是后者,那么您可以轻松地将常见的 Spring 上下文 XML 文件提取到某个共享依赖项中,并且只需在两个 Web 应用程序中重用 JAR。不过,如果你需要的豆/在每个应用服务通话对方,你需要一个不同的选择。
回答by Reed Sandberg
Agreed with @RichardSmith, the accepted answer was not helpful for me. While Richard's answerwas helpful in pointing me in the right direction, I'm using Jetty so I can't use EAR. I ended up using the server context to share an object(s) between wars - works even with hot-(re)deployed webapps:
同意@RichardSmith,接受的答案对我没有帮助。虽然理查德的回答帮助我指明了正确的方向,但我使用的是 Jetty,所以我不能使用 EAR。我最终使用服务器上下文在War之间共享一个对象 - 即使使用热(重新)部署的 web 应用程序也能工作:
https://stackoverflow.com/a/46968645/1287091
https://stackoverflow.com/a/46968645/1287091
Probably a way to adapt this for Tomcat as well.
可能也是针对 Tomcat 进行调整的一种方法。