博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Tomcat组件梳理—Service组件
阅读量:5086 次
发布时间:2019-06-13

本文共 8011 字,大约阅读时间需要 26 分钟。

Tomcat组件梳理—Service组件

1.组件定义

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

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

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

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

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

790334-20190625001750087-1612317974.png

如上图,一个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
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属性变化的使用还是挺有意思的。具体可以参考下面的文章

参考文章:

  • 《Java架构师必读源码之Tomcat8》https://www.jianshu.com/p/2ca506449b90
  • 《PropertyChangeSupport类》https://blog.csdn.net/todebug/article/details/1776324

转载于:https://www.cnblogs.com/cenyu/p/11080505.html

你可能感兴趣的文章
Alan Turing的纪录片观后感
查看>>
c#自定义控件中的事件处理
查看>>
IOS--沙盒机制
查看>>
使用 JointCode.Shuttle 访问任意 AppDomain 的服务
查看>>
sqlite的坑
查看>>
digitalocean --- How To Install Apache Tomcat 8 on Ubuntu 16.04
查看>>
【题解】[P4178 Tree]
查看>>
Mongo自动备份
查看>>
cer证书签名验证
查看>>
synchronized
查看>>
【深度学习】caffe 中的一些参数介绍
查看>>
Python-Web框架的本质
查看>>
QML学习笔记之一
查看>>
App右上角数字
查看>>
从.NET中委托写法的演变谈开去(上):委托与匿名方法
查看>>
小算法
查看>>
201521123024 《java程序设计》 第12周学习总结
查看>>
新作《ASP.NET MVC 5框架揭秘》正式出版
查看>>
IdentityServer4-用EF配置Client(一)
查看>>
WPF中实现多选ComboBox控件
查看>>