我有一个基于Struts的web应用程序,其结构类似于下面所示的。(不是这只是一个例子)
$TOMCAT_HOME/webapps/myapp
|-css
|-myapp.css
|-js
|-myapp.js
|-forum
|-index.jsp
|-list.jsp
|-users.jsp
|-Articles
|-index.jsp
|-ListArticles.jsp
|-Guestbook
|-viewGuestBook.jsp
|-AddnewEntry.jsp
|-WEB-INF
|-classes
com
|-myapp
|-forum
|-DisplayForum.class
|-ListUsers.class
|-article
|-ArticleList.class
|-AddArticle.class
|-guestbk
|-LoadGuestBook.class
|-ProcessGuestBook.class
目前,该应用程序是使用ANT构建的,并作为单个war文件(名为myapp.war)部署到Tomcat应用服务器上。我想分开的应用程序,使其部署使用多个战争文件的每个模块。(即论坛。战争的文章。War和留言簿(War)。新war文件的内容将只包含与模块相关的文件。例如,论坛。War文件将包含
$TOMCAT_HOME/webapps/forum
|-forum
|-index.jsp
|-list.jsp
|-users.jsp
|-WEB-INF
|-classes
com
|-myapp
|-forum
|-DisplayForum.class
|-ListUsers.class
对于这种方法,有几件事我不确定。
共享静态资源
*.css和*.js文件在每个war文件中都是通用的。如果我有不同的战争文件,我将有一个副本的css文件在每个战争文件。是否有任何方式,我可以提供资源文件(css, js,静态文件)在一个共同的方法,使他们共享。我想也许我应该包括一个新的战争文件称为共同。War和包含共享的静态数据。(我认为其他战争文件可以使用URL访问这些文件,因为它们是静态资源。对吧?)
共享类
有些类是全局共享的。举个例子,有一个类叫做UserSession
。当用户登录到应用程序时,创建UserSession对象并将其存储在Hashtable中,并将用户的会话id作为Hashtable的键。每当用户尝试访问应用程序的任何部分时,都会根据Hashtable中的会话id检查会话id。
UserSession对象做很多事情——比如
- 验证用户登录
- 跟踪用户活动
- 记录用户登录历史到数据库
- 等等……
我需要所有的war文件(应用程序/模块)都可以访问UserSession
对象,但是每个会话只关联一个。我应该如何构建它,以便用户的会话跨越不同的war文件?
我一直在阅读有关如何共享对象的文章,并提出了两个选项
- 通过JNDI共享对象
- 通过Tomcat ServletContext共享对象
据我所知,如果一个对象存储在ServletContext
中,它可以被任何应用程序(即war文件)访问。如果我想要每个用户会话的不同实例,这将如何工作。例如
User1登录- UserSession存储在ServletContext中User2登录-我在哪里存储User2的UserSession对象?
目前,我将sessionID存储在HTTPSession
中,UserSession
对象存储在HashTable中。
HttpSession session = request.getSession(true);
UserSession userSession = getUserSession(session.getId());
User1是否获得相同的sessionId,而不管他/她正在访问的war文件?如果是这样,我可以在ServletContext
中存储另一个包含sessionid的列表对象吗?
我还看到了使用JNDI的对象共享的引用。我对JNDI不是很熟悉。我对数据源使用了JNDI,但仅此而已。它究竟是如何运作的?如果有人能给我提供一个示例,说明如何使用JNDI来共享数据,我将不胜感激。JNDI真的是更好的方法吗?为什么?
最后,UserSession.class
文件驻留在哪里?我知道我可以把它放在一个jar文件在$TOMCAT_HOME/lib
,但这通常不推荐。问题是,如果它在一个战争文件的WEB-INF/lib
文件夹中,它不能被任何其他战争文件访问。
希望能得到一些建议。我很想知道您使用什么策略来部署由多个war文件组成的应用程序。
感谢编辑
好吧,我忘了说为什么我想分割战争文件。基本上,我们有几个开发团队。我们遇到过这样的情况:一个团队在开发应用程序的特定区域,而另一个团队在开发不同的区域。
例如,假设以下场景-
Team1正在开发论坛模块,预计下个月发布。Team2已经被要求交付对文章的修改,应该会在下周发布。
如果Team1已经签入了他们的代码,并且正在执行系统/集成测试,这将花费超过一周的时间,那么Team2就被填满了,因为他们必须等待。
这类问题通常使用分支来解决,但我们倾向于避免分支,因为它引入了许多合并的复杂性,所以我们决定避免分支。
另一个原因是我们有一个旧的应用程序,我正在考虑重用这个应用程序。旧的基于纯HTTPServlet的应用程序。即不基于任何框架(即结构,弹簧等)。如果我想集成它与我现有的应用程序,我将需要使用会话/servletcontext。
而且,很多人都怀疑这样一个事实:如果你做了一个简单的改变(例如,你在一个css文件中添加了一个新的样式表定义),你必须重新构建和重新部署整个应用程序。
其他原因包括
- 可以简化可伸缩性/负载平衡-(可能?)这个不太确定。我正在考虑将每个战争文件部署到不同的服务器/集群。
- 降低PERMGEN内存需求
- 等等…
我不确定你是否正确理解,但是HttpSession对于每个用户(浏览器会话)和每个应用程序都是不同的,AFAIK,所以你不能用它来共享数据。
基本上,你需要在你的web应用程序之间进行通信。您可以使用一个war作为UserSession的数据管理器,而所有其他war都与此进行通信。数据管理器应用程序需要公开一个服务,例如UserSessionManager,它可以通过其他应用程序访问。 JNDI是这方面的传统解决方案。Spring对此提供了一些帮助,但是JNDI API也不是太复杂。在数据管理器之争中,您可以在初始化方法中执行如下操作:DataManager mgr = new DataManagerImpl(...);
InitialContext ic = new InitialContext();
ic.rebind("java:global/env/datamanager", mgr);
你使用的接口和数据对象需要放在一个jar中,在所有的"客户端"战争中共享,实现只在数据管理器战争中。在客户机大战中,您可以这样做:
InitialContext ic = new InitialContext();
DataManager mgr = (DataManager)ic.lookup("java:global/env/datamanager");
希望这有帮助,基尔特•。
如果Team1已经签入了他们的代码,并且正在执行将花费一周以上的系统/集成测试,那么Team2就被填满了,因为他们必须等待。
这类问题通常可以使用分支来解决,但我们倾向于避免分支,因为它会给合并带来很多复杂性,因此我们决定避免分支。
嗯,这就是你的问题。这就是分支的作用。如果它给你带来了问题,那么答案就是解决这些问题,而不是完全避免分支。这可能就像切换到一个更好的VCS一样简单。(你现在用的是哪一个?)
而且,很多人都怀疑这样一个事实:如果你做了一个简单的改变(例如,你在单个css文件中添加了一个新的样式表定义),你必须重新构建和重新部署整个应用程序。
这就是Java web应用程序的本质。如果将CSS文件放入单独的war中,那么仍然需要重新构建和重新部署该war。而随着多场战争的爆发,这个过程将变得更加复杂,而不是更简单。
无论如何,每个Java IDE都允许您通过单个按键来完成此操作,因此我不认为这有什么大不了的。
可以简化可伸缩性/负载平衡-(可能?)
可能。但你知道他们怎么说过早的优化。