首頁  >  文章  >  Java  >  服務程式

服務程式

巴扎黑
巴扎黑原創
2017-06-23 16:31:252007瀏覽

 

一概述

1.伺服器

處理請求、給予回應的全部因素構成的整體稱作伺服器,包含硬體與軟體兩個面向。

2.Servlet規格

伺服器處理請求、回應遵守的原則。

3.Servlet是什麼?

Server Applet,運行在伺服器端的java應用程序,使用java語言編寫,遵守java規範,Servlet規範的核心。

4.Servlet在Web伺服器中的地位

# Servlet在整個網路伺服器中扮演控制器的角色,將請求轉送給對應的業務邏輯處理。

5.tomcat是什麼?

tomcat是伺服器的軟體方面,是實現了Servlet規範與JSP規範的容器,由Apache提供、免費、開放原始碼的輕量級級應用程式伺服器,適用於中小型系統和並發存取用戶不是很多的場合。

6.MIME

Multipurpose Internet Mail Extensions,多用途互聯網郵件擴展協議,為每種類型的文件製定一種規範以便瀏覽器接收到檔案以後呼叫對應的元件開啟。

二幾個重要類別

1.ServletContext

  • ## ServletContext,Servlet上下文,是所用Servlet存在的環境,一個Web應用程序,一個實例對象,在整個應用

    層級起作用。
  • JSP內建物件application就是一個ServletContext實例,
  • ServletContext在檔案上對應於web.xml,web.xml包含整個伺服器中使用者自訂的全部訊息,從此可以看出

    ServletContext的作用範圍。
  • 作用:ServletContext主要用於在Web伺服器啟動時載入各元件到伺服器,根據自訂參數初始化伺服器。
  • 生命週期:ServletContext物件在伺服器啟動時創建,伺服器停止時銷毀。

重要方法:

servletContext.setAttribute(name, object);//向servletContext作用域中添加属性,该属性为所有用户共享servletContext.getAttribute(name);//获取servletContext作用域中指定属性的属性值servletContext.removeAttribute(name);//从servletContext作用域中删除指定属性servletContext.getRealPath(path);//根据相对于项目的路径获取资源的绝对路径URLservletContext.getResourceAsStream(path);//获取路径文件的输入流servletContext.getInitParameter(name);//获取初始化参数的值

物件取得:

ServletContext物件由Web伺服器在啟動時自動創建,程式設計師需要做的就是取得該實例對象,以下是幾種

取得方式。

this.getServletContext();//HttpServlet提供了获取ServletContext实例对象的方法,在doGet或者doPost方法内部request.getServletContext();//通过request对象获取HttpSession session = request.getSession();
session.getServletContext();//通过session对象获取

2.ServletConfig

用來初始化Servlet,一個Servlet,一個ServletConfig。
###
public void init(ServletConfig config) throws ServletException {
String initParameter = config.getInitParameter("initParamName");
}
####

 

三 Servlet

1.Servlet的工作原理:

Web容器启动时会创建两个与Servlet相关的Map集合,两个集合的key值均为urlPattern,即请求uri,第一个Map的value是Servlet的引用变量,第二个Map的value是Servlet的全限定性类名。请求到达Web容器后,系统先搜索第一个Map集合,如果存在与uri对应的引用变量,则获取该引用变量,如果不存在,继续搜索第二个Map集合,获取对应的全限定类型,创建对象,并把引用变量存到第一个Map集合中。

2.Servlet继承结构

                                                             
                                    Servlet                 ServletConfig              Serializable
                                         |                               |                               |
                                         --------------------------------------------------
                                                                         |
                                              GenericServlet
                                                                         |
                                                  HttpServlet

  3.实际开发中Servlet的创建方式

   Servlet接口是Servlet规范中定义的,服务器自动调用其中service方法处理请求,该接口有多个抽象方法,很多在实际开发中很少使用,实现该接口需要实现其中的全部抽象方法,因此不采用直接实现Servlet接口的方法创建Servlet。

    GenericServlet实现Servlet接口中大多数抽象方法,保留了一个抽象方法service,继承该抽象类创建servlet,必须实现该抽象方法。HTTP中多个请求方法在处理请求前必须做一些固定的前置工作,如果实现该serivce方法就需要在每一个Servlet的service方法中都编写前置工作代码,造成代码冗余。为了解决此问题,tomcat提供了一个GenericServlet的子类HttpServlet,HttpServlet采用固定行为结构的模板方法模式将前置工作固定在一个方法,用户在创建Serlvet时继承HttpServlet,然后重写与请求方式对应的方法即可。(具体参考源码)

