我们看下engine,引擎的执行
如下engine下包含了host节点
<Engine name="Catalina" defaultHost="localhost"> <!--For clustering, please take a look at documentation at: /docs/cluster-howto.html (simple how to) /docs/config/cluster.html (reference documentation) --> <!-- <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> --> <!-- Use the LockOutRealm to prevent attempts to guess user passwords via a brute-force attack --> <Realm className="org.apache.catalina.realm.LockOutRealm"> <!-- This Realm uses the UserDatabase configured in the global JNDI resources under the key "UserDatabase". Any edits that are performed against this UserDatabase are immediately available for use by the Realm. --> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <!-- SingleSignOn valve, share authentication between web applications Documentation at: /docs/config/valve.html --> <!-- <Valve className="org.apache.catalina.authenticator.SingleSignOn" /> --> <!-- Access log processes all example. Documentation at: /docs/config/valve.html Note: The pattern used is equivalent to using pattern="common" --> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> </Engine>
接口里包含了host节点
public interface Engine extends Container { //设置host public String getDefaultHost(); public void setDefaultHost(String defaultHost); public String getJvmRoute(); public void setJvmRoute(String jvmRouteId); public Service getService(); public void setService(Service service); }
默认引擎的类加载图
构造方法
public StandardEngine() { super(); //设置管道 pipeline.setBasic(new StandardEngineValve()); /* Set the jmvRoute using the system property jvmRoute */ try {//设置jvm路径 setJvmRoute(System.getProperty("jvmRoute")); } catch(Exception ex) { log.warn(sm.getString("standardEngine.jvmRouteFail")); } // By default, the engine will hold the reloading thread backgroundProcessorDelay = 10; }
@Override protected void initInternal() throws LifecycleException { // Ensure that a Realm is present before any attempt is made to start // one. This will create the default NullRealm if necessary. getRealm(); super.initInternal(); }
protected synchronized void startInternal() throws LifecycleException { // Log our server identification information if (log.isInfoEnabled()) { log.info(sm.getString("standardEngine.start", ServerInfo.getServerInfo())); } // Standard container startup super.startInternal(); }
<Engine name="Standalone" ...> ... <Valve className="org.apache.catalina.valves.AccessLogValve" prefix="catalina_access_log" suffix=".txt" pattern="common"/> ... </Engine>
@Override public AccessLog getAccessLog() { if (accessLogScanComplete) { return accessLog; } AccessLogAdapter adapter = null; Valve valves[] = getPipeline().getValves(); for (Valve valve : valves) { if (valve instanceof AccessLog) { // 看这里 if (adapter == null) { adapter = new AccessLogAdapter((AccessLog) valve); } else { adapter.add((AccessLog) valve); } } } if (adapter != null) { accessLog = adapter; } accessLogScanComplete = true; return accessLog; }
AccessLog(日志记录器)主要的作用就是记录日志,这个记录的方法就是logAccess()方法
getAccessLog日志
@Override public AccessLog getAccessLog() { if (accessLogScanComplete) { return accessLog; } AccessLogAdapter adapter = null; Valve valves[] = getPipeline().getValves();//是不是管道 for (Valve valve : valves) { if (valve instanceof AccessLog) {//adapter 用匹配器模式 if (adapter == null) { adapter = new AccessLogAdapter((AccessLog) valve); } else { adapter.add((AccessLog) valve); } } } if (adapter != null) { accessLog = adapter; } accessLogScanComplete = true; return accessLog; }
public void logAccess(Request request, Response response, long time, boolean useDefault) { boolean logged = false; if (getAccessLog() != null) {//如果找到了accessLog直接记录 accessLog.log(request, response, time); logged = true; } if (!logged && useDefault) {//如果没有找到,那么到子容器中找实现 AccessLog newDefaultAccessLog = defaultAccessLog.get(); if (newDefaultAccessLog == null) { // If we reached this point, this Engine can't have an AccessLog // Look in the defaultHost Host host = (Host) findChild(getDefaultHost()); Context context = null; if (host != null && host.getState().isAvailable()) { newDefaultAccessLog = host.getAccessLog(); if (newDefaultAccessLog != null) { if (defaultAccessLog.compareAndSet(null, newDefaultAccessLog)) { AccessLogListener l = new AccessLogListener(this, host, null); l.install(); } } else {//host为空,再找子容器 // Try the ROOT context of default host context = (Context) host.findChild(""); if (context != null && context.getState().isAvailable()) { newDefaultAccessLog = context.getAccessLog(); if (newDefaultAccessLog != null) {//如果host有,直接注册 if (defaultAccessLog.compareAndSet(null, newDefaultAccessLog)) { AccessLogListener l = new AccessLogListener( this, null, context); l.install(); } } } } } if (newDefaultAccessLog == null) {//如果依然为空, newDefaultAccessLog = new NoopAccessLog();//这个其实是一个空模式,以便采用统一方式调用(不用判空了) if (defaultAccessLog.compareAndSet(null, newDefaultAccessLog)) { AccessLogListener l = new AccessLogListener(this, host, context); l.install(); } } } // 最后记录日志,(上面最后有空模式实现,所以可以直接调用,不用判空) newDefaultAccessLog.log(request, response, time); } }