IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> tomcat源码分析-service及standardService分析 -> 正文阅读

[游戏开发]tomcat源码分析-service及standardService分析

前面已经知道,server管理包含多个service,我们从类的结构看起
1.整体类的继承结构
在这里插入图片描述
server.xml结构

<!--
    每个Service元素只能有一个Engine元素.元素处理在同一个<Service>中所有<Connector>元素接收到的客户请求
-->

<Service name="Catalina">
<!-- 1. 属性说明
	name:Service的名称
-->

    <!--2. 一个或多个excecutors -->
    <!--
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>
    -->

    <!--
		3.Connector元素:Connector接口定义.<Connector>元素代表与客户程序实际交互的组件,它负责接收客户请求,以及向客户返回响应结果.
    -->
    <Connector port="80" maxHttpHeaderSize="8192"
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" redirectPort="8443" acceptCount="100"
               connectionTimeout="20000" disableUploadTimeout="true" />
    <!-- 属性说明
		port:服务器连接器的端口号,该连接器将在指定端口侦听来自客户端的请求。
		enableLookups:如果为true,则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名;
					若为false则不进行DNS查询,而是返回其ip地址。
		redirectPort:服务器正在处理http请求时收到了一个SSL传输请求后重定向的端口号。
		acceptCount:当所有可以使用的处理请求的线程都被用光时,可以放到处理队列中的请求数,超过这个数的请求将不予处理,而返回Connection refused错误。
		connectionTimeout:等待超时的时间数(以毫秒为单位)。
		maxThreads:设定在监听端口的线程的最大数目,这个值也决定了服务器可以同时响应客户请求的最大数目.默认值为200。
		protocol:必须设定为AJP/1.3协议。
		address:如果服务器有两个以上IP地址,该属性可以设定端口监听的IP地址,默认情况下,端口会监听服务器上所有IP地址。
		minProcessors:服务器启动时创建的处理请求的线程数,每个请求由一个线程负责。
		maxProcessors:最多可以创建的处理请求的线程数。
		minSpareThreads:最小备用线程 。
		maxSpareThreads:最大备用线程。
		debug:日志等级。
		disableUploadTimeout:禁用上传超时,主要用于大数据上传时。
    -->


    <Connector port="8009" enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />
    <!-- 负责和其他HTTP服务器建立连接。在把Tomcat与其他HTTP服务器集成时就需要用到这个连接器。 -->
	
    <!--
		4. Engine
    -->
    <Engine name="Catalina" defaultHost="localhost">
    
    </Engine>
  </Service>

如上面所示,我们要从,engine,connector,Executor,engine四个组件介绍

service接口

public interface Service extends Lifecycle {
//负责处理connectors的所有请求
    public Engine getContainer();

  
    public void setContainer(Engine engine);

    public String getName();
    public void setName(String name);

    public Server getServer();

    public void setServer(Server server);

	//返回父类加载器,如果没有设置返回system class loader
    public ClassLoader getParentClassLoader();

    public void setParentClassLoader(ClassLoader parent);
	//container注册的域
    public String getDomain();
    
    public void addConnector(Connector connector);

    public Connector[] findConnectors();
    public void removeConnector(Connector connector);

    public void addExecutor(Executor ex);
    public Executor[] findExecutors();
    public Executor getExecutor(String name);
    public void removeExecutor(Executor ex);
    Mapper getMapper();
}

StandardService实现

  • 成员变量
 /**
     * The name of this service.
     */
     //名字
    private String name = null;


    /**
     * The <code>Server</code> that owns this Service, if any.
     */
     //server本身
    private Server server = null;

    /**
     * The property change support for this component.
     */
    protected final PropertyChangeSupport support = new PropertyChangeSupport(this);


    /**
     * The set of Connectors associated with this Service.
     */
     //连接器,这里为什么不用list,我分析可能是数量很少,所有没必要用list
    protected Connector connectors[] = new Connector[0];
    private final Object connectorsLock = new Object();

    /**
     * The list of executors held by the service.
     */
    protected final ArrayList<Executor> executors = new ArrayList<>();

    private Engine engine = null;

    private ClassLoader parentClassLoader = null;

    /**
     * Mapper.
     */
    protected final Mapper mapper = new Mapper();


    /**
     * Mapper listener.
     */
    protected final MapperListener mapperListener = new MapperListener(this);

