JavaWeb三大组件(Servlet、Filter、Listener)

1.Servlet

Servlet简介

    运行在服务器端Servlet容器中的小程序(服务器将请求封装为对象HttpRequest交给Servlet小程序去执行,对数据进行操作,servlet是帮web服务器处理数的)Servlet就是一个接口,凡是实现这个接口的类我们都称为Servlet

Servlet作用

      接受请求-->处理请求-->返回响应

为什么要有Servlet

      ①服务器返回客户静态资源,例如:web页面,图片等,WEB服务器擅长提供静态页面不能提供动态即时页面,不能往数据库保存数据

       ②Servlet :服务器端小程序 -可以提供动态页面 -可以与后台交互-运行在servlet容器中,servlet容器运行在服务器中。比如用户输入用户名和密码,web服务器只会响应一些静态页面自己不会处理这些数据,所以服务器会将请求或响应封装为一个对象作为参数传递给java程序,java程序会去处理这些数据,如果用户名密码正确给客户返回一个页面,否则返回另一页面(所有的java程序(Servlet都会有一个方法service(HttpServletRequest request, HttpServletResponse response)方法,这个方法的参数就是请求和响应))

Servlet创建步骤

1.创建一个类实现Servlet接口
2.在web.xml文件中注册servlet(在web.xml文件中配置Servlet)

          
              别名
              全类名
          

          
            别名        //对应的Servert
            /requestadress   //为Servlet映射一个请求地址   Servlet接受浏览器发给web服务器请求 要有请求地址
          

    客户通过浏览器发送请求给web服务器,如发送的请求为一个地址 如:/requestadress,在配置文件web.XML中会映射这个请求地址给 对应的Servlet(Servlet-name),web服务器通过Servlet-name对应的全类名创建一个Servlet实例 , 通过Servlet实例调用其service()方法完成数据的处理。

Servlet生命周期

- Servlet的生命周期是指Servlet的对象由被创建到被销毁的过程。
    - Servlet的生命周期方法:
            1.构造器
                - Servlet第一次处理请求的时候调用,用于创建Servlet的实例,只会调用一次。
                - Servlet是单例,同一个Servlet在服务器中只有一个对象,但是它是多线程的,效率高;
                - 它是以多线程的方式调用service()方法,Servlet不是线程安全的,在service()中尽量不要操作全局变量。
            2.init()
                - 构造器执行以后,init马上被调用,用来做初始化操作,只会调用一次
                - 注意如果我们继承的是HttpServlet,那么他的里面有两个init方法。
                - 如果要重写只能重写的无参的方法。
            3.service()
                - 每次处理请求时都会调用service,它用来处理用户发送的请求,会调用多次
                - 如果我们通过继承HttpServlet实现Servlet,
                    我们只需要根据要处理的请求类型,重写doGet或doPost
            4.destroy()
                - Servlet对象销毁之前调用,用来做一些收尾工作,只会调用一次

ServletConfig接口

     每一个Servlet都有其唯一对应的ServletConfig,ServletConfig代表Servlet的配置信息,具体来说就是servlet标签中的内容

   
          Servlet3
          com.atguigu.servlet.Servlet3
          (初始化参数)
                  username
                  root

          
   

web服务器对XML进行解析时将其封装成一个对象(就像我们利用dom4j对students.xml 进行解析,并封装成student一样) 获取:由服务器创建,最终作为参数传递到init()方法中,我们可以在init方法中直接使用如果是通过继承HttpServlet,则可以直接调用ServletConfig的方法,因为HttpServlet实现了ServletConfig接口。
        功能:1.获取当前Servlet的别名(没用)
              2.获取当前Servlet的初始化参数(XML中的)
              3.获取ServletContext对象

ServletContext接口

代表整个的WEB应用,每一个WEB应用都有其唯一的ServletContext对象,  ServletContext对象在服务器启动时创建,在服务器停止时销毁 
      获取:通过ServletConfig的getServletContext()方法获取
      功能:
           1.获取整个WEB应用的初始化参数           

        
             phone
             13777788899
        

            2.根据虚拟路径获取资源的真实路径(物理路径)(主要用来文件的上传和下载的)
            3.可以作为一个域对象在不同的WEB资源之间共享数据 

HttpServlet接口

 在创建Servlet都是继承HttpServlet类的方式直接创建,然后重写doGet()和doPost()方法】
