tomcat源码-engine及standardEngine实现

本文档详细介绍了Tomcat服务器中Engine的配置,包括defaultHost、Realm和Host节点的设置,以及Cluster的注释说明。Engine的初始化和启动过程也进行了讲解,特别是如何设置和获取AccessLog进行日志记录。在访问日志部分,讨论了AccessLogValve的使用,以及如何在不同层级的容器中寻找和记录日志。
摘要由CSDN通过智能技术生成

我们看下engine,引擎的执行

server.xml

如下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 &quot;%r&quot; %s %b" />

      </Host>
    </Engine>

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);
}

standardEngine

默认引擎的类加载图
在这里插入图片描述
构造方法

    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;
    }
  • 初始化InitInternal
    初始化里没有做,获取realm和调用父类的方法
    @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();
    }
  • 启动startInternal
    启动方法调用了父类的方法
    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();
    }
  • LogAccess
    日志访问,运行web服务器时,正常生成的输出文件之一是访问日志,该访问日志以标准格式为服务器处理的每个请求生成一行信息。
    catalina 包含一个可选的valve实现,该实现可以创建与Web服务器创建的标准格式相同的访问日志,也可以创建任意数量的自定义格式。
<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);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值