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)

      <servlet>
          <servlet-name>别名</servlet-name>
          <servlet-class>全类名</servlet-class>
      </servlet>
 
      <servlet-mapping>
        <servlet-name>别名</servlet-name>        //对应的Servert
        <url-pattern>/requestadress</url-pattern>   //为Servlet映射一个请求地址   Servlet接受浏览器发给web服务器请求 要有请求地址
    </servlet-mapping>  
 
客户通过浏览器发送请求给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标签中的内容

<servlet>
          <servlet-name>Servlet3</servlet-name>
          <servlet-class>com.atguigu.servlet.Servlet3</servlet-class>
          <init-param>(初始化参数)
                  <param-name>username</param-name>
                  <param-value>root</param-value>
​
​
      </init-param>
​
​
   </servlet>

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应用的初始化参数

    <context-param>
         <param-name>phone</param-name>
         <param-value>13777788899</param-value>
    </context-param>
        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("<h1>欢迎登录</h1>")
       [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

<filter>
    <display-name>ChartSetFilter</display-name>
    <filter-name>ChartSetFilter</filter-name>
    <filter-class>com.atguigu.survey.filter.ChartSetFilter</filter-class>
</filter>
 
<filter-mapping>
    <filter-name>ChartSetFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  1. 如果有多个过滤器都匹配该请求,顺序决定于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文件中注册监听器

<listener>
   <listener-class>com.atguigu.web.listener.MyServletContextListener</listener-class>
</listener>

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文件中注册监听器     

<listener> <listener-class>com.atguigu.web.listener.ReqAttrListener</listener-class> </listener> 3.感知session监听器

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

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

猜你喜欢

转载自blog.csdn.net/weixin_43619912/article/details/94664789