• tomcat启动(五)Catalina分析-service.init


    上篇写到StandardService.init()

    这个方法做什么呢?一起来看看。

    这个类也是实现了Lifecycle

    如图。这个图中i表示Interface接口。如Lifecycle,Container,Executor

    C表示Class类 如StandardService

    C上有一个小A表示Abstract Class抽象类 如LifecycleBase,WebappClassLoaderBase

    感觉用这个图来表示继承关系很好,但这个不能显示出实现关系。要用类图才可以。

    public class StandardService extends LifecycleMBeanBase implements Service

     跑题了。。

    StandardService和StandardServer一样也是继承自LifecycleMBeanBase

    在StandardService没有init方法。

    调用的其实是LifecycleBase这个类的init方法,然后会调用StandardService.initInternal()

    主要作用:

    Invoke a pre-startup initialization. This is used to allow connectors to bind to restricted ports under Unix operating environments.

    调用预启动初始化。这用于允许connectors绑定到Unix操作环境下的受限端口。

    执行LifecycleMBeanBase.initInternal()向MBeanServer类进行MBean(service)组件注册

    在这个StandardService的initInternal方法中会先判断container是否为空,

    如果不为空则执行container.init()注册container组件(这里的Container是:StandardEngine)

    1、初始化所有Executors   

    其实就是为Executor指定domain,

    然后使用StandardThreadExecutor.initInteral()方法

    向MBeanServer注册Executor组件(跟server和service调用init()过程一样)

    这里的Executor加载的是org.apache.catalina.core.StandardThreadExecutor类

    public interface Executor extends java.util.concurrent.Executor, Lifecycle

    //这里可以略过。。。。
    An object that executes submitted Runnable tasks. This interface provides a way of decoupling task submission from the mechanics of how each task will be run, including details of thread use, scheduling, etc. An Executor is normally used instead of explicitly creating threads. For example, rather than invoking new Thread(new(RunnableTask())).start() for each of a set of tasks, you might use:
    执行提交Runnable任务的对象。该接口提供了一种将任务提交从每个任务的运行机制分解的
    方法,包括线程使用,调度等的细节。通常使用执行程序,而不是显式创建线程。例如,您可以
    使用以下各项来调用每个新任务

    Executor executor
    = anExecutor; executor.execute(new RunnableTask1()); executor.execute(new RunnableTask2()); ... However, the Executor interface does not strictly require that execution be asynchronous. In the simplest case, an executor can run the submitted task immediately in the caller's thread:
    Executor接口并不严格要求执行是异步的。在最简单的情况下,执行程序可以立即在调用者的线程中运行提交的任务: class DirectExecutor implements Executor { public void execute(Runnable r) { r.run(); } }} More typically, tasks are executed in some thread other than the caller's thread. The executor below spawns a new thread for each task. class ThreadPerTaskExecutor implements Executor { public void execute(Runnable r) { new Thread(r).start(); } }} Many Executor implementations impose some sort of limitation on how and when tasks are scheduled. The executor below serializes the submission of tasks to a second executor, illustrating a composite executor.
    更通常地,任务在除调用者的线程之外的一些线程中执行。下面的执行器为每个任务生成一个新的线程。
    class SerialExecutor implements Executor { final Queue tasks = new ArrayDeque(); final Executor executor; Runnable active; SerialExecutor(Executor executor) { this.executor = executor; } public synchronized void execute(final Runnable r) { tasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (active == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((active = tasks.poll()) != null) { executor.execute(active); } } }} The Executor implementations provided in this package implement ExecutorService, which is a more extensive interface. The ThreadPoolExecutor class provides an extensible thread pool implementation. The Executors class provides convenient factory methods for these Executors. Memory consistency effects: Actions in a thread prior to submitting a Runnable object to an Executor happen-before its execution begins, perhaps in another thread.
    此包中提供的Executor实现来实现ExecutorService,它是一个更广泛的接口。
    ThreadPoolExecutor类提供了一个可扩展的线程池实现。
    Executors类为这些
    Executors执行人员提供了方便的工厂方法。
    内存一致性效果:在将Runnable对象提交给执行程序之前,线程中的操作会在其执行开始之前发生,也许在另一个线程中。

    2 、初始化Mapper Listener。调用MapperListener.init()方法,跟上面server,service,executor一样注册组件

    3   初始化自定义connectors连接器  Initialize our defined Connectors。

    同上调用connector.init()注册connector组件

    但在connector.initInteral()方法被重写了

    代码不长就贴出来吧

    @Override
        protected void initInternal() throws LifecycleException {
    
            super.initInternal();
    
            // Initialize adapter
            adapter = new CoyoteAdapter(this);
            protocolHandler.setAdapter(adapter);
    
            // Make sure parseBodyMethodsSet has a default
            if( null == parseBodyMethodsSet ) {
                setParseBodyMethods(getParseBodyMethods());
            }
    
            if (protocolHandler.isAprRequired() &&
                    !AprLifecycleListener.isAprAvailable()) {
                throw new LifecycleException(
                        sm.getString("coyoteConnector.protocolHandlerNoApr",
                                getProtocolHandlerClassName()));
            }
    
            try {
                protocolHandler.init();
            } catch (Exception e) {
                throw new LifecycleException
                    (sm.getString
                     ("coyoteConnector.protocolHandlerInitializationFailed"), e);
            }
        }

     初始化CoyoteAdapter

    Implementation of a request processor which delegates委托 the processing to a Coyote processor

    执行将处理委托给CoyoteAdapter的请求处理器

    ProtocolHandler protocolHandler端口处理程序

    摘要协议实现,包括线程等。ProtocolHandler 处理器是单线程的,

    特定于基于流的协议,不适合像JNI这样的Jk协议。这是由CoyoteAdapter实现的主要接口。

    adapter是由coyote servlet container.实现的主要接口。

    这个ProtocolHandler是一个接口,调用的ProtocolHandler.init()方法的类是org.apache.coyote.http11.Http11NioProtocol

    Note:这里不是用Http11Protocol进行处理,我这个tomcat8.0版本是使用Http11NioProtocol处理器

    在Connector构造方法中通过protocolHandlerClassName这个变量来生成处理程序实例

    connecto被创建会先设置端口处理程序setProtocol()

    这里处理http协议请求的有两个处理器

    Http11AprProtocol和Http11NioProtocol前者需要安装复杂环境,后者为默认处理器
    /**
         * Coyote Protocol handler class name.
         * Defaults to the Coyote HTTP/1.1 protocolHandler.
         */
        protected String protocolHandlerClassName =
            "org.apache.coyote.http11.Http11NioProtocol";
    public Connector(String protocol) {
      setProtocol(protocol);
    
      Class<?> clazz = Class.forName(protocolHandlerClassName);
      p = (ProtocolHandler) clazz.newInstance();//生成实例
    
    }
    
    public void setProtocol(String protocol) {
    
            if (AprLifecycleListener.isAprAvailable()) {
                if ("HTTP/1.1".equals(protocol)) {
                    setProtocolHandlerClassName
                        ("org.apache.coyote.http11.Http11AprProtocol");
                } else if ("AJP/1.3".equals(protocol)) {
                    setProtocolHandlerClassName
                        ("org.apache.coyote.ajp.AjpAprProtocol");
                } else if (protocol != null) {
                    setProtocolHandlerClassName(protocol);
                } else {
                    setProtocolHandlerClassName
                        ("org.apache.coyote.http11.Http11AprProtocol");
                }
            } else {
                if ("HTTP/1.1".equals(protocol)) {
                    setProtocolHandlerClassName
                        ("org.apache.coyote.http11.Http11NioProtocol");
                } else if ("AJP/1.3".equals(protocol)) {
                    setProtocolHandlerClassName
                        ("org.apache.coyote.ajp.AjpNioProtocol");
                } else if (protocol != null) {
                    setProtocolHandlerClassName(protocol);
                }
            }
    
        }

     初始化protocolHandler也就是调用Http11NioProtocol的init方法

    public abstract class AbstractProtocol<S> implements ProtocolHandler , MBeanRegistration

    有上面可以知道AbstractProtocol实现的ProtocolHandler

    --》实际调用

    @Override
        public void init() throws Exception {
            // SSL implementation needs to be in place before end point is
            // initialized
    必须在end point被初始化之前创建SSL
    sslImplementation = SSLImplementation.getInstance(sslImplementationName); super.init(); }
    // Component not pre-registered so register it注册protocolHandler组件
    Registry.getRegistry(null, null).registerComponent(this, oname,
                        null);
    //创建thread pool线程池的MBean的名称
    tpOname = new ObjectName(domain + ":" +
                            "type=ThreadPool,name=" + getName());
    getName()获得的名字是prefix-address-port 
    //注册线程池组件
    Registry.getRegistry(null, null).registerComponent(endpoint,
                            tpOname, null);
    //Name of MBean for the Global Request Processor.
    //注册GlobalRequestProcessor全局请求处理器组件
    rgOname=new ObjectName(domain +
                        ":type=GlobalRequestProcessor,name=" + getName());
                Registry.getRegistry(null, null).registerComponent(
                        getHandler().getGlobal(), rgOname, null );
    String endpointName = getName();
            endpoint.setName(endpointName.substring(1, endpointName.length()-1));
    这里从1开始length-1结束是为了去掉首尾双引号
    endpoint.init();

     这里执行endpoint是执行的NioEndpoint.init()方法-------在Http11NioProtocol构造方法中设置

    public Http11NioProtocol() {
            endpoint=new NioEndpoint();
            cHandler = new Http11ConnectionHandler(this);
            ((NioEndpoint) endpoint).setHandler(cHandler);
            setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
            setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
            setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
        }
    NioEndpoint这个类解释
    NIO tailored thread pool, providing the following services: 
        •Socket acceptor thread
        •Socket poller thread
        •Worker threads pool
    When switching to Java 5, there's an opportunity to use the virtual machine's 
    thread pool.
    NIO定制的线程池,提供以下服务:
    •套接字线程
    •套接字轮询线程
    •工作线程池
    切换到Java 5时,有机会使用虚拟机的线程池。

     NioEndpoint.init()没有重写父类的方法----调用

    public final void init() throws Exception {
            testServerCipherSuitesOrderSupport();
            if (bindOnInit) {
                bind();
                bindState = BindState.BOUND_ON_INIT;
            }
        }

     parameter:bindOnInit:默认为true

    Controls when the Endpoint binds the port.控制endpoint绑定端口

    true, the default binds the port on init() and unbinds it on destroy().

    If set to false the port is bound on start() and unbound on stop().

    NioEndpoint.bind()

     
    /**
         * Initialize the endpoint.
         */
        @Override
        public void bind() throws Exception {
    面向流的listening socket的可选通道,新创建的服务器套接字通道已打开但尚未绑定。
    调用未绑定服务器套接字通道的accept方法的尝试将导致抛出NotYetBoundException。
    可以通过调用此类定义的bind方法来绑定服务器套接字通道 serverSock
    = ServerSocketChannel.open(); socketProperties.setProperties(serverSock.socket());
    //实现了ip套接字地址 InetSocketAddress addr
    = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort())); serverSock.socket().bind(addr,getBacklog()); serverSock.configureBlocking(true); //mimic APR behavior serverSock.socket().setSoTimeout(getSocketProperties().getSoTimeout()); // Initialize thread count defaults for acceptor, poller
    初始化线程计数器
    if (acceptorThreadCount == 0) { // FIXME: Doesn't seem to work that well with multiple accept threads acceptorThreadCount = 1; } if (pollerThreadCount <= 0) { //minimum one poller thread pollerThreadCount = 1; } stopLatch = new CountDownLatch(pollerThreadCount); // Initialize SSL if needed if (isSSLEnabled()) { SSLUtil sslUtil = handler.getSslImplementation().getSSLUtil(this); sslContext = sslUtil.createSSLContext(); sslContext.init(wrap(sslUtil.getKeyManagers()), sslUtil.getTrustManagers(), null); SSLSessionContext sessionContext = sslContext.getServerSessionContext(); if (sessionContext != null) { sslUtil.configureSessionContext(sessionContext); } // Determine which cipher suites and protocols to enable enabledCiphers = sslUtil.getEnableableCiphers(sslContext); enabledProtocols = sslUtil.getEnableableProtocols(sslContext); } if (oomParachute>0) reclaimParachute(true); selectorPool.open(); }

    到这里在Catalina.load()方法中调用的server.init()已经执行完成。

    接下来将调用Catalina.start()方法来调用server.start()启动服务

    附:
    ObjectName代表一个在domain域下的一个对象名称,或者一个正则对象,这个对象可以通过正则上下文来查询

    tpOname = new ObjectName(domain + ":" +"type=ThreadPool,name=" + getName());

    分为三部分:域名,property list属性列表,属性名key

    domain:type=ProtocolHandler,port=
    提供底层网络I / O的端点必须与ProtocolHandler实现(ProtocolHandler使用BIO,需要BIO端点等)匹配
     
  • 相关阅读:
    大数据技术之Kafka是什么
    大数据技术之Hadoop 基础认识
    在eclipse中运行Mapreduce & spark
    datatstage 中一直处于Ready 状态
    Datastage run 有时候太慢 有时候performance 还Okay
    不能重复造轮子,尤其是枯燥的轮子,要造就造有趣的、好玩的轮子
    什么是好?什么是优秀?
    字面量-上集
    图片切换-vue
    数据绑定
  • 原文地址:https://www.cnblogs.com/gne-hwz/p/7729649.html
Copyright © 2020-2023  润新知