如上的结构可以看出,service包括,一个engine,一个mapper,多个connectors,多个executor,一个mapperListener。

  • Engine相关
private Engine engine = null;

@Override
public Engine getContainer() {
    return engine;
}

@Override
public void setContainer(Engine engine) {
    Engine oldEngine = this.engine;
    if (oldEngine != null) {
        oldEngine.setService(null);
    }
    this.engine = engine;
    if (this.engine != null) {
        this.engine.setService(this);
    }
    if (getState().isAvailable()) {
        if (this.engine != null) {
            try {
                this.engine.start(); // 启动Engine
            } catch (LifecycleException e) {
                log.error(sm.getString("standardService.engine.startFailed"), e);
            }
        }
        // 重启Mapper - Restart MapperListener to pick up new engine.
        try {
            mapperListener.stop();
        } catch (LifecycleException e) {
            log.error(sm.getString("standardService.mapperListener.stopFailed"), e);
        }
        try {
            mapperListener.start();
        } catch (LifecycleException e) {
            log.error(sm.getString("standardService.mapperListener.startFailed"), e);
        }
        if (oldEngine != null) {
            try {
                oldEngine.stop();
            } catch (LifecycleException e) {
                log.error(sm.getString("standardService.engine.stopFailed"), e);
            }
        }
    }

    // 触发container属性变更事件
    support.firePropertyChange("container", oldEngine, this.engine);
}
  • Connectors相关
  */
protected Connector connectors[] = new Connector[0];
private final Object connectorsLock = new Object();

/**
  * Add a new Connector to the set of defined Connectors, and associate it
  * with this Service's Container.
  *
  * @param connector The Connector to be added
  */
@Override
public void addConnector(Connector connector) {
	//这里体现了copyOnwright思想
    synchronized (connectorsLock) {
        connector.setService(this);
        Connector results[] = new Connector[connectors.length + 1];
        System.arraycopy(connectors, 0, results, 0, connectors.length);
        results[connectors.length] = connector;
        connectors = results;
    }

    try {
    //添加后立即启动
        if (getState().isAvailable()) {
            connector.start();
        }
    } catch (LifecycleException e) {
        throw new IllegalArgumentException(
                sm.getString("standardService.connector.startFailed", connector), e);
    }

    // Report this property change to interested listeners
    support.firePropertyChange("connector", null, connector);
}


public ObjectName[] getConnectorNames() {
    ObjectName results[] = new ObjectName[connectors.length];
    for (int i=0; i<results.length; i++) {
        results[i] = connectors[i].getObjectName();
    }
    return results;
}

/**
  * 当前Service相关的所有Connectors.
  */
@Override
public Connector[] findConnectors() {
    return connectors;
}

/**
  * 删除connector
  *
  * @param connector The Connector to be removed
  */
@Override
public void removeConnector(Connector connector) {

    synchronized (connectorsLock) {
        // 找到conector位置
        int j = -1;
        for (int i = 0; i < connectors.length; i++) {
            if (connector == connectors[i]) {
                j = i;
                break;
            }
        }
        if (j < 0)
            return;
        if (connectors[j].getState().isAvailable()) {
            try {
                connectors[j].stop(); // 停止
            } catch (LifecycleException e) {
                log.error(sm.getString(
                        "standardService.connector.stopFailed",
                        connectors[j]), e);
            }
        }
        connector.setService(null); // 去除父service绑定
        int k = 0;
        Connector results[] = new Connector[connectors.length - 1];
        for (int i = 0; i < connectors.length; i++) {
            if (i != j)
                results[k++] = connectors[i]; // 后续connector向前移位
        }
        connectors = results;

        // 触发connector属性变更事件
        support.firePropertyChange("connector", connector, null);
    }
}
  • Executor相关
    这里主要是对executor的增删改,同时增删的时候,注意容器的状态
