在Web应用程序中,提供用户界面(UI)通常只是工作的一半。 许多应用程序都有后端服务支持的要求。 后端服务的一些示例是调度程序进程(批处理),侦听队列并在消息进入时作出响应,或者是简单的事情,例如存储供整个应用程序使用的信息。 这些全局数据通常需要在所有Servlet类(对于每个请求处理器)之间共享。 在这里,我将向您展示如何在基于Servlet的应用程序中以及在何处添加此类后端服务。
在开始之前,我想解释一下Servlet应用程序如何存储数据变量(毕竟所有后端服务只是Java对象)。 您可以在3个主要区域中添加和共享数据(我们有时将这些区域称为不同的“空间”,“范围”或“上下文”)。 您可能还会将每个区域都视为具有唯一键和数据值的哈希映射。
- 应用程序范围 –这是为您的Web应用程序实例分配的全局,应用程序范围的存储映射空间。 每个Web应用程序都有其独特的空间。 即使将相同的WAR文件部署到域服务器中,它们每个都将获得自己的空间。 您可以通过实现
javax.servlet.ServletContextListener
接口来获取此空间。 此接口还具有两个回调方法,当您的应用程序启动(初始化)或关闭(销毁)时将调用它们。 使用这些方法,您可以执行自己的一次性应用程序或服务设置和清理逻辑。 您可以使用ServletContext#setAttribute(key, value)
方法存储任何Java对象。 此存储在外部不是持久性的,而仅在服务器内存中。 因此,添加的内容越多,所需的内存就越多(通常您只想保留对服务对象的引用,因此通常不会出现内存问题)。 这是您应该在其中创建后端服务并对其进行初始化,然后将实例添加到该空间中的位置,以便稍后可以检索它。您还可以使用Singleton Pattern创建一个Application范围的上下文区域,以将您自己的业务服务作为空间保存,但是如果需要在Web应用程序环境中对其进行初始化,则仍然需要
ServletContextListener
。 - 请求范围 –这是单个HTTP请求过程存储映射空间,仅针对特定请求或临时退出。 该地图空间也不是持久的。 您可以通过处理一种HTTP操作方法来访问Servlet代码中的该空间。 您将使用
HttpServletRequest#setAttribute(key, value)
方法添加数据。 通常,这些存储的数据用于传递到VIEW处理层(例如JSP)以构造HTML输出。 您已经看过我的一些预览文章,该文章在Servlet组件中使用了该文章。还要注意,在处理请求的Servlet方法内部,您还将可以使用
HttpServletRequest#getServletContext()#getAttribute(key)
方法访问上述“应用程序空间”方法。 - 会话范围 –这是一个特殊的空间,您可以在其中跟踪特定的用户与应用程序的交互,作为一系列的会话请求,或称为用户会话。 请记住,HTTP请求是无状态的,因此,如果要存储一些数据以在多个请求之间共享,则将需要此空间,但是对于每个客户端浏览器用户,它们应该是隔离的。 通常在应用程序中实现用户登录和资源限制时使用。 您可以使用Serlvet类中的
HttpServletRequest#getSession(true)#setAttribute(key, value)
方法添加到此空间。 每次针对该特定客户端用户,application
服务器将自动为您返回相同的会话对象或空间。
但是,处理用户会话可能很棘手,因此您必须花时间并仔细设计应用程序,以实现需要的适当解决方案。 我将在未来写一篇单独的文章,介绍如何使用Session作用域,但是现在,我可以向您展示如何使用内部自定义服务初始化Web应用程序的示例。 您可以在我的servlet3-example中找到此代码。
package zemian.servlet3example.web;import javax.servlet.ServletContext;
import zemian.servlet3example.service.Application;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import zemian.service.logging.Logger;@WebListener
public class WebAppStartup implements ServletContextListener {private static final Logger LOGGER = new Logger(WebAppStartup.class);@Overridepublic void contextInitialized(ServletContextEvent event) {LOGGER.debug("WebApp is starting up.");Application app = Application.getInstance();app.init();// Store the app instances. event.getServletContext().setAttribute(Application.SERVLET_CONTEXT_KEY, app);LOGGER.info("WebApp initialized."); }@Overridepublic void contextDestroyed(ServletContextEvent event) {Application app = Application.getInstance();app.destroy();LOGGER.info("WebApp destroyed.");}
}
有了这个,我可以轻松地在Application
类中添加任何自定义业务后端服务,然后让任何Servlet代码访问它。 注意,我使用的是Servlet 3的@WebListener
批注,因此不需要配置。 您只需将WAR应用程序打包在一起,它将被EE应用程序服务器检测到!
翻译自: https://www.javacodegeeks.com/2015/01/ee-servlet-3-how-to-setup-backend-services-in-a-web-application.html