0

我目前正在构建一个 Java EE Web 应用程序,并发现这篇文章给了我一些关于如何构建一个更好的应用程序的很好的指导。第一个技巧是“使用 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 Notes:控制器获取调用此方法以帮助调试的 servlet 的名称。关闭连接完成了我通常在 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) {}
    }
}
4

1 回答 1

2

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

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

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

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

于 2013-04-14T02:04:07.987 回答