第十五節簡介我之前好像很長時間沒有把完整的代碼貼上了,其實我覺得前14節都是一些基礎性的東西。我們先來回憶一下,之前學了什麼。 剛開始主要是想讓大家先把tomcat理解成一個Connector 和 container的合體。之後我們知道connector是為了建立串連的,我們講了tomcat4的預設連接器,雖然現在被替代了。Container是用來處理請求的,說了Container的四種類型。以及其中的pipeline, vavle。其實我覺得這些 不需要我做什麼 代碼來示範,而是 應該自己去讀讀tomcat的代碼。所以,這節課 我不再寫那麼長的代碼了,我們用tomcat已經寫好的jar包。那麼開始Bootstrap
package com.vic.startup;import org.apache.catalina.Connector;import org.apache.catalina.Context;import org.apache.catalina.Lifecycle;import org.apache.catalina.LifecycleListener;import org.apache.catalina.Loader;import org.apache.catalina.Manager;import org.apache.catalina.Wrapper;import org.apache.catalina.connector.http.HttpConnector;import org.apache.catalina.core.StandardContext;import org.apache.catalina.loader.WebappLoader;import org.apache.catalina.session.StandardManager;import com.vic.core.SimpleContextConfig;import com.vic.core.SimpleWrapper;public class Bootstrap {public static void main(String[] args) {//這裡以前說過了,把catalina.base設定為一個系統屬性 值 為 使用者的當前工作目錄System.setProperty("catalina.base", System.getProperty("user.dir"));//建立一個連接器Connector connector = new HttpConnector();//這裡幫大家複習一下,wrapper負責管理Servlet,所以下面的代碼不言而喻Wrapper wrapper1 = new SimpleWrapper();wrapper1.setName("Session");wrapper1.setServletClass("SessionServlet");Context context = new StandardContext();//一個context包含多個wrappercontext.setPath("/myApp");context.setDocBase("myApp");context.addChild(wrapper1);context.addServletMapping("/myApp/Session", "Session");//這是生命週期的時候講的,這次我們用自己實現的,具體原因一會講LifecycleListener listener = new SimpleContextConfig();((Lifecycle) context).addLifecycleListener(listener);Loader loader = new WebappLoader();context.setLoader(loader);connector.setContainer(context);//添加一個Manager,這是12.13.14節的知識Manager manager = new StandardManager();context.setManager(manager);try {connector.initialize();((Lifecycle) connector).start();((Lifecycle) context).start();//當我們在Console視窗輸入一個位元組的時候,我們的web伺服器就自動停止了System.in.read();((Lifecycle) context).stop();}catch (Exception e) {e.printStackTrace();}}}
好的,我在解釋應該把 這個 bootstrap介紹的差不多了。接下來看core包的代碼。首先就是 實現了LifecycleListener介面的SimpleContextConfig。這個是我們自己實現的。
package com.vic.core;import org.apache.catalina.Context;import org.apache.catalina.Lifecycle;import org.apache.catalina.LifecycleEvent;import org.apache.catalina.LifecycleListener;public class SimpleContextConfig implements LifecycleListener {public void lifecycleEvent(LifecycleEvent event) {if (Lifecycle.START_EVENT.equals(event.getType())) {Context context = (Context) event.getLifecycle();context.setConfigured(true);}}}
這個沒什麼說的,Lifecycle我這裡說過了~SimplePipeline
package com.vic.core;import java.io.IOException;import javax.servlet.ServletException;import org.apache.catalina.Contained;import org.apache.catalina.Container;import org.apache.catalina.Lifecycle;import org.apache.catalina.LifecycleException;import org.apache.catalina.LifecycleListener;import org.apache.catalina.Pipeline;import org.apache.catalina.Request;import org.apache.catalina.Response;import org.apache.catalina.Valve;import org.apache.catalina.ValveContext;public class SimplePipeline implements Pipeline, Lifecycle {public SimplePipeline(Container container) {setContainer(container);}// The basic Valve (if any) associated with this Pipeline.protected Valve basic = null;// The Container with which this Pipeline is associated.protected Container container = null;// the array of Valvesprotected Valve valves[] = new Valve[0];public void setContainer(Container container) {this.container = container;}public Valve getBasic() {return basic;}public void setBasic(Valve valve) {this.basic = valve;((Contained) valve).setContainer(container);}public void addValve(Valve valve) {if (valve instanceof Contained)((Contained) valve).setContainer(this.container);synchronized (valves) {Valve results[] = new Valve[valves.length + 1];System.arraycopy(valves, 0, results, 0, valves.length);results[valves.length] = valve;valves = results;}}public Valve[] getValves() {return valves;}public void invoke(Request request, Response response) throws IOException,ServletException {// Invoke the first Valve in this pipeline for this request(new StandardPipelineValveContext()).invokeNext(request, response);}public void removeValve(Valve valve) {}// implementation of the Lifecycle interface's methodspublic void addLifecycleListener(LifecycleListener listener) {}public LifecycleListener[] findLifecycleListeners() {return null;}public void removeLifecycleListener(LifecycleListener listener) {}public synchronized void start() throws LifecycleException {}public void stop() throws LifecycleException {}// this class is copied from org.apache.catalina.core.StandardPipeline// class's// StandardPipelineValveContext inner class.protected class StandardPipelineValveContext implements ValveContext {protected int stage = 0;public String getInfo() {return null;}public void invokeNext(Request request, Response response)throws IOException, ServletException {int subscript = stage;stage = stage + 1;// Invoke the requested Valve for the current request threadif (subscript < valves.length) {valves[subscript].invoke(request, response, this);} else if ((subscript == valves.length) && (basic != null)) {basic.invoke(request, response, this);} else {throw new ServletException("No valve");}}} // end of inner class}
SimpleWrapper這個同樣,基本也是copy的,這裡沒什麼重點。
package com.vic.core;import java.beans.PropertyChangeListener;import java.io.IOException;import javax.naming.directory.DirContext;import javax.servlet.Servlet;import javax.servlet.ServletException;import javax.servlet.UnavailableException;import org.apache.catalina.Cluster;import org.apache.catalina.Container;import org.apache.catalina.ContainerListener;import org.apache.catalina.InstanceListener;import org.apache.catalina.Lifecycle;import org.apache.catalina.LifecycleException;import org.apache.catalina.LifecycleListener;import org.apache.catalina.Loader;import org.apache.catalina.Logger;import org.apache.catalina.Manager;import org.apache.catalina.Mapper;import org.apache.catalina.Pipeline;import org.apache.catalina.Realm;import org.apache.catalina.Request;import org.apache.catalina.Response;import org.apache.catalina.Valve;import org.apache.catalina.Wrapper;import org.apache.catalina.util.LifecycleSupport;public class SimpleWrapper implements Wrapper, Pipeline, Lifecycle {public SimpleWrapper() {pipeline.setBasic(new SimpleWrapperValve());}// the servlet instanceprivate Servlet instance = null;private String servletClass;private Loader loader;private String name;protected LifecycleSupport lifecycle = new LifecycleSupport(this);private SimplePipeline pipeline = new SimplePipeline(this);protected Container parent = null;protected boolean started = false;public synchronized void addValve(Valve valve) {pipeline.addValve(valve);}public Servlet allocate() throws ServletException {// Load and initialize our instance if necessaryif (instance == null) {try {instance = loadServlet();} catch (ServletException e) {throw e;} catch (Throwable e) {throw new ServletException("Cannot allocate a servlet instance", e);}}return instance;}public Servlet loadServlet() throws ServletException {if (instance != null)return instance;Servlet servlet = null;String actualClass = servletClass;if (actualClass == null) {throw new ServletException("servlet class has not been specified");}Loader loader = getLoader();// Acquire an instance of the class loader to be usedif (loader == null) {throw new ServletException("No loader.");}ClassLoader classLoader = loader.getClassLoader();// Load the specified servlet class from the appropriate class loaderClass classClass = null;try {if (classLoader != null) {classClass = classLoader.loadClass(actualClass);}} catch (ClassNotFoundException e) {throw new ServletException("Servlet class not found");}// Instantiate and initialize an instance of the servlet class itselftry {servlet = (Servlet) classClass.newInstance();} catch (Throwable e) {throw new ServletException("Failed to instantiate servlet");}// Call the initialization method of this servlettry {servlet.init(null);} catch (Throwable f) {throw new ServletException("Failed initialize servlet.");}return servlet;}public String getInfo() {return null;}public Loader getLoader() {if (loader != null)return (loader);if (parent != null)return (parent.getLoader());return (null);}public void setLoader(Loader loader) {this.loader = loader;}public Logger getLogger() {return null;}public void setLogger(Logger logger) {}public Manager getManager() {return null;}public void setManager(Manager manager) {}public Cluster getCluster() {return null;}public void setCluster(Cluster cluster) {}public String getName() {return name;}public void setName(String name) {this.name = name;}public Container getParent() {return parent;}public void setParent(Container container) {parent = container;}public ClassLoader getParentClassLoader() {return null;}public void setParentClassLoader(ClassLoader parent) {}public Realm getRealm() {return null;}public void setRealm(Realm realm) {}public DirContext getResources() {return null;}public void setResources(DirContext resources) {}public long getAvailable() {return 0;}public void setAvailable(long available) {}public String getJspFile() {return null;}public void setJspFile(String jspFile) {}public int getLoadOnStartup() {return 0;}public void setLoadOnStartup(int value) {}public String getRunAs() {return null;}public void setRunAs(String runAs) {}public String getServletClass() {return null;}public void setServletClass(String servletClass) {this.servletClass = servletClass;}public void addChild(Container child) {}public void addContainerListener(ContainerListener listener) {}public void addMapper(Mapper mapper) {}public void addPropertyChangeListener(PropertyChangeListener listener) {}public Container findChild(String name) {return null;}public Container[] findChildren() {return null;}public ContainerListener[] findContainerListeners() {return null;}public void addInitParameter(String name, String value) {}public void addInstanceListener(InstanceListener listener) {}public void addSecurityReference(String name, String link) {}public void deallocate(Servlet servlet) throws ServletException {}public String findInitParameter(String name) {return null;}public String[] findInitParameters() {return null;}public String findSecurityReference(String name) {return null;}public String[] findSecurityReferences() {return null;}public Mapper findMapper(String protocol) {return null;}public Mapper[] findMappers() {return null;}public void invoke(Request request, Response response) throws IOException,ServletException {pipeline.invoke(request, response);}public boolean isUnavailable() {return false;}public void load() throws ServletException {}public Container map(Request request, boolean update) {return null;}public void removeChild(Container child) {}public void removeContainerListener(ContainerListener listener) {}public void removeMapper(Mapper mapper) {}public void removeInitParameter(String name) {}public void removeInstanceListener(InstanceListener listener) {}public void removePropertyChangeListener(PropertyChangeListener listener) {}public void removeSecurityReference(String name) {}public void unavailable(UnavailableException unavailable) {}public void unload() throws ServletException {}// method implementations of Pipelinepublic Valve getBasic() {return pipeline.getBasic();}public void setBasic(Valve valve) {pipeline.setBasic(valve);}public Valve[] getValves() {return pipeline.getValves();}public void removeValve(Valve valve) {pipeline.removeValve(valve);}// implementation of the Lifecycle interface's methodspublic void addLifecycleListener(LifecycleListener listener) {}public LifecycleListener[] findLifecycleListeners() {return null;}public void removeLifecycleListener(LifecycleListener listener) {}public synchronized void start() throws LifecycleException {System.out.println("Starting Wrapper " + name);if (started)throw new LifecycleException("Wrapper already started");// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);started = true;// Start our subordinate components, if anyif ((loader != null) && (loader instanceof Lifecycle))((Lifecycle) loader).start();// Start the Valves in our pipeline (including the basic), if anyif (pipeline instanceof Lifecycle)((Lifecycle) pipeline).start();// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(START_EVENT, null);// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);}public void stop() throws LifecycleException {System.out.println("Stopping wrapper " + name);// Shut down our servlet instance (if it has been initialized)try {instance.destroy();} catch (Throwable t) {}instance = null;if (!started)throw new LifecycleException("Wrapper " + name + " not started");// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(STOP_EVENT, null);started = false;// Stop the Valves in our pipeline (including the basic), if anyif (pipeline instanceof Lifecycle) {((Lifecycle) pipeline).stop();}// Stop our subordinate components, if anyif ((loader != null) && (loader instanceof Lifecycle)) {((Lifecycle) loader).stop();}// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);}}
SimpleWrapperValve
package com.vic.core;import java.io.IOException;import javax.servlet.Servlet;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.catalina.Contained;import org.apache.catalina.Container;import org.apache.catalina.Context;import org.apache.catalina.Request;import org.apache.catalina.Response;import org.apache.catalina.Valve;import org.apache.catalina.ValveContext;public class SimpleWrapperValve implements Valve, Contained {protected Container container;public void invoke(Request request, Response response,ValveContext valveContext) throws IOException, ServletException {SimpleWrapper wrapper = (SimpleWrapper) getContainer();ServletRequest sreq = request.getRequest();ServletResponse sres = response.getResponse();Servlet servlet = null;HttpServletRequest hreq = null;if (sreq instanceof HttpServletRequest)hreq = (HttpServletRequest) sreq;HttpServletResponse hres = null;if (sres instanceof HttpServletResponse)hres = (HttpServletResponse) sres; Context context = (Context) wrapper.getParent(); request.setContext(context); try {servlet = wrapper.allocate();if (hres != null && hreq != null) {servlet.service(hreq, hres);} else {servlet.service(sreq, sres);}} catch (ServletException e) {}}public String getInfo() {return null;}public Container getContainer() {return container;}public void setContainer(Container container) {this.container = container;}}
這個類是重點,我們能看到第38/39行,為什麼要設定這個req的context,因為當我們從req想要得到一個session,我們會調用它的getSession的動作,但是getSession肯定是先去拿context,再拿context的manager,之後manager . 就完事了。 所以,我們要設定req的context,所以就在servlet生存的wrapper中設定。