zoukankan      html  css  js  c++  java
  • Tomcat组件梳理—Service组件

    Tomcat组件梳理—Service组件

    1.组件定义

    Tomcat中只有一个Server,一个Server可以用多个Service,一个Service可以有多个Connector和一个Container。

    Server掌握着整个Tomcat的生死大权。

    Service是对外提供服务的。一个Server可以有多个Service,只不过Cataina中只添加了一个,这一个就代表了Tomcat的所有服务。

    Connector用于接收请求并将请求封装成Request和Response来具体处理

    Container用于封装和管理Servlet,以及具体处理reqeust请求

    如上图,一个Service包含多个Connector和一个Engine,两者的关联关系使用Mapper来做映射,还有一个可选的线程池Executor。

    2.属性

    先把Service的属性代码摆出来:

       /**
         * service的名称
         */
        private String name = null;
    
        /**
         * Service所属的Server
         */
        private Server server = null;
    
        /**
         * 组件对属性改变的支持
         */
        protected final PropertyChangeSupport support = new PropertyChangeSupport(this);
    
        /**
         * 跟这个Service相关联的Connector集合
         */
        protected Connector connectors[] = new Connector[0];
    
        /**
         * Connector的锁
         */
        private final Object connectorsLock = new Object();
    
        /**
         * 线程池
         */
        protected final ArrayList<Executor> executors = new ArrayList<>();
    
        /**
         * Servlet的引擎
         */
        private Engine engine = null;
    
        /**
         * 类加载器
         */
        private ClassLoader parentClassLoader = null;
    
        /**
         * Mapper.
         */
        protected final Mapper mapper = new Mapper();
    
        /**
         * Mapper 监听器
         */
        protected final MapperListener mapperListener = new MapperListener(this);
    
    

    解释一下这里面关键的几个点:

    • Connector connectors[]:多个连接器,一个Servlet服务接受两个不同的协议连接,只不过不同的协议通过对应的Connector都被处理成了一个Request对象,这样对于Engine来说,都是一样的请求。

    • Engine engine:Servlet引擎,就是专门用来处理请求的,其他的都不管。

    • Mapper mapper:mapper保存了一个映射关系,不同请求路径对应哪一个Servlet的API。

    • PropertyChangeSupport support:JDK自带的观察者模式,主要是观察Java Bean对象的属性更改的,等会拿出来单独说。

    在Service属性中,主要就是这四个东西,主要的架构关系,在上面的图中有解析,就不再多介绍。

    3.动作

    Service的方法比较简单,因为只是包装,自己没有太多的一个功能,所有主要功能有:1.监听Service属性变化,2.启动,3.关闭。没了,就这三个,其他的都是对属性的setter和getter的具体实现,就不管了。

    3.1.启动

    在Server组件的分析中,我们已经知道了Server会调用Service的init()方法和start()方法来完成启动操作,那我们分别来看一下Service组件的init()和start()。

    首先是init()方法:

    protected void initInternal() throws LifecycleException {
    
        //1.父类执行init
        super.initInternal();
    
        //2.执行servlet的引擎engine的init
        if (engine != null) {
            engine.init();
        }
    
        // 3.执行Executors的init
        for (Executor executor : findExecutors()) {
            if (executor instanceof JmxEnabled) {
                ((JmxEnabled) executor).setDomain(getDomain());
            }
            executor.init();
        }
    
        // 4.mapper监听器的init
        mapperListener.init();
    
        // 5.connect的init
        synchronized (connectorsLock) {
            for (Connector connector : connectors) {
                try {
                    connector.init();
                } catch (Exception e) {
                    String message = sm.getString(
                            "standardService.connector.initFailed", connector);
                    log.error(message, e);
    
                    if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
                        throw new LifecycleException(message);
                    }
                }
            }
        }
    }
    

    好像没有太多可说的,自己没有做啥事情,就是调用自己的子组件的init()方法。主要包括Engine,Executor,Mapper,Connector这四个。

    再看一个start()方法:

    protected void startInternal() throws LifecycleException {
    
        //1.设置生命周期的状态
        setState(LifecycleState.STARTING);
    
        //2.执行engine的start
        if (engine != null) {
            synchronized (engine) {
                engine.start();
            }
        }
    
        //3.执行executor的start
        synchronized (executors) {
            for (Executor executor: executors) {
                executor.start();
            }
        }
    
        //4.执行mapper监听器的start
        mapperListener.start();
    
        // 5.执行connect的start
        synchronized (connectorsLock) {
            for (Connector connector: connectors) {
                try {
                    // If it has already failed, don't try and start it
                    if (connector.getState() != LifecycleState.FAILED) {
                        connector.start();
                    }
                } catch (Exception e) {
                    log.error(sm.getString(
                            "standardService.connector.startFailed",
                            connector), e);
                }
            }
        }
    }
    

    同init()方法一样,没啥好说的。

    3.2.关闭

    Service的关闭操作主要调用两个方法,分别是stop(),destroy()。这两个代码里的业务逻辑跟启动里面的是一样的,就是去调用子组件里对应的方法。没啥好说的,不过还是把代码放一下看看。

    首先是stop()方法

    protected void stopInternal() throws LifecycleException {
    
        //先暂停或者关闭Connector
        synchronized (connectorsLock) {
            for (Connector connector: connectors) {
                try {
                    //暂停
                    connector.pause();
                } catch (Exception e) {
                    log.error(sm.getString(
                            "standardService.connector.pauseFailed",
                            connector), e);
                }
    
                //如果有绑定socket,就关闭掉
                connector.getProtocolHandler().closeServerSocketGraceful();
            }
        }
    
    
        setState(LifecycleState.STOPPING);
    
        // 调用engine的stop()方法
        if (engine != null) {
            synchronized (engine) {
                engine.stop();
            }
        }
    
        // 调用Connector的stop()方法
        synchronized (connectorsLock) {
            for (Connector connector: connectors) {
                if (!LifecycleState.STARTED.equals(
                        connector.getState())) {
                    // Connectors only need stopping if they are currently
                    // started. They may have failed to start or may have been
                    // stopped (e.g. via a JMX call)
                    continue;
                }
                try {
                    connector.stop();
                } catch (Exception e) {
                    log.error(sm.getString(
                            "standardService.connector.stopFailed",
                            connector), e);
                }
            }
        }
    
        // 调用mapperListener的stop()方法
        if (mapperListener.getState() != LifecycleState.INITIALIZED) {
            mapperListener.stop();
        }
    
        //调用executor的stop()方法
        synchronized (executors) {
            for (Executor executor: executors) {
                executor.stop();
            }
        }
    }
    

    然后是destroy()方法

    protected void destroyInternal() throws LifecycleException {
        //1.调用mapper的destroy()方法
        mapperListener.destroy();
    
        //2.调用每个Connector的destroy()方法
        synchronized (connectorsLock) {
            for (Connector connector : connectors) {
                try {
                    connector.destroy();
                } catch (Exception e) {
                    log.error(sm.getString(
                            "standardService.connector.destroyFailed", connector), e);
                }
            }
        }
    
        //3.调用Executor的destroy()的方法
        for (Executor executor : findExecutors()) {
            executor.destroy();
        }
    
        //4.调用engine的destroy()方法
        if (engine != null) {
            engine.destroy();
        }
    
        super.destroyInternal();
    }
    

    如上,真的没啥好说的,就不说了。

    3.3.监听Service属性变化

    这里是一个比较有意思的操作,就是你怎么去监听一个java对象的属性被改变了?

    我想大部分都有思路,使用监听器设计模式,是的。但是JDK已经提供好了这种使用方法,并在Tomcat里有了比较好的应用。这里只看Tomcat中是怎么用的。介绍会比较简单,详细的可以查看下面的 "参考文章"。

    Tomcat中使用JDK中的PropertyChangeSupport类来实现监听的需求,使用该类需要按照如下要求:

    1.在Service中构造一个PropertyChangeSupport类,并将这个Java Bean传入。

    //org.apache.catalina.core.StandardService
    /**
     * 属性改变的监听管理
     */
    protected final PropertyChangeSupport support = new PropertyChangeSupport(this);
    
    

    2.需要在Service中添加对应的添加监听器方法和删除监听器方法,对应如下:

    /**
     * Add a property change listener to this component.
     * @param listener The listener to add
     */
    public void addPropertyChangeListener(PropertyChangeListener listener) {
      support.addPropertyChangeListener(listener);
    }
    
    /**
     * Remove a property change listener from this component.
     * @param listener The listener to remove
     */
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        support.removePropertyChangeListener(listener);
    }
    

    3.最后,如果需要实现自己的监听器,只需要实现void propertyChange(PropertyChangeEvent evt);方法即可。

    public interface PropertyChangeListener extends java.util.EventListener {
    
        /**
         * This method gets called when a bound property is changed.
         * @param evt A PropertyChangeEvent object describing the event source
         *          and the property that has changed.
         */
    
        void propertyChange(PropertyChangeEvent evt);
    
    }
    

    这样,就可以来完成对Service属性的监听了。非常好的方法,之前从来不知道。

    5.总结

    Service的动作不多,主要是对Connector和Engine的包装成一个组件,方便统一管理和映射。但是Service里面有一个监听Java Bean属性变化的使用还是挺有意思的。具体可以参考下面的文章

    参考文章:

  • 相关阅读:
    《JavaScript》forEach()和map()
    《JavaScript》split和join
    09慕课网《进击Node.js基础(一)》HTTP-get/request
    08慕课网《进击Node.js基础(一)》事件events
    07慕课网《进击Node.js基础(一)》HTTP小爬虫
    06慕课网《进击Node.js基础(一)》作用域和上下文
    05慕课网《进击Node.js基础(一)》HTTP概念进阶(同步/异步)
    前端每周学习分享--第4期
    前端每周学习分享--第3期
    前端每周学习分享--第2期
  • 原文地址:https://www.cnblogs.com/cenyu/p/11080505.html
Copyright © 2011-2022 走看看