【问题标题】:JNDI lookup in a servlet's init parameter a good idea?在 servlet 的 init 参数中查找 JNDI 是个好主意吗?
【发布时间】:2013-04-14 01:29:14
【问题描述】:

我目前正在构建一个 Java EE Web 应用程序,发现 this 文章为我提供了一些关于如何构建更好的应用程序的重要指导。第一个技巧是“使用 HttpServlet init() 方法缓存数据”。这听起来像是一个天才的想法,但现在我已经实现了自己的版本,我担心线程安全和保持连接打开。

  1. 这个想法,以及我实现它的方式是线程安全的,以确保每个线程都有自己的数据库连接吗?
  2. 我知道,只要我想更改 JNDI 查找,这需要重新启动 servlet,我对此没有意见,但不只是在 JDBC 方法中进行 JNDI 查找还有其他缺点吗?
  3. 我使用 destroy 方法关闭上下文变量的方式是一个聪明的想法,还是在大量线程或任何其他障碍的情况下这不起作用?

这里有一些代码可以让您了解我是如何实现这个想法的。在我在我的 40 个其他 servlet 上实现它之前,我想要一些关于我的第一个实现的指导。非常感谢您的阅读。哦,如果有帮助的话,我也可以添加 dao 方法。

Servlet 说明:在 init 中,我只调用了一个 bean,它完成了所有 JNDI 绒毛,以便更容易地添加到多个 servlet。然后在servelt中,我将数据源发送到要使用的dao方法。我还认为在启动时添加负载是明智之举,这样我就可以在启动服务器时查看 JNDI 是否立即工作。

@WebServlet(name="GetBoardPostCommenters", urlPatterns={"/getBoardPostCommenters"}, loadOnStartup = 1)
public class GetBoardPostCommenters extends HttpServlet
{
    private InstrideJndi jndi = null;
    private static final long serialVersionUID = 1L;

    public void init(ServletConfig servletConfig) throws ServletException
    {
        super.init(servletConfig);
        jndi = new InstrideJndi("GetBoardPostCommenters");
    }

    public void destroy()
    {
        jndi.closeConnection();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
    {
        BoardPost boardPost;

        boardPost = new BoardPost();
        boardPost.setId(Long.parseLong(request.getParameter("boardPostId")));
        boardPost = BoardPostCommentLikeDAO.getBoardPostCommenters(boardPost, jndi.getDataSource());

        request.setAttribute("likerCommenterList", boardPost.getCommenterList());
        request.getRequestDispatcher("WEB-INF/util/likerCommenterList.jsp").forward(request, response);
    }
}

Bean 注释:控制器获取调用此方法的 servlet 的名称以帮助调试。而 close 连接完成了我通常在 dao 方法的 finally 中所做的事情。

public class InstrideJndi
{
    private DataSource dataSource = null;
    private Context initialContext = null;
    private Context environmentContext = null;

    public InstrideJndi(String className)
    {
        try
        {
            this.initialContext = new InitialContext();
            this.environmentContext = (Context) initialContext.lookup("java:/comp/env");
            this.dataSource = (DataSource) environmentContext.lookup("jdbc/instride");
        }
        catch(NamingException error)
        {
            System.out.println("Error With JNDI Lookup -  " + className + " - " + error.getMessage());
            error.printStackTrace();
        }
    }

    public DataSource getDataSource()
    {
        return this.dataSource;
    }

    public void closeConnection()
    {
        if (initialContext != null) try{initialContext.close();} catch(NamingException ignore) {}
        if (environmentContext != null) try{environmentContext.close();} catch(NamingException ignore) {}
    }
}

【问题讨论】:

    标签: java performance jakarta-ee jdbc jndi


    【解决方案1】:

    每个线程在此处都有自己的 DataSource 引用。您的 servlet 将是跨多个请求线程的一个实例,每个线程调用 doGet()。相反,init() 仅在 web 模块启动时调用,在 servlet 实例服务请求之前。

    另一个提示 - 在一次查找中检索容器管理的资源是相当常见的。

    this.dataSource = new InitialContext().lookup("java:/comp/env/jdbc/instride");
    

    我可能是错的,但我通常不会 close() 这些类型的 InitialContext 实例,除非我特别期望它是网络操作(ldap、从远程应用程序服务器查找资源等)。

    【讨论】:

    • 感谢您查看我的问题。需要明确的是,我所做的很好(线程安全),我可以用你给出的例子来缩短我的代码,让它更清晰一些。但我所拥有的应该不会造成问题吧?
    • 在我的 Web 应用程序的整个生命周期内(直到下一次重新启动)都打开这些查找会好吗?
    • 我没有预见到任何问题。如果您查看使用注入(通过@Resource)获取容器管理资源(如 DataSource 实例)的教程,它们通常是成员或类级别(静态)变量,因此它们在请求之间共享。只要确保你总是 .close() 从共享数据源获得的连接。
    猜你喜欢
    • 2014-10-15
    • 2013-04-05
    • 2012-10-16
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 2020-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多