Java的Servlet网络通信(一)监听(Listener)

295 阅读2分钟

监听提升程序效率

业务需求 : 在实现用户注册的业务时,需要使用JDBC和MySQL打交道。在这个过程中,最耗时的是连接对象的创建,如何简短程序耗时呢?

Ref : 连接数据库通过console实现简单的java登录操作

根据业务需求,我们引入ServletContextListener这个监听接口,其监听的是全局作用域对象(ServletContext)的初始化和销毁时刻。而全局作用域对象在Http服务器启动时初始化,在服务器关闭时销毁。因此我们可以将JDBC连接对象存储在全局对象中。

监听的步骤

  • 实现ServletContextListener接口的实现类
public class OneListener implements ServletContextListener
  • 重写contextInitializedcontextDestroyed方法
   //监听器监听到全局作用域对象的初始化时调用该方法
   public void contextInitialized(ServletContextEvent sce) {
        JDBCUtil util=new JDBCUtil();
        Map map=new HashMap();
        for (int i = 0; i <20 ; i++) {
            try {
                Connection con=util.getConnection();
                 System.out.println("创建连接"+con);
                //使用con的地址作为key
                map.put(con,true);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
       // map是局部变量,为了保存它,将它放到全局作用域对象中,其生命周期是服务器的启动到关闭
        ServletContext application= sce.getServletContext();
        application.setAttribute("connKey",map);
    }
    
    //监听销毁时刻
     public void contextDestroyed(ServletContextEvent sce) {
          ServletContext application= sce.getServletContext();
          Map map=(Map)application.getAttribute("connKey");
        //获得map所有的keySet  
        Iterator it= map.keySet().iterator();
        //set中的对象是无序的,不能被遍历,可以获得其迭代器
        while (it.hasNext()){
             Connection con=(Connection)it.next();
             if(con!=null){
                 System.out.println("销毁连接"+con);
             }
        }
    }
  • 在WEB-INF的web.xml中注册监听
 <listener>
    <listener-class>com.company.listener.OneListener</listener-class>
 </listener>

在JDBC中使用创建的连接对象

程序设计原则:对扩展开放,对修改关闭。 因此修改原来JDBCUtil工具类的代码需要采用方法重载的方式。

 public Connection getConnection(HttpServletRequest req) throws SQLException {
       Connection con=null;
       //通过请求对象获得全局作用域对象
       ServletContext application=req.getServletContext();
       Map map=(Map)application.getAttribute("connKey");
       Iterator it=map.keySet().iterator();
       while (it.hasNext()){
           con=(Connection)it.next();
           //迭代map的keySet,如果con的值为true则代表未使用,将其返回并修改键值对为false表示正在使用。
           if((boolean)map.get(con)){
               map.put(con,false);
               break;
           }
       }
       return con;
    }
 public  void close(Connection conn, Statement ps,HttpServletRequest req ){
        if (ps!=null){
            try {
                ps.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        ServletContext application=req.getServletContext();
        Map map=(Map)application.getAttribute("connKey");
        map.put(conn,true);
    }
//重载DAO中注册向数据库添加数据的方法
public int add(Users user, HttpServletRequest req) {
      Connection conn = null;
      PreparedStatement ps = null;
      int rs=0;
      try {
      //使用重载的方法
          conn = util.getConnection(req);
          String sql = "insert into t_userInfo(userName,password,sex,email) values(?,?,?,?)";
          ps = conn.prepareStatement(sql);
          ps.setString(1, user.getUserName());
          ps.setString(2, user.getPassword());
          ps.setString(3, user.getSex());
          ps.setString(4, user.getEmail());
          rs = ps.executeUpdate();
      } catch (SQLException throwables) {
          throwables.printStackTrace();
      }finally {
       //使用重载的方法
          util.close(conn,ps,req);
      }
      return rs;
    }

HttpServletRequest req的传递路径:

controller(Servlet)=>DAO(add方法)=>JDBCUtil(getConnection和close方法)

源码参照github仓库链接