/**
  * Adds a named executor to the service
  * @param ex Executor
  */
@Override
public void addExecutor(Executor ex) {
    synchronized (executors) {
        if (!executors.contains(ex)) {
            executors.add(ex);
            if (getState().isAvailable()) {
                try {
                    ex.start(); // 启动
                } catch (LifecycleException x) {
                    log.error(sm.getString("standardService.executor.start"), x);
                }
            }
        }
    }
}

/**
  * Retrieves all executors
  * @return Executor[]
  */
@Override
public Executor[] findExecutors() {
    synchronized (executors) {
        Executor[] arr = new Executor[executors.size()];
        executors.toArray(arr);
        return arr;
    }
}


/**
  * Retrieves executor by name, null if not found
  * @param executorName String
  * @return Executor
  */
@Override
public Executor getExecutor(String executorName) {
    synchronized (executors) {
        for (Executor executor: executors) {
            if (executorName.equals(executor.getName()))
                return executor;
        }
    }
    return null;
}

/**
 * Removes an executor from the service
 * @param ex Executor
  */
@Override
public void removeExecutor(Executor ex) {
    synchronized (executors) {
        if ( executors.remove(ex) && getState().isAvailable() ) {
            try {
                ex.stop(); // 停止
            } catch (LifecycleException e) {
                log.error(sm.getString("standardService.executor.stop"), e);
            }
        }
    }
}

Lifecycle相关模板方法

  • 初始化方法
/**
 * Invoke a pre-startup initialization. This is used to allow connectors
 * to bind to restricted ports under Unix operating environments.
 */
@Override
protected void initInternal() throws LifecycleException {

    super.initInternal();

    if (engine != null) {
        engine.init();
    }

    // Initialize any Executors
    for (Executor executor : findExecutors()) {
        if (executor instanceof JmxEnabled) {
            ((JmxEnabled) executor).setDomain(getDomain());
        }
        executor.init();
    }

    // Initialize mapper listener
    mapperListener.init();

    // Initialize our defined Connectors
    synchronized (connectorsLock) {
        for (Connector connector : connectors) {
            connector.init();
        }
    }
}
  • startInternal 方法
    protected void startInternal() throws LifecycleException {

        if(log.isInfoEnabled()) {
            log.info(sm.getString("standardService.start.name", this.name));
        }
        setState(LifecycleState.STARTING);

        // Start our defined Container first
        if (engine != null) {
            synchronized (engine) {
                engine.start();
            }
        }

        synchronized (executors) {
            for (Executor executor: executors) {
                executor.start();
            }
        }
//作用是在 start 的时候将容器类对象注册到 Mapper 对象中
        mapperListener.start();

        // Start our defined Connectors second
        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);
                }
            }
        }
    }

mapperListener 的作用是在 start 的时候将容器类对象注册到 Mapper 对象中。
Mapper是 Tomcat 处理 Http 请求时非常重要的组件。Tomcat 使用 Mapper 来处理一个 Request 到 Host、Context 的映射关系,从而决定使用哪个 Service 来处理请求。

mapperListener的startInternal方法:

    public void startInternal() throws LifecycleException {

        setState(LifecycleState.STARTING);

        Engine engine = service.getContainer();
        if (engine == null) {
            return;
        }
	//重要
        findDefaultHost();

        addListeners(engine);

        Container[] conHosts = engine.findChildren();
        for (Container conHost : conHosts) {
            Host host = (Host) conHost;
            if (!LifecycleState.NEW.equals(host.getState())) {
                // Registering the host will register the context and wrappers
                registerHost(host);
            }
        }
    }
  • findDefaultHost() 方法
