美文网首页
Tomcat源码解析-组件之StandardEngine

Tomcat源码解析-组件之StandardEngine

作者: 贪睡的企鹅 | 来源:发表于2019-08-14 16:41 被阅读0次

    1 Container容器

    Container容器用来表示tomcat中servlet容器,负责servelt的加载和管理,处理请求,并返回标准的 ServletResponse 对象给连接器。

    image

    Container容器组件

    tomcat 将Container容器按功能分为4个组件,分别是 Engine、Host、Context 和 Wrapper。这 4 种容器不是平行关系,而是父子关系。

    • Wrapper:表示一个 Servlet

    • Context:表示一个 Web 应用程序,一个 Web 应用程序中可能会有多个 Servlet

    • Host:表示的是一个虚拟主机,或者说一个站点,可以给 Tomcat 配置多个虚拟主机地址,而一个虚拟主机下可以部署多个 Web 应用程序

    • Engine:表示引擎,用来管理多个虚拟站点,一个 Service 最多只能有一个 Engine。

    image

    2 StandardEngine类结构

    image
    2.1 Lifecycle接口
    public interface Lifecycle {
        ....
        // 初始化方法
        public void init() throws LifecycleException;
        // 启动方法
        public void start() throws LifecycleException;
        // 停止方法,和start对应
        public void stop() throws LifecycleException;
        // 销毁方法,和init对应
        public void destroy() throws LifecycleException;
        // 获取生命周期状态
        public LifecycleState getState();
        // 获取字符串类型的生命周期状态
        public String getStateName();
    }
    

    Lifecycle接口定义tomcat中所有组件的生命周期相关接口方法。Tomcat 定义一个基类LifecycleBase 来实现 Lifecycle 接口,把一些公共的逻辑放到基类中实现。而子类就负责实现自己的初始化、启动和停止等模板方法。

    详见 Tomcat架构设计-组件生命周期 Lifecycle

    2.2 Container接口
    public interface Container extends Lifecycle {
        
        public static final String ADD_CHILD_EVENT = "addChild";
    
        public static final String ADD_VALVE_EVENT = "addValve";
    
        public static final String REMOVE_CHILD_EVENT = "removeChild";
        
        public static final String REMOVE_VALVE_EVENT = "removeValve";
        
        //返回日志组件
        public Log getLogger();
        
        //返回日志名称
        public String getLogName();
        
        //返回容器注册到JMX bean ObjectName
        public ObjectName getObjectName();
        
        //返回容器注册到JMX bean 命名空间
        public String getDomain();
        
        //返回容器注册到JMX bean 属性
        public String getMBeanKeyProperties();
        
        //返回容器依赖Pipeline组件
        public Pipeline getPipeline();
        
        //返回容器依赖Cluster组件
        public Cluster getCluster();
        
        //设置容器依赖Cluster组件
        public void setCluster(Cluster cluster);
        
        //返回周期性任务执行间隔事件
        public int getBackgroundProcessorDelay();
        
        //设置周期性任务执行间隔事件
        public void setBackgroundProcessorDelay(int delay);
        
        //返回容器名称
        public String getName();
        
        //设置容器名称
        public void setName(String name);
        
        //返回父容器
        public Container getParent();
        
        //设置父容器
        public void setParent(Container container);
        
        //返回父类加载器
        public ClassLoader getParentClassLoader();
        
        //设置父类加载器
        public void setParentClassLoader(ClassLoader parent);
        
        //返回容器依赖Realm组件
        public Realm getRealm();
        
        // 设置容器依赖Realm组件
        public void setRealm(Realm realm);
        
        //容器默认周期性任务处理调用方法
        public void backgroundProcess();
        
        //为当前容器组件添加子容器组件
        public void addChild(Container child);
        
        //添加容器事件监听器
        public void addContainerListener(ContainerListener listener);
        
        //添加属性变更监听器
        public void addPropertyChangeListener(PropertyChangeListener listener);
        
        //查找指定名称的子容器
        public Container findChild(String name);
        
        //获取所有子容器组件
        public Container[] findChildren();
        
        //返回所有容器事件监听器
        public ContainerListener[] findContainerListeners();
    
        //删除子容器
        public void removeChild(Container child);
        
        //当前容器删除容器事件监听器
        public void removeContainerListener(ContainerListener listener);
        
        //当前容器删除属性变更监听器
        public void removePropertyChangeListener(PropertyChangeListener listener);
        
        //处理容器事件
        public void fireContainerEvent(String type, Object data);
        
        //使用AccessLog组件打印请求日志
        public void logAccess(Request request, Response response, long time,
                boolean useDefault);
        
        //返回访问日志组件AccessLog
        public AccessLog getAccessLog();
        
        //返回设置处理子容器启动关闭线程池核心线程数。
        public int getStartStopThreads();
    
        //设置处理子容器启动关闭线程池核心线程数。
        public void setStartStopThreads(int startStopThreads);
    
        //返回tomcat工作目录
        public File getCatalinaBase();
    
        //返回tomcat安装目录
        public File getCatalinaHome();
    }
    

    Container接口定义tomcat中所有容器组件的通用接口方法。Tomcat 定义一个基类ContainerBase 来实现Container 接口,把一些公共的逻辑放到基类中实现。

    详见 Tomcat架构设计-容器组件基类 ContainerBase

    3 StandardEngine职责&核心属性

    3.1 职责

    StandardEngine核心职责实现Engine接口,并管理子容器Host组件(下图蓝色),以及从父类ContainerBase(下图红色),LifecycleBase(下图黄色) 继承的通用组件。

    image
    public interface Engine extends Container {
        
        //获取默认host组件名称
        public String getDefaultHost();
        
        //设置默认host组件名称
        public void setDefaultHost(String defaultHost);
        
        //获取Tomcat实例的JVM路由ID。所有路由ID必须唯一
        public String getJvmRoute();
        
        //设置Tomcat实例的JVM路由ID。所有路由ID必须唯一
        public void setJvmRoute(String jvmRouteId);
        
        //返回关联上层组件Service
        public Service getService();
        
        //设置关联上层组件Service
        public void setService(Service service);
    }
    
    3.2 核心属性

    StandardEngine内部只定义实现Engine接口所需要的属性。

    public class StandardEngine extends ContainerBase implements Engine {
    
         //默认host子组件名称
        private String defaultHost = null;
    
         //上层Service组件
        private Service service = null;
    
         //Tomcat实例的JVM路由ID。所有路由ID必须唯一,用于集群环境中
        private String jvmRouteId;
        
        ...省略代码
    

    其主要属性从ContainerBase继承而来

    public abstract class ContainerBase extends LifecycleMBeanBase
            implements Container {
            
        ...省略代码    
        /**
         * 当前容器的名称
         */
        protected String name = null;
    
        /**
         * 当前容器组件的父容器组件
         */
        protected Container parent = null;
    
        /**
         * 父类加载器
         */
        protected ClassLoader parentClassLoader = null;
    
    
        /**
         * 存储子容器的Map,key表示容器的名称,value表示容器组件对象
         */
        protected final HashMap<String, Container> children = new HashMap<>();
    
        /**
         * 容器事件监听器
         */
        protected final List<ContainerListener> listeners = new CopyOnWriteArrayList<>();
    
        /**
         * log组件
         */
        protected Log logger = null;
    
        /**
         * 关联的log名称
         */
        protected String logName = null;
    
        /**
         * 当前容器组件对应cluster组件
         */
        protected Cluster cluster = null;
    
        /**
         * 集群对象CLuster读写锁
         */
        private final ReadWriteLock clusterLock = new ReentrantReadWriteLock();
    
        /**
         * 当前容器组件对应的的Realm组件
         */
        private volatile Realm realm = null;
    
        /**
         * 当前容器组件对应的Realm组件读写锁
         */
        private final ReadWriteLock realmLock = new ReentrantReadWriteLock();
    
        /**
         * 当前容器组件对应的pipeline组件
         */
        protected final Pipeline pipeline = new StandardPipeline(this);
    
        /**
         * 当前容器组件对应的AccessLog组件
         */
        protected volatile AccessLog accessLog = null;
    
        /**
         * 获取AccessLog组件时
         * 如果accessLogScanComplete为false
         * 对AccessLog组件初始化(扫描pipeline组件中类型为AccessLog的Value,添加到AccessLog组件)
         */
        private volatile boolean accessLogScanComplete = false;
    
    
        //工具类
        /**
         * 错误日志管理器
         */
        protected static final StringManager sm =
            StringManager.getManager(Constants.Package);
    
    
        /**
         * 属性变更处理器
         */
        protected final PropertyChangeSupport support =
                new PropertyChangeSupport(this);
                
        ...省略代码           
    

    4 StandardEngine运行流程

    tomcat中所有组件都需要经历如下流程。

    [图片上传失败...(image-43b823-1565851092609)]

    4.1 构建StandardEngine

    Tomcat使用Digester解析server.xml,Digester是一款用于将xml转换为Java对象的事件驱动型工具,是对SAX的高层次的封装。相对于SAX,Digester可以针对每一个xml标签设置对应的解析规则。详见 Tomcat相关技术-Digester(二)

    Tomcat在Catalina组件初始化阶段调用createStartDigester()创建Digester对象,Digester对象内包含解析server.xml规则,接着通过Digester对象解析server.xml实例化StandardEngine,并对部分属性设置值.

    server.xml配置

       <Engine name="Catalina" defaultHost="localhost">
          <Realm className="org.apache.catalina.realm.LockOutRealm">
            <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
                   resourceName="UserDatabase"/>
          </Realm>
          <Host name="localhost"  appBase="webapps"
                unpackWARs="true" autoDeploy="true">
            <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>标签及子标签tomcat在2个规则组EngineRuleSetHostRuleSet中定义了解析规则。

           //设置EngineRuleSet作为解析规则组, 解析<Server><Service>子标签
            digester.addRuleSet(new EngineRuleSet("Server/Service/"));
    
            //设置HostRuleSet作为解析规则组.解析<Server><Service><Engine>子标签
            digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
        
    
    4.1 EngineRuleSet规则组
    4.1.1 解析<Engine>标签
            /** 解析<Engine>标签实例化StandardEngine对象,并push到操作栈中 **/
            digester.addObjectCreate(prefix + "Engine",
                                     "org.apache.catalina.core.StandardEngine",
                                     "className");
    
            /** 解析<Engine>标签将标签中属性值映射到其实例化对象中**/
            digester.addSetProperties(prefix + "Engine");
            
            
             /** 解析<Engine>标签将操作栈栈顶对象作为次栈顶对象StandardService.setContainer方法调用的参数,设置到StandardServer.container属性中**/
            digester.addSetNext(prefix + "Engine",
                                "setContainer",
                                "org.apache.catalina.Engine");
                                
            /** 解析<Engine>标签,使用LifecycleListenerRule规则,负责给栈顶对象添加一个生命周期监听器. 默认listenerClass为engineConfigClass,
             * 或者在标签指定org.apache.catalina.startup.EngineConfig属性值作为listenerClass**/
            digester.addRule(prefix + "Engine",
                             new LifecycleListenerRule
                             ("org.apache.catalina.startup.EngineConfig",
                              "engineConfigClass"));                    
    
    

    实例化StandardEngine

        /**
         * 实例化StandardEngine
         */
        public StandardEngine() {
            super();
            /** 设置StandardEngineValve作为pipeline组件尾阀门 **/
            pipeline.setBasic(new StandardEngineValve());
            /** 从系统属性jvmRoute值,设置 Tomcat实例的JVM路由ID **/
            try {
                setJvmRoute(System.getProperty("jvmRoute"));
            } catch(Exception ex) {
                log.warn(sm.getString("standardEngine.jvmRouteFail"));
            }
            /** 设置周期任务执行间隔事件 **/
            backgroundProcessorDelay = 10;
        }
    

    设置标签属性映射到StandardEngine对象

    <Engine>标签中属性可以查看官方文档 /docs/config/host.htm,这里所有属性在上面的属性中都有说明。

    4.1.2 解析<Cluster>标签
            //解析<Server><Service><Engine><Cluster>标签
            /** 解析<Cluster>标签实例化标签中className属性定义的对象,并push到操作栈中 **/
            digester.addObjectCreate(prefix + "Engine/Cluster",
                                     null, // MUST be specified in the element
                                     "className");
    
            /** 解析<Cluster>标签将标签中属性值映射到其实例化对象中**/
            digester.addSetProperties(prefix + "Engine/Cluster");
    
            /** 解析<Cluster>标签将操作栈栈顶对象作为次栈顶对象StandardEngine.setCluster方法调用的参数,即设置到StandardEngine.cluster属性中**/
            digester.addSetNext(prefix + "Engine/Cluster",
                                "setCluster",
                                "org.apache.catalina.Cluster");
    

    设置cluster组件

    setCluster()方法是从父类ContainerBase继承.

    public abstract class ContainerBase extends LifecycleMBeanBase
            implements Container {
            
        ...省略代码    
    
        @Override
        public void setCluster(Cluster cluster) {
    
            Cluster oldCluster = null;
            Lock writeLock = clusterLock.writeLock();
            writeLock.lock();
            try {
                /**  获取当前组件原始Cluster组件对象引用设置给oldCluster **/
                oldCluster = this.cluster;
                if (oldCluster == cluster)
                    return;
                this.cluster = cluster;
    
                /**  如果当前组件还在运行,则停止oldCluster组件 **/
                if (getState().isAvailable() && (oldCluster != null) &&
                    (oldCluster instanceof Lifecycle)) {
                    try {
                        ((Lifecycle) oldCluster).stop();
                    } catch (LifecycleException e) {
                        log.error("ContainerBase.setCluster: stop: ", e);
                    }
                }
    
                /** 将新设置cluster组件和当前容器组件对象反相关联 **/
                if (cluster != null)
                    cluster.setContainer(this);
    
                /** 如果当前组件处于运行状态,启动新设置cluster组件 **/
                if (getState().isAvailable() && (cluster != null) &&
                    (cluster instanceof Lifecycle)) {
                    try {
                        ((Lifecycle) cluster).start();
                    } catch (LifecycleException e) {
                        log.error("ContainerBase.setCluster: start: ", e);
                    }
                }
            } finally {
                writeLock.unlock();
            }
    
            /** 触发属性变更 **/
            support.firePropertyChange("cluster", oldCluster, cluster);
        }
    
    4.1.3 解析<Listener>标签
            //解析<Server><Service><Engine><Listener>标签
            /** 解析<Listener>标签实例化标签中className属性定义的对象,并push到操作栈中 **/
            digester.addObjectCreate(prefix + "Engine/Listener",
                                     null, // MUST be specified in the element
                                     "className");
    
            /** 解析<Listener>标签将标签中属性值映射到其实例化对象中**/
            digester.addSetProperties(prefix + "Engine/Listener");
    
            /** 解析<Cluster>标签将操作栈栈顶对象作为次栈顶对象StandardEngine.addLifecycleListener方法调用的参数,即设置到StandardEngine生命周期监听器数组中**/
            digester.addSetNext(prefix + "Engine/Listener",
                                "addLifecycleListener",
                                "org.apache.catalina.LifecycleListener");
    

    注册生命周期监听器

    addLifecycleListener()方法是从父类LifecycleBase继承.

    
    public abstract class LifecycleBase implements Lifecycle {
    
        /**
         * 管理当前组件生命周期监听器列表
         */
        private final List<LifecycleListener> lifecycleListeners = new CopyOnWriteArrayList<>();
        
        /**
         * 给当前组件添加一个生命周期监听器
         */
        @Override
        public void addLifecycleListener(LifecycleListener listener) {
            lifecycleListeners.add(listener);
        }
    
    4.1.4 解析<Valve>标签
            //解析<Server><Service><Engine><Valve>标签
            /** 解析<Valve>标签实例化标签中className属性定义的对象,并push到操作栈中 **/
            digester.addObjectCreate(prefix + "Engine/Valve",
                                     null, // MUST be specified in the element
                                     "className");
    
            /** 解析<Valve>标签将标签中属性值映射到其实例化对象中**/
            digester.addSetProperties(prefix + "Engine/Valve");
    
    
            /** 解析<Valve>标签将操作栈栈顶对象作为次栈顶对象StandardEngine.addValve方法调用的参数,即设置到StandardEngine中Pipline组件中**/
            digester.addSetNext(prefix + "Engine/Valve",
                                "addValve",
                                "org.apache.catalina.Valve");
    

    给子pipeline组件添加Valve处理器

    addValve()方法是从父类ContainerBase继承.

    public abstract class ContainerBase extends LifecycleMBeanBase
            implements Container {
            
        /**
         * 当前容器组件对应的pipeline组件
         */
        protected final Pipeline pipeline = new StandardPipeline(this);    
        /**
         * 给pipeline组件添加一个Valve
         */
        public synchronized void addValve(Valve valve) {
            pipeline.addValve(valve);
        }
    
    4.1.5 解析<Realm>标签
        /** 解析<Realm>标签使用自定义规则组RealmRuleSet**/
        digester.addRuleSet(new RealmRuleSet(prefix + "Engine/"));
        
        /**
         * 解析Realm标签添加到StandardEngine属性中
         */
        @SuppressWarnings("deprecation")
        public class RealmRuleSet extends RuleSetBase {
        
            @Override
            public void addRuleInstances(Digester digester) {
                StringBuilder pattern = new StringBuilder(prefix);
                for (int i = 0; i < MAX_NESTED_REALM_LEVELS; i++) {
                    if (i > 0) {
                        pattern.append('/');
                    }
                    pattern.append("Realm");
                    addRuleInstances(digester, pattern.toString(), i == 0 ? "setRealm" : "addRealm");
                }
            }
        
            private void addRuleInstances(Digester digester, String pattern, String methodName) {
                digester.addObjectCreate(pattern, null /* MUST be specified in the element */,
                        "className");
                digester.addSetProperties(pattern);
                digester.addSetNext(pattern, methodName, "org.apache.catalina.Realm");
                digester.addRuleSet(new CredentialHandlerRuleSet(pattern + "/"));
            }
        }    
    
    4.2 EngineRuleSet规则组
       @Override
        public void addRuleInstances(Digester digester) {
    
            //解析<Server><Service><Engine><Host>标签
            /** 解析<Host>标签实例化StandardHost对象,并push到操作栈中 **/
            digester.addObjectCreate(prefix + "Host",
                                     "org.apache.catalina.core.StandardHost",
                                     "className");
    
            /** 解析<Host>标签将标签中属性值映射到其实例化对象中**/
            digester.addSetProperties(prefix + "Host");
    
    
            /** 解析<Host>标签,使用CopyParentClassLoaderRule规则,负责调用次栈顶对象getParentClassLoader获取父类加载,设置到栈顶对象parentClassLoader属性上 **/
            digester.addRule(prefix + "Host",
                             new CopyParentClassLoaderRule());
    
            /** 解析<Host>标签,使用LifecycleListenerRule规则,负责给栈顶对象添加一个生命周期监听器. 默认为hostConfigClass,或者在标签指定org.apache.catalina.startup.HostConfig属性**/
            digester.addRule(prefix + "Host",
                             new LifecycleListenerRule
                             ("org.apache.catalina.startup.HostConfig",
                              "hostConfigClass"));
    
            /** 解析<Host>标签将操作栈栈顶对象作为次栈顶对象StandardService.addChild方法调用的参数,即将实例化StandardHost对象添加StandardServer.child子容器列表属性中**/
            digester.addSetNext(prefix + "Host",
                                "addChild",
                                "org.apache.catalina.Container");
    
    4.3 重要的规则
    4.3.1 CopyParentClassLoaderRule规则

    CopyParentClassLoaderRule规则,负责调用次栈顶对象getParentClassLoader获取父类加载,设置到栈顶对象parentClassLoader属性上

    public class CopyParentClassLoaderRule extends Rule {
    
    
        public CopyParentClassLoaderRule() {
        }
        
        @Override
        public void begin(String namespace, String name, Attributes attributes)
            throws Exception {
    
            if (digester.getLogger().isDebugEnabled())
                digester.getLogger().debug("Copying parent class loader");
            Container child = (Container) digester.peek(0);
            Object parent = digester.peek(1);
            Method method =
                parent.getClass().getMethod("getParentClassLoader", new Class[0]);
            ClassLoader classLoader =
                (ClassLoader) method.invoke(parent, new Object[0]);
            child.setParentClassLoader(classLoader);
    
        }
    }
    
    
    4.3.2 LifecycleListenerRule规则

    LifecycleListenerRule 规则负责给栈顶对象添加一个生命周期监听器.

    /**
     *  解析标签给栈顶对象添加一个生命周期监听器
     */
    public class LifecycleListenerRule extends Rule {
        
        public LifecycleListenerRule(String listenerClass, String attributeName) {
            this.listenerClass = listenerClass;
            this.attributeName = attributeName;
        }
        /**
         * 标准中指定属性,用来设置监听器处理类
         */
        private final String attributeName;
    
        /**
         * 默认监听器处理类
         */
        private final String listenerClass;
        
        @Override
        public void begin(String namespace, String name, Attributes attributes)
            throws Exception {
    
            /** 获取栈顶原始对象 **/
            Container c = (Container) digester.peek();
    
            /** 获取次栈顶元素对象 **/
            Container p = null;
            Object obj = digester.peek(1);
    
            /** 如果栈顶元素对象是容器设置给p **/
            if (obj instanceof Container) {
                p = (Container) obj;
            }
    
            String className = null;
    
            /** 获取标签attributeName值赋值给className **/
            if (attributeName != null) {
                String value = attributes.getValue(attributeName);
                if (value != null)
                    className = value;
            }
    
            /** 获取次栈顶对象attributeName属性值赋值给className **/
            if (p != null && className == null) {
                String configClass =
                    (String) IntrospectionUtils.getProperty(p, attributeName);
                if (configClass != null && configClass.length() > 0) {
                    className = configClass;
                }
            }
    
            /** 如果className == null使用listenerClass作为className默认值**/
            if (className == null) {
                className = listenerClass;
            }
    
    
            /** 实例化className添加栈顶对象生命周期监听器列表中*/
            Class<?> clazz = Class.forName(className);
            LifecycleListener listener = (LifecycleListener) clazz.getConstructor().newInstance();
            c.addLifecycleListener(listener);
        }
    }
    

    组件生命周期

    接下来初始化开始则进入tomcat组件的生命周期,对于tomcat中所有组件都必须实现Lifecycle,Tomcat 定义一个基类LifecycleBase 来实现 Lifecycle 接口,把一些公共的逻辑放到基类中实现,比如生命状态的转变与维护、生命事件的触发以及监听器的添加和删除等,而子类就负责实现自己的初始化、启动和停止等模板方法。为了避免跟基类中的方法同名,我们把具体子类的实现方法改个名字,在后面加上 Internal,叫 initInternal、startInternal 等。

    StandardEngine父类对容器的初始化、启动和停止等模板方法进行的了默认实现。子类容器只需要重写父类实现即可实现扩展。

    4.2 初始化StandardEngine
        @Override
        protected void initInternal() throws LifecycleException {
            getRealm();
            super.initInternal();
        }
    
    4.3 启动StandardEngine
        @Override
        protected synchronized void startInternal() throws LifecycleException {
            if(log.isInfoEnabled()){
                log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo());
            }
            super.startInternal();
        }
    

    StandardEngine其他生命周期实现均从父类ContainerBase继承。

    4.4 停止StandardEngine
    /**
         * 组件停止模板实现
         */
        @Override
        protected synchronized void stopInternal() throws LifecycleException {
    
            /** 关闭处理定时任务线程 **/
            threadStop();
    
            /** 设置当前容器的状态LifecycleState.STOPPING **/
            setState(LifecycleState.STOPPING);
    
    
            /** 停止pipeline组件**/
            if (pipeline instanceof Lifecycle &&
                    ((Lifecycle) pipeline).getState().isAvailable()) {
                ((Lifecycle) pipeline).stop();
            }
    
            /** 使用线程池异步处理子容器关闭 **/
            Container children[] = findChildren();
            List<Future<Void>> results = new ArrayList<>();
            for (int i = 0; i < children.length; i++) {
                results.add(startStopExecutor.submit(new StopChild(children[i])));
            }
    
            /** 等待所有子容器关闭完毕 **/
            boolean fail = false;
            for (Future<Void> result : results) {
                try {
                    result.get();
                } catch (Exception e) {
                    log.error(sm.getString("containerBase.threadedStopFailed"), e);
                    fail = true;
                }
            }
            if (fail) {
                throw new LifecycleException(
                        sm.getString("containerBase.threadedStopFailed"));
            }
    
            /** 关闭Realm组件**/
            Realm realm = getRealmInternal();
            if (realm instanceof Lifecycle) {
                ((Lifecycle) realm).stop();
            }
    
            /** 关闭Cluster组件**/
            Cluster cluster = getClusterInternal();
            if (cluster instanceof Lifecycle) {
                ((Lifecycle) cluster).stop();
            }
        }
    
    4.5 销毁StandardEngine
    /**
         * 组件销毁模板实现
         */
        @Override
        protected void destroyInternal() throws LifecycleException {
    
            /** 销毁Realm组件**/
            Realm realm = getRealmInternal();
            if (realm instanceof Lifecycle) {
                ((Lifecycle) realm).destroy();
            }
    
            /** 销毁cluster组件**/
            Cluster cluster = getClusterInternal();
            if (cluster instanceof Lifecycle) {
                ((Lifecycle) cluster).destroy();
            }
    
            /** 销毁cluster组件**/
            if (pipeline instanceof Lifecycle) {
                ((Lifecycle) pipeline).destroy();
            }
    
            /** 清空所有子容器 **/
            for (Container child : findChildren()) {
                removeChild(child);
            }
    
            /** 父容器和当前容器组件取消关联 **/
            if (parent != null) {
                parent.removeChild(this);
            }
    
            /** 关闭处理子容器启动关闭线程池 **/
            if (startStopExecutor != null) {
                startStopExecutor.shutdownNow();
            }
    
            super.destroyInternal();
        }
    

    5 核心方法

    5.1 重写addChild
        @Override
        public void addChild(Container child) {
            if (!(child instanceof Host)){
                throw new IllegalArgumentException
                        (sm.getString("standardEngine.notHost"));
            }
            super.addChild(child);
        }
    
    5.2 重写logAccess
        /**
         * AccessLog组件
         */
        private final AtomicReference<AccessLog> defaultAccessLog =
            new AtomicReference<>();
            
        
        /**
         * 使用AccessLog组件打印日志,
         *
         * 如果useDefault=true,使用defaultAccessLog属性中保存AccessLog打印日志
         * 如果defaultAccessLog未初始化AccessLog,则尝试从子容器host,context获取绑定的AccessLog组件设置到defaultAccessLog,使用新设置AccessLog组件打印日志
         */
        @Override
        public void logAccess(Request request, Response response, long time,
                boolean useDefault) {
    
            boolean logged = false;
    
            if (getAccessLog() != null) {
                accessLog.log(request, response, time);
                logged = true;
            }
    
            if (!logged && useDefault) {
                AccessLog newDefaultAccessLog = defaultAccessLog.get();
                /** 如果newDefaultAccessLog未初始化 **/
                if (newDefaultAccessLog == null) {
                    /** 获取默认host子容器组件 **/
                    Host host = (Host) findChild(getDefaultHost());
                    Context context = null;
                    if (host != null && host.getState().isAvailable()) {
                        /** 获取host容器绑定的AccessLog 设置给 newDefaultAccessLog**/
                        newDefaultAccessLog = host.getAccessLog();
    
                        if (newDefaultAccessLog != null) {
                            if (defaultAccessLog.compareAndSet(null,
                                    newDefaultAccessLog)) {
                                AccessLogListener l = new AccessLogListener(this,
                                        host, null);
                                l.install();
                            }
                        } else {
                            /** 获取context容器绑定的AccessLog 设置给 newDefaultAccessLog**/
                            context = (Context) host.findChild("");
                            if (context != null &&
                                    context.getState().isAvailable()) {
                                newDefaultAccessLog = context.getAccessLog();
                                if (newDefaultAccessLog != null) {
                                    if (defaultAccessLog.compareAndSet(null,
                                            newDefaultAccessLog)) {
                                        /** 并设置AccessLogListener 作为当前容器对象engine,和子容器host的监听器。 **/
                                        AccessLogListener l = new AccessLogListener(
                                                this, null, context);
                                        l.install();
                                    }
                                }
                            }
                        }
                    }
    
                    /** 如果无法从子容器获取AccessLog,默认使用NoopAccessLog作为默认的AccessLog **/
                    if (newDefaultAccessLog == null) {
                        newDefaultAccessLog = new NoopAccessLog();
                        if (defaultAccessLog.compareAndSet(null,
                                newDefaultAccessLog)) {
                            /** 并设置AccessLogListener 作为当前容器对象engine,和子容器host的监听器。 **/
                            AccessLogListener l = new AccessLogListener(this, host,
                                    context);
                            l.install();
                        }
                    }
                }
                /** 使用newDefaultAccessLog打印日志 **/
                newDefaultAccessLog.log(request, response, time);
            }
        }    
    

    AccessLogListener

    AccessLogListener同时实现3种监听器

       protected static final class AccessLogListener
                implements PropertyChangeListener, LifecycleListener,
                ContainerListener {
    

    绑定监听器,取消监听器

           public void install() {
                engine.addPropertyChangeListener(this);
                if (host != null) {
                    host.addContainerListener(this);
                    host.addLifecycleListener(this);
                }
                if (context != null) {
                    context.addLifecycleListener(this);
                }
            }
    
            private void uninstall() {
                disabled = true;
                if (context != null) {
                    context.removeLifecycleListener(this);
                }
                if (host != null) {
                    host.removeLifecycleListener(this);
                    host.removeContainerListener(this);
                }
                engine.removePropertyChangeListener(this);
            }
    

    监听事件处理

            @Override
            public void lifecycleEvent(LifecycleEvent event) {
                if (disabled) return;
    
                String type = event.getType();
                if (Lifecycle.AFTER_START_EVENT.equals(type) ||
                        Lifecycle.BEFORE_STOP_EVENT.equals(type) ||
                        Lifecycle.BEFORE_DESTROY_EVENT.equals(type)) {
                    engine.defaultAccessLog.set(null);
                    uninstall();
                }
            }
    
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (disabled) return;
                if ("defaultHost".equals(evt.getPropertyName())) {
                    engine.defaultAccessLog.set(null);
                    uninstall();
                }
            }
    
            @Override
            public void containerEvent(ContainerEvent event) {
                if (disabled) return;
                if (Container.ADD_CHILD_EVENT.equals(event.getType())) {
                    Context context = (Context) event.getData();
                    if ("".equals(context.getPath())) {
                        engine.defaultAccessLog.set(null);
                        uninstall();
                    }
                }
            }
    

    6 处理流程

    每一个容器组件都有一个 Pipeline 对象,Pipeline 中维护了 Valve 链表,默认时每一个Pipeline存放了一个默认的BasicValue,
    这里每一个Value表示一个处理点,当调用addValve 方法时会将添加Vaule添加到链表头部,Pipeline 中没有 invoke
    方法,请求处理时Pipeline只需要获取链表中第一个Valve调用incoke去执行,执行完毕后当前Value会调用
    getNext.invoke() 来触发下一个 Valve 调用

    每一个容器在执行到最后一个默认BasicValue时,会负责调用下层容器的 Pipeline 里的第一个 Valve

    Pipeline.jpg

    对于StandardEngine容器来说默认情况只添加了一个默认的StandardEngineValve。

    7.1 StandardEngineValve
    final class StandardEngineValve extends ValveBase {
    
        public StandardEngineValve() {
            super(true);
        }
    
    
        private static final StringManager sm =
            StringManager.getManager(Constants.Package);
    
    
        @Override
        public final void invoke(Request request, Response response)
            throws IOException, ServletException {
    
            /** 获取host子容器组件 **/
            Host host = request.getHost();
            if (host == null) {
                response.sendError
                    (HttpServletResponse.SC_BAD_REQUEST,
                     sm.getString("standardEngine.noHost",
                                  request.getServerName()));
                return;
            }
    
            /** 如果当前请求支持异步,则检查当前容器组件Pipeline管道种所有Value阀是否都支持异步,如果不是则重置为false **/
            if (request.isAsyncSupported()) {
                /** getPipeline().isAsyncSupported() 如果当前容器组件Pipeline管道种所有Value阀都支持异步则返回true**/
                /** 设置当前请求是否支持异步,需要当前容器Pipeline管道种所有Value阀都支持异步 **/
                request.setAsyncSupported(host.getPipeline().isAsyncSupported());
            }
    
            /** 调用host容器的Pipeline管道的第一个Value阀执行 **/
            host.getPipeline().getFirst().invoke(request, response);
        }
    }
    

    7 EngineConfig监听器

    解析xml种给StandardEngine组件添加LifecycleListener监听器,负责监听生命周期事件打印日志

    public class EngineConfig
        implements LifecycleListener {
    
        private static final Log log = LogFactory.getLog(EngineConfig.class);
    
        protected Engine engine = null;
    
        protected static final StringManager sm =
            StringManager.getManager(Constants.Package);
    
    
        @Override
        public void lifecycleEvent(LifecycleEvent event) {
    
    
            try {
                /** 获取触发事件的组件engine **/
                engine = (Engine) event.getLifecycle();
            } catch (ClassCastException e) {
                log.error(sm.getString("engineConfig.cce", event.getLifecycle()), e);
                return;
            }
            /** 如果当前事件START_EVENT,调用start()方法打印启动日志 **/
            if (event.getType().equals(Lifecycle.START_EVENT))
                start();
    
            /** 如果当前事件STOP_EVENT,调用stop()方法打印停止日志 **/
            else if (event.getType().equals(Lifecycle.STOP_EVENT))
                stop();
        }
    
        protected void start() {
            if (engine.getLogger().isDebugEnabled())
                engine.getLogger().debug(sm.getString("engineConfig.start"));
        }
    
    
        protected void stop() {
            if (engine.getLogger().isDebugEnabled())
                engine.getLogger().debug(sm.getString("engineConfig.stop"));
    
        }
    }
    

    相关文章

      网友评论

          本文标题:Tomcat源码解析-组件之StandardEngine

          本文链接:https://www.haomeiwen.com/subject/rhhnjctx.html