Servlet基礎知識,ServletContext,ServletConfig對象詳解
Servlet的執行過程:
通過一個簡單的Servlet程序開發,來說明Servlet程序的開發步驟和執行流程
開發Servlet的步驟:
1.1 步驟: 1)編寫java類,繼承HttpServlet類 2)重新doGet和doPost方法 3)Servlet程序交給tomcat服務器運行 3.1 servlet程序的class碼拷貝到WEB-INF/classes目錄 3.2 在web.xml文件中進行配置 |
Web.xml的配置一個Servlet的寫法
<!-- 配置一個servlet --> <!-- servlet的配置 --> <servlet> <!-- servlet的內部名稱,自定義。盡量有意義 --> <servlet-name>FirstServlet</servlet-name> <!-- servlet的類全名: 包名+簡單類名 --> <servlet-class>a_servlet.FirstServlet</servlet-class> </servlet>
<!-- servlet的映射配置 --> <servlet-mapping> <!-- servlet <servlet-name>FirstServlet</servlet-name> <!-- servlet的映射路徑(訪問servlet的名稱) --> <url-pattern>/first</url-pattern> </servlet-mapping> |
啟動Tomcat,在瀏覽器的地址欄中輸入http://localhost:8080/day10/first 就可以訪問first
這個Servlet了
問題:在地址欄中輸入URL:http://localhost:8080/day10/first ,是怎麽找到fisrt這個
瀏覽器是如何找到資源詳解
前提: tomcat服務器啟動時,首先加載webapps目錄中的每個web應用的web.xml配置文件。 http://localhost:8080/day10/first詳解: http://: http協議 localhost: 到本地的hosts文件中查找是否存在該域名對應的IP地址127.0.0.1,找到,直接訪問,找不到到DNS服務器上找 8080: 找到tomcat服務器監聽的端口號 /day10 在tomcat的webapps目錄下找 day10的目錄 /first 資源名稱。 1)在day10的web.xml中查找是否有匹配的url-pattern的內容(/first) 2)如果找到匹配的url-pattern,則使用當前servlet-name的名稱到web.xml文件中查詢是否相同名稱的servlet配置 3)如果找到,則取出對應的servlet配置信息中的servlet-class內容: 字符串: a_servlet.FirstServlet
通過反射: a)構造FirstServlet的對象 b)然後調用FirstServlet裏面的方法
|
Servlet的映射路徑總結:
url-pattern 瀏覽器輸入 精確匹配 /first http://localhost:8080/day10/first /itcast/demo1 http://localhost:8080/day10/itcast/demo1
模糊匹配 /* http://localhost:8080/day10/任意路徑 /itcast/* http://localhost:8080/day10/itcast/任意路徑 *.後綴名 http://localhost:8080/day10/任意路徑.do *.do *.action *.html(偽靜態)
註意: 1)url-pattern要麽以 / 開頭,要麽以*開頭。 例如, itcast是非法路徑。 2)不能同時使用兩種模糊匹配,例如 /itcast/*.do是非法路徑 3)當有輸入的URL有多個servlet同時被匹配的情況下: 3.1 精確匹配優先。(長的最像優先被匹配) 3.2 以後綴名結尾的模糊url-pattern優先級最低
|
Servlet的生命周期詳解
問題的引入:
servlet類對象什麽時候創建,什麽時候調用什麽方法,什麽時候銷毀。
以前的對象處理: new Student(); stu.study(); stu=null;
Servlet程序的運行在Tomcat上,生命周期由tomcat服務器控制的
|
Servlet四個重要的方法來控制生命周期
構造方法: 創建servlet對象的時候調用。默認情況下,第一次訪問servlet的時候創建servlet對象 只調用1次。證明servlet對象在tomcat是單實例的。 init方法: 創建完servlet對象的時候調用。只調用1次。 service方法: 每次發出請求時調用。調用n次。 destroy方法: 銷毀servlet對象的時候調用。停止服務器或者重新部署web應用時銷毀servlet對象。 只調用1次。 |
代碼演示:
public class LifeDemo extends HttpServlet { /** * 1.構造方法 */ public LifeDemo(){ System.out.println("1.servlet對象被創建了。"); } /** * 2.init方法 */ @Override public void init(ServletConfig config) throws ServletException { System.out.println("2.init方法被調用"); } /** * 3.service方法 */ @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.println("3.service方法被調用"); } /** * 4.destroy方法 */ @Override public void destroy() { System.out.println("4.servlet對象銷毀了"); } } |
訪問URL:
http://localhost:8080/day10/LifeDemo
然後重新加載項目
運行的結果:
1.servlet對象被創建了。 2.init方法被調用 3.service方法被調用 九月 20, 2017 7:47:55 下午 org.apache.catalina.core.StandardContext reload 信息: Reloading Context with name [/day10] has started 4.servlet對象銷毀了
|
偽代碼方式描述Tomcat控制Servlet的生命周期
Tomtcat內部代碼運行: 1)通過映射找到到servlet-class的內容,字符串: .a_servlet.FirstServlet 2)通過反射構造FirstServlet對象 2.1 得到字節碼對象 Class clazz = class.forName("a_servlet.FirstServlet"); 2.2 調用無參數的構造方法來構造對象 Object obj = clazz.newInstance(); ---1.servlet的構造方法被調用 3)創建ServletConfig對象,通過反射調用init方法 3.1 得到方法對象 Method m = clazz.getDeclareMethod("init",ServletConfig.class); 3.2 調用方法 m.invoke(obj,config); --2.servlet的init方法被調用 4)創建request,response對象,通過反射調用service方法 4.1 得到方法對象 Methodm m =clazz.getDeclareMethod("service",HttpServletRequest.class,HttpServletResponse.class); 4.2 調用方法 m.invoke(obj,request,response); --3.servlet的service方法被調用 5)當tomcat服務器停止或web應用重新部署,通過反射調用destroy方法 5.1 得到方法對象 Method m = clazz.getDeclareMethod("destroy",null); 5.2 調用方法 m.invoke(obj,null); --4.servlet的destroy方法被調用
|
Servlet的自動加載:
自動加載的背景: 默認情況下,第一次訪問servlet的時候創建servlet對象。如果servlet的構造方法或init方法中執行了比較多的邏輯代碼,那麽導致用戶第一次訪問sevrlet的時候比較慢,用戶體驗感覺不好。
解決辦法: 改變servlet創建對象的時機: 提前到 加載web應用的時候!!! |
<servlet> <servlet-name>LifeDemo</servlet-name> <servlet-class>gz.itcast.c_life.LifeDemo</servlet-class> <!-- 讓servlet對象自動加載 --> <load-on-startup>1</load-on-startup> 註意: 整數值越大,創建優先級越低!! </servlet> |
改變web.xml配置文件後啟動Tomcat服務器:
Servlet的多線程引發的問題
servlet對象在tomcat服務器是單實例多線程的。(一個對象,多個線程訪問)
因為servlet是多線程的,所以當多個servlet的線程同時訪問了servlet的共享數據,如成員變量,可能會引發線程安全問題。 |
解決辦法: 1)把使用到共享數據的代碼塊進行同步(使用synchronized關鍵字進行同步) 2)建議在servlet類中盡量不要使用成員變量。如果確實要使用成員,必須同步。而且盡量縮小同步代碼塊的範圍。(哪裏使用到了成員變量,就同步哪裏!!),以避免因為同步而導致並發效率降低。
|
代碼:
public class TheradDemo extends HttpServlet { int count = 1; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); synchronized (TheradDemo.class) {//鎖對象必須唯一。建議使用類對象 response.getWriter().write("你現在是當前網站的第"+count+"個訪客"); //線程1執行完 , 線程2執行 count++; } } } |
ServletConfig對象
作用:
ServletConfig對象: 主要是用於加載servlet的 一些 初始化參數。在一個web應用可以存在多個ServletConfig對象(一個Servlet對應一個ServletConfig對象) |
創建和得到SevletConfig對象
創建時機: 在創建完servlet對象之後,在調用init方法之前創建。 得到對象: 直接從有參數的init方法中得到!!! |
完整的例子:
ConfigDemo.java
public class ConfigDemo extends HttpServlet {
/** * 1)tomcat服務器把這些參數會在加載web應用的時候,封裝到ServletConfig對象中 * 2)tomcat服務器調用init方法傳入ServletConfig對象 */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /** * 讀取servlet的初始參數 */ String path = this.getServletConfig().getInitParameter("path");
File file = new File(path);
//讀取內容 BufferedReader br = new BufferedReader(new FileReader(file)); String str = null; while( (str=br.readLine())!=null ){ System.out.println(str); }
//查詢當前servlet的所有初始化參數 Enumeration<String> enums = this.getServletConfig().getInitParameterNames(); while(enums.hasMoreElements()){ String paramName = enums.nextElement(); String paramValue = this.getServletConfig().getInitParameter(paramName); System.out.println(paramName+"="+paramValue); } //得到servlet的名稱 String servletName = this.getServletConfig().getServletName(); System.out.println(servletName); }
}
|
Web.xml配置文件:
<servlet> <servlet-name>ConfigDemo</servlet-name> <servlet-class>gz.itcast.f_config.ConfigDemo</servlet-class> <init-param> <param-name>path</param-name> <param-value>d:/b.txt</param-value> </init-param> <init-param> <param-name>BBB</param-name> <param-value>BBB‘s value</param-value> </init-param> <init-param> <param-name>CCCC</param-name> <param-value>CCCC‘s value</param-value> </init-param> </servlet> |
打印出的結果:
|
註意: servlet的參數只能由當前的這個sevlet獲取!!!!
ServletContext對象也是不能獲取的
ServletConfig對象API總結:
ServletConfig的API: java.lang.String getInitParameter(java.lang.String name) 根據參數名獲取參數值 java.util.Enumeration getInitParameterNames() 獲取所有參數 ServletContext getServletContext() 得到servlet上下文對象 java.lang.String getServletName() 得到servlet的名稱
|
ServletContext對象
概念:
ServletContext對象 ,叫做Servlet的上下文對象。表示一個當前的web應用環境。一個 web應用中只有一個ServletContext對象。
對象的創建和獲取方法:
創建時機:加載web應用時創建ServletContext對象。 得到對象: 從ServletConfig對象的getServletContext方法得到 |
獲取ServletConfig對象和當前項目名:
API介紹:java.lang.String getContextPath() --得到項目名 用在請求重定向的資源名稱中
Java代碼:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.得到ServletContext對象 //ServletContext context = this.getServletConfig().getServletContext(); ServletContext context = this.getServletContext(); //(推薦使用)
System.out.println(context); //2.得到web應用路徑 /day10 /** * web應用路徑:部署到tomcat服務器上運行的web應用名稱 */ String contextPath = context.getContextPath();
System.out.println(contextPath); /** * 案例:應用到請求重定向 */ response.sendRedirect(contextPath+"/index.html"); } |
獲取web.xml的公共參數值:
java.lang.String getInitParameter(java.lang.String name) - -得到web應用的初始化參數(這些參數是Servlet的初始參數是有差別的,可以看出是全局變量和局部變量的關系) java.util.Enumeration getInitParameterNames() --獲取所有的初始參數值 |
ServletContext對象獲取初始化參數:
web應用參數可以讓當前web應用的所有servlet獲取!!!
API介紹:
java.lang.String getInitParameter(java.lang.String name) -
-得到web應用的初始化參數(這些參數是Servlet的初始參數是有差別的,可以看出是全局變量和局部變量的關系)
java.util.Enumeration getInitParameterNames() --獲取所有的初始參數值
Java代碼:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //得到SErvletContext對象 ServletContext context = this.getServletContext();
System.out.println("參數"+context.getInitParameter("AAA"));
Enumeration<String> enums = context.getInitParameterNames(); while(enums.hasMoreElements()){ String paramName = enums.nextElement(); String paramValue =context.getInitParameter(paramName); System.out.println(paramName+"="+paramValue); }
//嘗試得到ConfigDemo中的servlet參數 //結果證明,獲取失敗,因為它要獲取的是Servlet的初始化參數, //而Servlet的初始化參數只能是由那一個ServletConfig對象 String path = this.getServletConfig().getInitParameter("path"); System.out.println("path="+path); }
|
web.xml:
|
打印的結果:
參數AAA‘s value AAA=AAA‘s value CCC=CCC‘s value BBB=BBB‘s value path=null |
ServletConfig對象數據的共享
概念: 域對象:作用是用於保存數據,獲取數據。可以在不同的動態資源之間共享數據。
ServletContext域對象:作用範圍在整個web應用中有效!!!
所有的域對象:
HttpServletRequet 域對象 ServletContext域對象 HttpSession 域對象 PageContext域對象 |
聲明:現在只介紹ServletContext對象
API介紹:
保存數據:void setAttribute(java.lang.String name, java.lang.Object object)
獲取數據: java.lang.Object getAttribute(java.lang.String name)
刪除數據: void removeAttribute(java.lang.String name)
例子:ContextDemo3.java代碼:
/** * 保存數據 * */ public class ContextDemo3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.得到域對象 ServletContext context = this.getServletContext();
//2.把數據保存到域對象中 //context.setAttribute("name", "eric"); context.setAttribute("student", new Student("jacky",20)); System.out.println("保存成功"); }
}
class Student{ private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Student(String name, int age) { super(); this.name = name; this.age = age; } @Override public String toString() { return "Student [age=" + age + ", name=" + name + "]"; } } |
ServletContext4.java代碼:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.得到域對象 ServletContext context = this.getServletContext();
//2.從域對象中取出數據 //String name = (String)context.getAttribute("name"); Student student = (Student)context.getAttribute("student"); //System.out.println("name="+name);
System.out.println(student); } |
轉發和重定向的區別:
RequestDispatcher getRequestDispatcher(java.lang.String path)
1)轉發 a)地址欄不會改變 b)轉發只能轉發到當前web應用內的資源 c)可以在轉發過程中,可以把數據保存到request域對象中
2)重定向 a)地址欄會改變,變成重定向到地址。 b)重定向可以跳轉到當前web應用,或其他web應用,甚至是外部域名網站。 c)不能再重定向的過程,把數據保存到request中。
結論: 如果要使用request域對象進行數據共享,只能用轉發技術!!!
|
ServletContext對象API總結:
java.lang.String getContextPath() --得到項目名 |
java.lang.String getInitParameter(java.lang.String name) - -得到web應用的初始化參數(這些參數是Servlet的初始參數是有差別的,可以看出是全局變量和局部變量的關系) java.util.Enumeration getInitParameterNames() --獲取所有的初始參數值
保存數據:void setAttribute(java.lang.String name, java.lang.Object object) 獲取數據: java.lang.Object getAttribute(java.lang.String name) 刪除數據: void removeAttribute(java.lang.String name) |
java.lang.String getRealPath(java.lang.String path) --得到web應用的資源文件 java.io.InputStream getResourceAsStream(java.lang.String path) |
Servlet基礎知識,ServletContext,ServletConfig對象詳解