private void findDefaultHost() {

    Engine engine = service.getContainer();
    String defaultHost = engine.getDefaultHost();

    boolean found = false;

    if (defaultHost != null && defaultHost.length() > 0) {
        Container[] containers = engine.findChildren();

        for (Container container : containers) {
            Host host = (Host) container;
            if (defaultHost.equalsIgnoreCase(host.getName())) {
                found = true;
                break;
            }

            String[] aliases = host.findAliases();
            for (String alias : aliases) {
                if (defaultHost.equalsIgnoreCase(alias)) {
                    found = true;
                    break;
                }
            }
        }
    }

    if (found) {
        mapper.setDefaultHostName(defaultHost);
    } else {
        log.error(sm.getString("mapperListener.unknownDefaultHost", defaultHost, service));
    }
}

findDefaultHost() 是主要是找出 defaultHost ,并调用
mapper.setDefaultHostName(defaultHost);
这个 defaultHost 是 server.xml 的 标签的属性,一般都是 “localHost”。

  • addListeners(engine) 方法在这里插入代码片
/**
 * Add this mapper to the container and all child containers
 *
 * @param container
 */
 //递归调用
private void addListeners(Container container) {
    container.addContainerListener(this);
    container.addLifecycleListener(this);
    for (Container child : container.findChildren()) {
        addListeners(child);
    }
}

这个方法的作用是,将 MapperListener 这个监听器添加到 Engine 及其子容器中。

  • registerHost
    调用 registerHost方法来注册 Engine 的字容器 Host。
/**
 * Register host.
 */
private void registerHost(Host host) {

    String[] aliases = host.findAliases();
    mapper.addHost(host.getName(), aliases, host);

    for (Container container : host.findChildren()) {
        if (container.getState().isAvailable()) {
            registerContext((Context) container);
        }
    }

    // Default host may have changed
    findDefaultHost();

    if(log.isDebugEnabled()) {
        log.debug(sm.getString("mapperListener.registerHost",
                host.getName(), domain, service));
    }
}

registerHost 方法先调用 mapper.addHost,然后调用 registerContext 方法注册 Host 的子容器 Context。
mapper.addHost 方法是将 Host 加入的 Mapper 类的的成员变量MappedHost[] hosts 中。

  • 接着看 registerContext 方法
/**
 * Register context.
 */
private void registerContext(Context context) {

    String contextPath = context.getPath();
    if ("/".equals(contextPath)) {
        contextPath = "";
    }
    Host host = (Host)context.getParent();

    WebResourceRoot resources = context.getResources();
    String[] welcomeFiles = context.findWelcomeFiles();
    List<WrapperMappingInfo> wrappers = new ArrayList<>();

    for (Container container : context.findChildren()) {
        prepareWrapperMappingInfo(context, (Wrapper) container, wrappers);

        if(log.isDebugEnabled()) {
            log.debug(sm.getString("mapperListener.registerWrapper",
                    container.getName(), contextPath, service));
        }
    }

    mapper.addContextVersion(host.getName(), host, contextPath,
            context.getWebappVersion(), context, welcomeFiles, resources,
            wrappers);

    if(log.isDebugEnabled()) {
        log.debug(sm.getString("mapperListener.registerContext",
                contextPath, service));
    }
}

registerContext 里先获取一些对象,比如 WebResourceRoot 对象、WrapperMappingInfo 对象,然后调用 mapper.addContextVersion。 Mapper#addContextVersion 方法比较琐细,就不细讲了。 其主要逻辑是将 Context 对象,以及 Context 的子容器 Wrapper 对象,每一个都分别构建一个对应的 MappedContext 和 MappedWrapper 对象, 然后把 MappedContext 和 MappedWrapper 塞进 ContextVersion 对象中, 最后把 Context 和 ContextVersion 的对应关系放在 Mapper 对象的一个 Map 里。 这里的 MappedContext 和 MappedWrapper 在 Tomcat 处理 Http 请求的时候是比较关键的。 registerHost 最后再更新了一下可能发生改变里的的 defaultHost

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-09-11 19:08:27  更:2021-09-11 19:10:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 12:13:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码