HttpServlet源码

protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {

        String method = req.getMethod();if (method.equals(METHOD_GET)) {long lastModified = getLastModified(req);if (lastModified == -1) {// servlet doesn't support if-modified-since, no reason// to go through further expensive logic                doGet(req, resp);
            } else {long ifModifiedSince;try {
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {// Invalid date header - proceed as if none was setifModifiedSince = -1;
                }if (ifModifiedSince < (lastModified / 1000 * 1000)) {// If the servlet mod time is later, call doGet()// Round down to the nearest second for a proper compare// A ifModifiedSince of -1 will always be less                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);

        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);

        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);

        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);

        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);

        } else {//// Note that this means NO servlet supports whatever// method was requested, anywhere on this server.//String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);

            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

从中可以看出Get请求在实际执行前做了很多准备工作。

4.生命周期

Servlet默认在调用时创建并初始化,这也是工作原理中第一个Map集合引用变量为空情况出现的原因。对一些必定会被访问并且访问频繁的Servlet可以设定为在容器启动时创建并初始化,提高访问速度。

<load-on-startup>int类型数字</load-on-startup>

小于0:默认值,调用时创建初始化。
    等于大于0:在Web服务器启动时创建初始化,值越小,优先级越高。出现相同值时,不会出现异常,容器自定义顺序执行。

     5.主要方法:

this.getInitParameter("");//获取初始化参数this.getServletName();//获取配置文件<servlet-name>标签的内容this.getServletContext();

6.由于继承HttpServlet创建的Servlet属于自定义类,系统不知晓,必须在配置文件中配置:

<servlet>     <servlet-name>bothRegisterServlet</servlet-name>     <servlet-class>com.servlet.register.BothRegisterServlet</servlet-class>     <init-param>         <param-name>xxx</param-name>         <param-value>xxxx</param-value>     </init-param>     <load-on-startup>1</load-on-startup>     <async-supported>true</async-supported></servlet><servlet-mapping>     <servlet-name>bothRegisterServlet</servlet-name>     <url-pattern>/bothRegisterServlet01</url-pattern></servlet-mapping>

由於訪問Web容器中的Servlet物件時,無論採用哪種方式都只能間接訪問,一般採用url訪問servlet,那麼就需要在訪問時使用的url與最終資源servlet之間建立一對一的映射關係,這就是servletMapping存在的原因。

允許為一個Servlet物件配置多個url格式。

四request

1.什麼是request?

Servlet規格定義的一個向Servlet提供客戶端請求資訊的物件。

2.request包含哪些訊息,或透過request可以取得哪些資訊?

  • 請求參數:當表單輸入為空時,伺服器端取得的內容為空字串,不為null。

  • request作用域內的屬性:可以將資料存放到request作用域中,在同一請求中取得。

  • 輸入流:檔案上傳時,可以透過request取得上傳檔案的輸入流。

  • Cookie:Cookie由伺服器生成,保存在客戶單,瀏覽器向伺服器發出請求時自動提交。

  • Part:代表上傳檔案的物件。

  • 其他內建物件:如session\application。

  • 其他與請求密切相關的資訊:如請求方式、使用的瀏覽器、協定、請求url、請求體長度、查詢字串、請求頭、客戶端IP、連接埠號碼等。

3.常用方法:

#⑴request.getParameter()與request.getAttribute()比較

  • getParameter:取得請求參數的值,傳回值String,表單輸入為空時,回傳值為空字串,不為null。

  • getAttribute:取得作用域範圍內的屬性,傳回類型為屬性類型,屬性不存在時,傳回null。

⑵request.getSession()與request.getSession(boolean create)比較

  • getSession():與getSession(true)相同,基於Cookie取得Session對象,如果Cookie不存在,則新建session。

  • getSession(false):基於Cookie取得Session對象,如果Cookie不存在,則傳回null。

⑶request.setCharacterEncoding():設定請求體的編碼方式,也就是伺服器解析瀏覽器提交的資料時所採用的編碼方式。 由於只有POST請求的資料透過請求體傳輸,所以只對POST請求有意義,對GET請求無意義。

⑷request.getContentLength():取得請求體的位元組長度,只對POST有意義。

⑸request.getQueryString():取得追到URL後面的請求字串,只對GET請求有意義。

⑹request.getRequestDispatcher().forward(request,response)request.getRequestDispatcher().include(request,response)的差異:

  • # # 持有回應權的資源不同:

forward將請求繼續向前推進,將回應權轉交給後面的資源,自身無法向伺服器發出回應,即在自身中使用out.write方法不能向頁面輸出內容。

include包含,將後面的資源作為自身的一部分,不僅後面的資源可以發出回應,自身也可以回應,相當於將自身的一部分程式碼分到後面的資源。

### 4.什麼是相同請求? ############ 一次請求在結束前,如果未進行重定向操作,進行轉送與包含操作,則仍屬於同一請求的範疇。 ############ 5.相同請求的意義 ############ 同一請求共享請求參數與作用域中的屬性等資訊。 ######

五 response

1.什么是response?

Servlet规范定义的一个向浏览器发出响应的对象,由Servlet容器自动创建。

2.reponse主要作用:

⑴设置响应的MIME类型及编码方式。

由于存在多种响应数据类型,因此服务器在响应前必须指明数据类型,以便浏览器根据指定类型处理接收的数据。

response.setContentType("text/html;charset=UTF-8");//以HTML方式处理

⑵设定响应头,即响应内容的其他方面:

response.setHeader(name,value);

⑶创建并将Cookie保存到客户端:

response.addCookie(Cookie cookie);

⑷重定向:

response.sendRedirect(url);

⑸获取向浏览器输出内容的输出流:

PrintWriter out=reponse.getWriter();

⑹获取文件下载的输出流:

ServletOutputStream sos=response.getOutputStream();

3.响应或者跳转后的代码执行问题

代码继续执行,对响应结果或者request作用域没有影响,因为响应已经结束,请求已转发给其他资源,自身就失去了处理请求的能力,但对session\applicatiion作用域可以产生影响。通常不在响应或者跳转之后对整个处理过程施加影响。

六 Cookie

1.什么是Cookie?

由服务器生成,保存在浏览器端的存储会话信息的对象。

2.创建Cookie

Servlet规范提供了Cookie类,用于创建Cookie对象:

Cookie cookie=new Cookie(name,value);

3.保存Cookie

由服务器创建,保存在客户端,浏览必须允许保存Cookie将cookie:

response.addCookie(cookie);

4.设定Cookie路径:

Cookie在访问服务器时自动提交,这种提交不是无选择地对任何访问路径都提交,而是只对设定的路径提交。在未单独设定Cookie的绑定路径时,Cookie与生成Cookie的访问路径绑定,访问该路径下任何一个资源时,浏览器自动提交Cookie。
    可以设定Cookie的绑定路径,使Cookie不受生成路径的限制:

cookie.setPath(String uri);

5.Cookie的生命周期

默认情况下,Cookie保存在浏览器缓存中,浏览器关闭,Cookie销毁。如果希望Cookie中保存的信息长期存在,可以将Cookie保存到本地硬盘中,前提是当前浏览器支持。

cookie.setMaxAge(int expiry);//以秒为单位
  • 取值大于0:将Cookie保存到硬盘中,无论浏览器是否关闭,指定时长过去后,Cookie被销毁。

  • 等于0:立即销毁Cookie。

  • 小于0:默认情况,将Cookie保存在浏览器缓存中,浏览器关闭,Cookie销毁。

6.常用方法:

String name = cookie.getName();//获取Cookie的名称String value = cookie.getValue();//获取Cookie的值cookie.setValue(newValue);//修改Cookie的值

7.主要应用:

Cookie主要用于保存浏览器关闭以后需要保留的会话信息,如登陆信息,实现免登陆功能。

七 Session

1.HTTP协议的无状态特性

在HTTP协议中,浏览器向服务器发送请求,服务器响应完毕后,连接结束,服务器端没有保存本次请求的任何信息,这就是HTTP协议的无状态特性。如果需要保存会话信息,就必须提供一种解决方案,而Session就是这个解决方案。

2.什么是Session?

Session是用来在服务器端保存会话信息的对象,比如保存用户在网站上的足迹等。

3.什么是同一Session?

在浏览器开启Cookie的情况下,从浏览器第一个访问网站到浏览器关闭的时间内浏览器与服务器所有的互动都是在同一个会话中。如果浏览器关闭了Cookie,那么浏览器每向服务器发送一次请求,都开启一个新的会话,即服务器端都会新建一个Session对象。

4.Session的工作原理

第一次访问时,服务器会自动创建一个Session对象,并为Session对象分配一个唯一的32位的id,同时生成一个Cookie对象,name为JSESSIONID,value为Session的id。在Cookie的有效期内,再次访问服务器时,根据value值获取对应的Session对象,这样就保证了在同一次会话中存在的始终是同一个Session对象。

5.Session的生命周期

Session对象在浏览器第一次访问服务器时创建,如果浏览器长时间不向服务器发送请求,在指定的时长之后,服务器会销毁Session对象。
    这里所说的时长不是从Session创建到销毁的时间长度,而是浏览器长时间发送请求,服务器保存Session对象的最大时间长度,通过以下方法设置,以秒为单位:

session.setMaxInactiveInterval(int interval);

6.Session的销毁

通过以下方法,浏览器可以主动销毁Session对象:

session.invalidate();

7.主要方法:

Session主要用于在同一会话中共享数据,所以对Session的主要操作是操作作用域中的属性:

session.setAttribute(name,value);//向作用域中添加属性session.getAttribute(name);//获取作用域中的属性session.removeAttribute(name);//从作用域中删除属性

八 请求转发与重定向

1.什么是请求转发?

服务器接收到请求以后,首先对请求进行预处理,然后将请求转发给其他的资源继续处理,这种转发叫做请求转发。

2.什么是重定向?

服务器调用特定的方法向浏览器发送一个资源路径,浏览器访问该路径,这一过程叫做重定向。

3.请求转发与重定向的区别

  • 请求转发是服务器调用不同的资源处理同一请求,始终是同一请求。

  • 重定向使得浏览器再次向服务器发送请求,前后是两个不同的请求。

九 异步机制

1.什么是异步机制?

为耗时的任务分配一个线程,主线程继续执行后面的代码,执行完毕,将主线程归还线程池,以便执行其他的请求。

2.异步机制产生的原因

Servlet是单例多线程的,允许并发访问的线程数目有限,为此Servlet建立了一个线程池,请求必须从线程池中获取了线程才能访问Servlet。若一个请求长时间占有线程,可能导致后面的请求长时间等待,降低了程序的吞吐能力。如果一个线程从Servlet线程池中获取了线程以后,另外开启一个线程处理耗时的任务,及时将主线程归还线程池,就解决这个问题。

3.异步机制的作用

异步机制的作用主要不是为了提高单次执行速度,而是提高吞吐量,即同一时间段内允许更多的请求访问Servlet。为了提高访问的线程数目,降低每次访问占有Servlet线程的时间,将耗时的任何交个另外一个线程处理,将主线程及时归还线程池。

4.异步机制的基本原理

Servlet接收到请求以后,对请求进行初步处理,然后开启一个异步线程处理具体的业务,Servlet线程继续执行后面的代码,执行完毕后,将Servlet线程归还线程池,以便其他请求使用。等待异步线程执行完毕后一起响应,异步线程执行完毕主要有两个标志:

  1. 在异步线程内部调用complete方法。

  2. 超时时间结束。

超时时间不并代表异步线程的生命时长,而是最大生命时长。如果在超时时长内,异步线程调用了complete方法,异步线程提前结束。
    异步线程默认的超时时长是10s(Servlet不同版本不同),当主线程执行完毕,同时超时时长结束或者异步线程提前结束,服务器开始向浏览器发送响应,销毁request、response对象,关闭输出流,如果异步线程未执行完毕,那么异步线程中已执行的响应会响应到浏览器,未执行的响应不会响应到浏览器。

  5.响应时机

   分配给异步线程的时间不是无限的,因此存在一个响应时机的问题。
    在主线程执行完毕并且异步线程超时时长用完或者提前结束时响应。

  6.异步处理的实现

AsyncContext ac=request.startAsync();
ac.setTimeout(int mills);
ac.start(Runnable run);//将异步线程管理对象ac作为参数传入异步线程中,通过该参数可以获取request\response

7.异步机制的使用

由于异步机制的设计目的是为了使请求尽快归还Servlet线程,提高程序的吞吐量,并未显著提高响应速度。异步机制通常不直接用作向浏览器输出响应内容,如在异步线程内部使用out.write直接向浏览器输出,而是用来处理耗时的任务,将处理结果存放到session/application等作用域中。

8.还可以使用AsyncContext对象为异步线程添加监听器,监听异步线程的执行过程。

十 web.xml

1.配置Servlet、Filter、Listener、contextParams等构成应用程序的重要信息。

2.配置欢迎页面,也是网站的首页,可以由多个文件构成,优先采用上面的文件:

<welcome-file-list>   <welcome-file>index.html</welcome-file>   <welcome-file>default.html</welcome-file></welcome-file-list>

注:在配置文件中书写路径时,只有欢迎列表中的路径不需要在前面加“/”,其他地方的路径都需要在前面加“/”,因为欢迎页面只能放在WebContent根路径下,不能放在WebContent根路径下的文件夹内,其路径相对固定,因此可以简写。

3.配置错误页面:

⑴方式一,根据错误代码配置页面,出现指定的错误代码时显示指定的页面:

<error-page>  <error-code>404</error-code>  <location>/xxxx</location>//可以放在WebContent目录下任意位置</error-page>

⑵方式一,根据异常类型配置页面,出现指定的异常时显示指定的页面:

<error-page> <exception-type>java.lang.NullException</exception>//异常类必须写完整的类名     <location>/xxxx</location></error-page>

4.配置ServletContext的初始化参数:

<context-param><param-name>paramName</param-name><param-value>paramValue</param-value></context-param>

十一 注解式开发

Servlet3.0新增注解式开发,注解式开发就是将在编写在配置文件web.xml中的信息转移到类文件上。

注解方式:
    在类名上添加注解:

@WebServlet(urlPatterns={"",""},loadOnStartup=1,initParams={@WebInitParam(name="",value="")},asyncSupported=true)

两种注册方式同时存在,如果映射路径不相同,相当于存在一个集中了所用路径的Servlet,如果存在相同路径,服务器无法启动。

十二 文件上传

1.Servlet3.0提供一个Part类型,该类封装了上传文件信息。

2.文件名存储在一个名为Content-Disposition的请求头中。

3.文件上传的具体实现:

Part part=request.getPart(文件字段名);//获取文件封装对象String fileName=part.getHeader("Content-Dispostion");//获取文件名part.write("parentPath/"+fileName);//将文件保存到指定路径,只能使用绝路径

十三 文件下载

1.Servlet提供了ServletOutputStream用作文件下载的输出流。

2.文件下载时必须设置浏览器以附件的形式处理从服务器获取的数据:

response.setHeader("Content-disposition","attachment;filename=xxxx");

如果请求头中设置的文件名含有中文必须转化为ISO-8859-1的编码方式。

3.从服务器获取输入流,利用ServletOutputStream输出流将文件写到用户指定路径:

InputStream is = getServletContext().getResourceAsStream("/Files/upload.txt");
ServletOutputStream os = response.getOutputStream();

有了輸入流與輸出流,後續操作就是將輸入流中的內容寫入輸出流,這是IO常見的操作。

十四執行緒安全性問題

1.Servlet執行緒安全性問題產生的原因

Servlet以單例的形式運行在多線程的環境中,其中的實例變數儲存在堆中的物件中,而堆是多線程共享的,因此實例變數存在線程安全問題,而靜態變數儲存在方法區,方法區也是多執行緒共享的,靜態變數也存在執行緒安全性問題,而局部變臉儲存在堆疊中,堆疊中的資料在內部是共享的,在堆疊間是不共享的,即一個線程一個棧,因此局部變數時線程安全的。

2.執行緒安全性問題的解決方案:

  • #將全域變數轉換為局部變數。

  • 將修改全域變數的程式碼加入同步方法或同步區塊。

  • 將全域變數儲存到ThrealLocal中,為每個執行緒分配一個變數的副本,各個執行緒相互獨立操作。

十五不登入

# 1.根據公開與保護程度,將網站上的資源分為開放性資源、權限性資源兩種:

  • 開放性資源:對所用使用者公開,無需權限就可以存取的資源。

  • 權限性資源:保存使用者個人訊息,經過驗證後才可以存取的資源。

2.免登入的意義

登入網站以後,下次使用相同瀏覽器造訪網站,不需要重新登入。

3.免登入的實作原理

# 將登入資訊(使用者名稱、密碼)儲存在Cookie中,將Cookie儲存在本地,造訪網站時瀏覽器自動提交Cookie,經Filter或Interceptor驗證通過後,無需登入直接存取。

4.免登入的條件

同一個瀏覽器:免登入需要從本機取得Cookie物件驗證資訊。

十六Servlet的元件可插性

# Servlet3.0元件具有可查性,指的是Servlet、Filter、Listener可以作為架包插入項目中。

架包建立:

  • # 建立專案Web Fragment Project。

  • 打包jar File。

  • 放入lib目錄下,當作架包。

使用:

# 可以將一些常用的Servlet元件封裝成架包,直接放在lib目錄下使用,例如解決POST請求時中文亂碼的Filter。

十七 動態註冊

1.什麼是動態註冊?

在Web執行時註冊Servlet、Filter、Listener。

2.動態註冊時機

為了安全,只能在網路伺服器啟動時註冊,也就是透過ServletContextListener監聽器註冊。

以上是服務程式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
上一篇:JAVA學習下一篇:JAVA學習