(原因:因为HttpServlet继承了GenericServlet,而GenericServlet实现了Servlet接口;实际上当请求到达是还是会直接找原生的service(ServletResqust request,ServletResponse response);而自己的原生service方法在父类HttpServlet中;父类中还有一个重载的service(HttpServletRequest request,HttpServletResponse response)方法,请求到达直接找了原生的service方法,然后把ServletRequest和ServletResponse强转为HttpServletRequset和HttpServletResponse然后调用重载的service方法,在重载的setvice方法中会判断请求是get请求还是post请求,如果是get请求会找doGet方法,如果是post请求会直接找doPost方法,所以我们只需要根据前台是get请求还是post请求来重写doGet方法或doPost方法即可)
          当需要处理get请求时重写doGet()方法
          当需要处理post请求时重写doPost()方法
          需要初始化对象时,重写init()无参方法即可
          需要做收尾工作的时候,重写destroy()方法即可

HttpServletRequest接口

request代表浏览器发送给服务器的请求报文
获取:由服务器创建(服务器将请求报文封装为HttpServletRequest对象),最终作为参数传递到doGet或doPost方法中,我们可以在这两个方法中直接使用
功能:
         [1]获取到浏览器发送的请求参数    :如用户名,密码等参数                

         request.getParameter(String name)  //根据参数名获取参数值

[2]动态的获取项目的名字(主要用来设置绝对路径的)              

          request.getContextPath();   

 [3]作为一个域对象在不同的WEB资源之间共享数据
 [4]请求的转发              

          RequestDispatcher dispatcher =request.getRequestDispatcher(String path)
          dispatcher.forward(request, response);
          request.getServerName()    :    localhost ;
          request.getServerPort()    :    8080  ; 
          request.getContextPath()   :    /项目名 ;

HttpServletResponse接口

代表服务器发送给浏览器的响应报文
     获取:由服务器创建(服务器将响应报文封装为HttpServletRsponse对象),最终作为参数传递到doGet或doPost方法中,我们可以在这两个方法中直接使用
     功能:
          [1]可以向浏览器发送一个页面或者是页面片段        

       response.sendRedirect("

欢迎登录

")

           [2]做请求的重定向

       response.sendRedirect(String path)

          [3]将数据写到页面

     PrintWriter writer = response.getWriter(); 
     writer.write(new Date());
     writer.flush();
     writer ose();     

 

如何解决Servlet的单线程安全问题

1、实现 SingleThreadModel 接口
          该接口指定了系统如何处理对同一个Servlet的调用。如果一个Servlet被这个接口指定,那么在这个Servlet中的service方法将不会有两个线程被同时执行, 当然也就不存在线程安全的问题。
2、同步对共享数据的操作
          使用synchronized 关键字能保证一次只有一个线程可以访问被保护的区段,在本论文中的Servlet可以通过同步块操作来保证线程的安全。
3、避免使用实例变量
         本实例中的线程安全问题是由实例变量造成的,只要在Servlet里面的任何方法里面都不使用实例变量,那么该Servlet就是线程安全的。   

    对上面的三种方法进行测试,可以表明用它们都能设计出线程安全的Servlet程序。但是,如果一个Servlet实现了SingleThreadModel接口,Servlet引擎将为每个新的请求创建一个单独的Servlet实例,这将引起大量的系统开销。SingleThreadModel在Servlet2.4中已不再提倡使用;同样如果在程序中使用同步来保护要使用的共享的数据,也会使系统的性能大大下降。这是因为被同步的代码块在同一时刻只能有一个线程执行它,使得其同时处理客户请求的吞吐量降低,而且很多客户处于阻塞状态。另外为保证主存内容和线程的工作内存中的数据的一致性,要频繁地刷新缓存,这也会大大地影响系统的性能。所以在实际的开发中也应避免或最小化 Servlet 中的同步代码;在Serlet中避免使用实例变量是保证Servlet线程安全的最佳选择。Servlet的线程安全问题只有在大量的并发访问时才会显现出来,并且很难发现,因此在编写Servlet程序时要特别注意。线程安全问题主要是由实例变量造成的,因此在Servlet中应避免使用实例变量。如果应用程序设计无法避免使用实例变量,那么使用同步来保护要使用的实例变量,但为保证系统的最佳性能,应该同步可用性最小的代码路径

2.Filter

既然和Servlet如此相似,为什么有了Servlet还要Filter呢?

①. Servlet 通常用来servlet主要负责处理请求并且应答浏览器发出的请求. 有 HttpServlet 作为实现类,根据需要覆盖 doGet 或 doPost.
②. Filter:意为 "过滤器". 它除了可以完成 Servlet 的功能之外,它还可以实现资源拦截的效果.若把 Servlet 比喻为要拜访的客户,则 Filter 为访问该客户过程中需要经过的门岗. 它将起到过滤的作用.
③. Servlet 和 Filter 的功能谁更强大 ? Filter 的功能更强大些,因为他还有一个拦截的功能. 因为在其中多一个 API:FilterChain. 

Filter创建步骤

1.创建一个类,实现javax.servlet.Filter接口

public class ChartSetFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub  
    }

    public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)throws IOException, ServletException {

        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        chain.doFilter(request, response);
    }

    public void destroy() {
        // TODO Auto-generated method stub  
    }   

}

