配接器模式改造Servlet(GenericServlet)
GenericServlet
-
我們撰寫一個Servlet類直接實作Servlet介面有什么缺點?
- 我們只需要service方法,其他方法大部分情況下是不需要使用的,代碼很丑陋,
-
配接器設計模式Adapter
- 手機直接插到220V的電壓上,手機直接就報廢了,怎么辦?可以找一個充電器,這個充電器就是一個配接器,手機連接配接器,配接器連接220V的電壓,這樣問題就解決了,
-
之前的一篇博客寫到抽象類的作用:降低介面實作類與介面之間的實作難度,
(實作類不一定需要用到介面中定義的所有方法,可以先創建一個抽象類先實作一部分方法,留下實作類需要的方法,實作類再繼承抽象類,實作需要的方法,)
-
撰寫一個GenericServlet類,這個類是一個抽象類,其中有一個抽象方法service,
- GenericServlet實作Servlet介面,
- GenericServlet是一個配接器,
- 以后撰寫的所有Servlet類繼承GenericServlet,重寫service方法即可,
-
import javax.servlet.*; import java.io.IOException; public abstract class GenericServlet implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { } @Override public ServletConfig getServletConfig() { return null; } // service設為抽象方法,留給子類去實作, @Override public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException; @Override public String getServletInfo() { return null; } @Override public void destroy() { } } -
思考:GenericServlet類是否需要改造一下?怎么改造?更利于子類程式的撰寫?
-
思考第一個問題:我提供了一個GenericServlet之后,init方法還會執行嗎?
- 還會執行,會執行GenericServlet類中的init方法,
-
思考第二個問題:init方法是誰呼叫的?
- Tomcat服務器呼叫的,
-
思考第三個問題:init方法中的ServletConfig物件是誰創建的?是誰傳過來的?
- 都是Tomcat干的,
- Tomcat服務器先創建了ServletConfig物件,然后呼叫init方法,將ServletConfig物件傳給了init方法,
-
思考一下Tomcat服務器偽代碼:
-
public class Tomcat { public static void main(String[] args){ // ..... // Tomcat服務器偽代碼 // 創建LoginServlet物件(通過反射機制,呼叫無引數構造方法來實體化LoginServlet物件) Class class = Class.forName("com.baidu.javaweb.servlet.LoginServlet"); Object obj = class.newInstance(); // 向下轉型 Servlet servlet = (Servlet)obj; // 創建ServletConfig物件 // Tomcat服務器負責將ServletConfig物件實體化出來, // 多型(Tomcat服務器完全實作了Servlet規范) ServletConfig servletConfig = new org.apache.catalina.core.StandardWrapperFacade(); // 呼叫Servlet的init方法 servlet.init(servletConfig); // 呼叫Servlet的service方法 // .... } }
-
-
-
再思考一下:
-
init方法中的ServletConfig物件是Tomcat小貓咪創建好的,
-
這個ServletConfig物件目前在inti方法的引數上,屬于區域變數,
-
那么ServletConfig物件以后肯定要在service方法中使用,怎么才能保證ServletConfig物件在service方法中能夠使用呢?
- 直接看代碼:
import javax.servlet.*; import java.io.IOException; public abstract class GenericServlet implements Servlet { // 成員變數 private ServletConfig config; @Override public void init(ServletConfig servletConfig) throws ServletException { // 將servletConfig 賦值給 config this.config = servletConfig; } @Override public ServletConfig getServletConfig() { // 這里就可以回傳config物件了, return config; } @Override public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException; @Override public String getServletInfo() { return null; } @Override public void destroy() { } }
-
-
再思考一下:
-
如果繼承GenericServlet的類,想要重寫init方法呢?
- 給init方法加上final,這樣子類就無法重寫init方法了,
-
但是如果子類就是要重寫init方法呢?
- 解決辦法:再GenericServlet類中添加一個無參的init方法,供子類進行重寫,
-
-
最終GenericServlet類的代碼;
-
import javax.servlet.*; import java.io.IOException; public abstract class GenericServlet implements Servlet { // 成員變數 private ServletConfig config; @Override public final void init(ServletConfig servletConfig) throws ServletException { // 將servletConfig 賦值給 config this.config = servletConfig; this.init(); } // 供子類重寫 public void init() { } @Override public ServletConfig getServletConfig() { // 這里就可以回傳config物件了, return config; } @Override public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException; @Override public String getServletInfo() { return null; } @Override public void destroy() { } }
-
-
值得慶幸的是:GenericServlet不需要我們程式員寫,官方替我們寫好了,
-
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package javax.servlet; import java.io.IOException; import java.io.Serializable; import java.util.Enumeration; public abstract class GenericServlet implements Servlet, ServletConfig, Serializable { private static final long serialVersionUID = 1L; private transient ServletConfig config; public GenericServlet() { } public void destroy() { } public String getInitParameter(String name) { return this.getServletConfig().getInitParameter(name); } public Enumeration<String> getInitParameterNames() { return this.getServletConfig().getInitParameterNames(); } public ServletConfig getServletConfig() { return this.config; } public ServletContext getServletContext() { return this.getServletConfig().getServletContext(); } public String getServletInfo() { return ""; } public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); } public void init() throws ServletException { } public void log(String message) { this.getServletContext().log(this.getServletName() + ": " + message); } public void log(String message, Throwable t) { this.getServletContext().log(this.getServletName() + ": " + message, t); } public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException; public String getServletName() { return this.config.getServletName(); } } -
可以看到官方寫的GenericServlet跟我們自己寫的差不多,實作的思想是一樣的,
-
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/394999.html
標籤:其他
上一篇:【計理02組04號】順序查找
下一篇:6.s081 lab1
