使用特殊的自动启动 servlet 在启动时进行初始化并共享应用程序数据 [英] Using special auto start servlet to initialize on startup and share application data

查看:24
本文介绍了使用特殊的自动启动 servlet 在启动时进行初始化并共享应用程序数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要进行一些配置并在某处连接到外部资源/对象/系统并将其存储在应用程序范围内.

我可以看到两种设置我的应用程序的方法:

  • 覆盖现有 servlet 中的 init() 和所需代码,并将所有构造的对象保留在同一个 servlet 中.
  • 拥有某种初始化 servlet 并使用它的 init() 来完成这项工作.然后将创建的对象存储在 ServletContext 中,以便与我的其他 servlet 共享.

以上哪种方法更好?有没有更好的方法在 servlet 之间共享对象?直接从彼此之间调用它们......?

解决方案

两者都不是更好的方法.Servlet 旨在侦听 HTTP 事件(HTTP 请求),而不是部署事件(启动/关闭).


CDI/EJB 不可用?使用 ServletContextListener

@WebListener公共类 Config 实现 ServletContextListener {公共无效上下文初始化(ServletContextEvent 事件){//在 webapp 启动期间做一些事情.}公共无效 contextDestroyed(ServletContextEvent 事件){//在 webapp 关闭期间做一些事情.}}

如果您还没有使用 Servlet 3.0 并且无法升级(因为 Servlet 3.0 是十多年前推出的,这将是时候了),因此无法使用 @WebListener注解,则需要在 /WEB-INF/web.xml 中手动注册,如下所示:

<listener-class>com.example.Config</listener-class></听众>

要在应用程序范围内存储和获取对象(以便所有 servlet 都可以访问它们),请使用 ServletContext#setAttribute()#getAttribute().p>

这是一个让监听器将自身存储在应用程序范围内的示例:

 public void contextInitialized(ServletContextEvent event) {event.getServletContext().setAttribute("config", this);//...}

然后在 servlet 中获取它:

 protected void doGet(HttpServletRequest request, HttpServletResponse response) {Config config = (Config) getServletContext().getAttribute("config");//...}

它也可以通过 ${config} 在 JSP EL 中使用.所以你也可以让它成为一个简单的 bean.


CDI 可用吗?使用 @Observes关于 ApplicationScoped.class

import jakarta.enterprise.context.ApplicationScoped;//因此不是,例如jakarta.faces.bean.ApplicationScoped@ApplicationScoped公共类配置{公共无效初始化(@Observes @Initialized(ApplicationScoped.class) ServletContext 上下文){//在 webapp 启动期间做一些事情.}公共无效销毁(@Observes @Destroyed(ApplicationScoped.class)ServletContext 上下文){//在 webapp 关闭期间做一些事情.}}

这可以通过 @Inject 在 servlet 中使用.如有必要,也可以使用 @Named 以便它也可以通过 EL 中的 #{config} 获得.

值得注意的是,这是自 CDI 1.1 以来的新功能.如果您仍在使用 CDI 1.0 并且无法升级,请选择其他方法.

如果您对如何在 Tomcat 等非 JEE 服务器上安装 CDI 感到好奇,请访问:如何在Tomcat上安装和使用CDI?


EJB 可用吗?考虑 @Startup@Singleton

@Startup@Singleton公共类配置{@PostConstruct公共无效初始化(){//在 webapp 启动期间做一些事情.}@PreDestroy公共无效销毁(){//在 webapp 关闭期间做一些事情.}}

这可以通过 @EJB 在 servlet 中使用.与其他方法的不同之处在于它默认是事务性的,并且在 @Singleton 的情况下也读/写锁定.因此,如果您需要将随机 EJB(例如 @Stateless)注入到 @WebListener@ApplicationScoped 中,那么您基本上可以像很好地将两者合并到一个 @Startup @Singleton.

另见:

I need to get some configuration and connect to external resources/objects/systems somewhere and store it in application scope.

I can see two ways to setup my application:

  • Overriding the init() in the existing servlets and required code there and keeping all constructed objects inside that same servlet.
  • Having some kind of an initialisation servlet and using its init() to do the work. Then storing created objects in ServletContext to share it with my other servlets.

Which out of above is better approach? Is there any better way to share objects between servlets? Calling them directly from one another or so...?

解决方案

None of both is the better approach. Servlets are intended to listen on HTTP events (HTTP requests), not on deployment events (startup/shutdown).


CDI/EJB unavailable? Use ServletContextListener

@WebListener
public class Config implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
        // Do stuff during webapp's startup.
    }

    public void contextDestroyed(ServletContextEvent event) {
        // Do stuff during webapp's shutdown.
    }

}

If you're not on Servlet 3.0 yet and can't upgrade (it would be about time because Servlet 3.0 was introduced more than a decade ago), and thus can't use @WebListener annotation, then you need to manually register it in /WEB-INF/web.xml like below:

<listener>
    <listener-class>com.example.Config</listener-class>
</listener>

To store and obtain objects in the application scope (so that all servlets can access them), use ServletContext#setAttribute() and #getAttribute().

Here's an example which lets the listener store itself in the application scope:

    public void contextInitialized(ServletContextEvent event) {
        event.getServletContext().setAttribute("config", this);
        // ...
    }

and then obtain it in a servlet:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        Config config = (Config) getServletContext().getAttribute("config");
        // ...
    }

It's also available in JSP EL by ${config}. So you could make it a simple bean as well.


CDI available? Use @Observes on ApplicationScoped.class

import jakarta.enterprise.context.ApplicationScoped; // And thus NOT e.g. jakarta.faces.bean.ApplicationScoped

@ApplicationScoped
public class Config {

    public void init(@Observes @Initialized(ApplicationScoped.class) ServletContext context) {
        // Do stuff during webapp's startup.
    }

    public void destroy(@Observes @Destroyed(ApplicationScoped.class) ServletContext context) {
        // Do stuff during webapp's shutdown.
    }
}

This is available in a servlet via @Inject. Make it if necessary also @Named so it's available via #{config} in EL as well.

Noted should be that this is new since CDI 1.1. If you're still on CDI 1.0 and can't upgrade, then pick another approach.

In case you're curious how to install CDI on a non-JEE server such as Tomcat, head to: How to install and use CDI on Tomcat?


EJB available? Consider @Startup@Singleton

@Startup
@Singleton
public class Config {

    @PostConstruct
    public void init() {
        // Do stuff during webapp's startup.
    }

    @PreDestroy
    public void destroy() {
        // Do stuff during webapp's shutdown.
    }
}

This is available in a servlet via @EJB. The difference with other approaches is that it's by default transactional and in case of @Singleton also read/write locked. So if you would ever need to inject a random EJB (e.g. @Stateless) into a @WebListener or an @ApplicationScoped then you could basically as good merge both into a single @Startup @Singleton.

See also:

这篇关于使用特殊的自动启动 servlet 在启动时进行初始化并共享应用程序数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