使用特殊的自动启动 servlet 在启动时进行初始化并共享应用程序数据

发布于 2024-09-14 12:45:29 字数 331 浏览 3 评论 0原文

我需要获取一些配置并连接到某个地方的外部资源/对象/系统并将其存储在应用程序范围中。

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

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

上述哪种方法更好?有没有更好的方法在 servlet 之间共享对象?直接互相打电话或者这样……?

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...?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

剧终人散尽 2024-09-21 12:45:29

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


CDI/EJB 不可用?使用 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.
    }

}

如果您还没有 Servlet 3.0,无法升级(大概是时候了,因为 Servlet 3.0 已经十多年前推出了),因此无法使用 @WebListener 注解,那么你需要手动在 /WEB-INF/web.xml 中注册它,如下所示:

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

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

下面是一个示例,它让侦听器将自身存储在应用程序范围中:

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

然后在 servlet 中获取它:

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

在 JSP EL 中也可以通过 ${config} 获得它。所以你也可以把它变成一个简单的 bean。


CDI可用吗?使用 @Observes关于 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.
    }
}

这可以在 servlet 中通过 @Inject 获得。如有必要,还可以将其设置为@Named,以便在 EL 中也可以通过#{config} 来使用它。

应该注意的是,这是自 CDI 1.1 以来的新内容。如果您仍使用 CDI 1.0 并且无法升级,请选择其他方法。

如果您好奇如何在 Tomcat 等非 JEE 服务器上安装 CDI,请前往:如何在Tomcat上安装和使用CDI?


EJB可用吗?考虑 @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.
    }
}

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

另请参阅:

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:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文