2.在web.xml文件中配置Filter

    
        ChartSetFilter
        ChartSetFilter
        com.atguigu.survey.filter.ChartSetFilter
    

    
        ChartSetFilter
        /*
    

3. 如果有多个过滤器都匹配该请求,顺序决定于web.xml filter-mapping的顺序,在前面的先执行,后面的后执行

Filter的生命周期

构造器:创建Filter实例时调用,Filter实例服务器一旦启动就会被创建
init():实例创建后马上被调用,用来对Filter做一些初始化的操作
doFilter():Filter的主要方法,用来完成过滤器主要功能的方法,每次访问目标资源时都会调用。
destroy():服务器停止时调用,用来释放资源。

3.Listener

监听器可以监听Application、Session、Request对象,当这些对象发生变化就会调用对应的监听方法。 

监听器的分类(三大类(八个监听器))

    1.用于监听域对象的创建和销毁的        

【重要】①ServletContextListener: 用于监听 ServletContext 对象被创建和销毁的监听器
             public void contextInitialized ( ServletContextEvent sce );
                       ServletContext创建时调用
             public void contextDestroyed ( ServletContextEvent sce );
                       ServletContext销毁时调用

        ②HttpSessionListener: 用于监听 HttpSession 对象被创建和销毁的监听器
             public void sessionCreated ( HttpSessionEvent se );
                       HttpSession对象创建时调用
             public void sessionDestroyed ( HttpSessionEvent se );
                       HttpSession对象销毁时调用

        ③ServletRequestListener:  用于监听 ServletRequest 对象被创建和销毁的监听器
             public void requestInitialized ( ServletRequestEvent sre );
                       ServletRequest对象创建时调用
              public void requestDestroyed ( ServletRequestEvent sre );
                       ServletRequest对象销毁时调用

      步骤:
      a.创建一个类实现实现ServletContextListener/HttpSessionListener/ServletRequestListener

   public class MyServletContextListener implements ServletContextListener {
          @Override
          public void contextInitialized(ServletContextEvent sce) {
            System.out.println("哈哈,我是ServletContext,我出生了");
          }

          @Override
          public void contextDestroyed(ServletContextEvent sce) {
            System.out.println("~~~~(>_<)~~~~,我是ServletContext,我要死了");
          }
    }

  b.在web.xml文件中注册监听器


   com.atguigu.web.listener.MyServletContextListener

2.用于监听域对象属性变化(添加属性、替换属性、移除属性... ...)       

     ④ServletContextAttributeListener
            public void attributeAdded(ServletContextAttributeEvent scab);
                   向ServletContext中添加属性时调用

            public void attributeRemoved(ServletContextAttributeEvent scab);
                   从ServletContext中移除属性时调用

            public void attributeReplaced(ServletContextAttributeEvent scab);
                   当ServletContext中的属性被修改时调用

      ⑤HttpSessionAttributeListener

      ⑥ervletRequestAttributeListener


     步骤:
        a.创建一个类实现实现ServletRequestAttributeListener/......Lsitener接口

     public class ReqAttrListener implements ServletRequestAttributeListener {
        @Override
        public void attributeAdded(ServletRequestAttributeEvent srae) {
           System.out.println("request域中添加一个属性" + srae.getName() + "=" + srae.getValue());
        }

        @Override
        public void attributeRemoved(ServletRequestAttributeEvent srae) {
          System.out.println("request域中移除一个属性" + srae.getName() + "=" + srae.getValue());
        }

        @Override
        public void attributeReplaced(ServletRequestAttributeEvent srae) {
           System.out.println("request域中一个属性被修改了" + srae.getName() + "=" + srae.getValue());
        }
     }  

       b.在web.xml文件中注册监听器     

  
          com.atguigu.web.listener.ReqAttrListener
  

3.感知session监听器       

  ⑦HttpSessionBindingListener监听 
        ⑴在需要监听的实体类实现HttpSessionBindingListener接口 
        ⑵重写valueBound()方法,这方法是在当该实体类被放到Session中时,触发该方法 
        ⑶重写valueUnbound()方法,这方法是在当该实体类从Session中被移除时,触发该方法 

  ⑧HttpSessionActivationListener监听 
        ⑴在需要监听的实体类实现HttpSessionActivationListener接口 
        ⑵重写sessionWillPassivate()方法,这方法是在当该实体类被序列化时,触发该方法 
        ⑶重写sessionDidActivate()方法,这方法是在当该实体类被反序列化时,触发该方法

Spring ApplicationListener

你可能感兴趣的:(JavaWEB)