Tomcat初始化启动

一:初始化init

1.在Bootstrap里执行主函数main,初始化commonLoader,catalinaLoader,sharedLoader为URLClassLoader,他的父类加载器是系统类加载器AppClassLoader,设置当前线程类加载器为catalinaLoader,表示下面那些类的加载用我们创建的类加载器加载,而不是使用默认是系统加载器加载,这种方式经常用于开源框架里。初始化Catalina类并且反射设置他的parentClassLoader属性为当前类加载器,保存Catalina实例catalinaDaemon,bootstrap实例daemon

2.调用catalina的load方法,创建新的Digester主要解析xml文件并且进行类实例化,规则的主要抽象类Rule,他的begin,body,end,finish主要对应xml标签解析的过程。

digester.addObjectCreate("Server", "org.apache.catalina.core.StandardServer","className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server","setServer","org.apache.catalina.Server");
开始创建Digester只设置了\conf\server.xml文件所需要的属性,上面代码对应于<Server port="8005" shutdown="SHUTDOWN">,后面会大量使用这种方式进行操作。digester.parse(inputSource);解析这个文件,初始化Server为StandardServer,设置监听器Listener,他们都有同一个接口LifecycleListener,但又不同的事件发生可以处理不同情况,这个在tomcat中很重要,因为很多很多操作都需要需要依赖监听器来执行,设置Service为StandardService,它包含两个Connector和MapperListener,tomcat8版本默认使用NIO处理http链接Connector,另一个Connector负责和其他的HTTP服务器建立连接,Engine为StandardEngine也就是最初的容器,容器共有的父类ContainerBase,开始设置冠道处理pipeline,Host为StandardHost,Valve等元素。

3.启动StandardServer初始化init,自身有6个监听器VersionLoggerListener,AprLifecycleListener,JreMemoryLeakPreventionListener,GlobalResourcesLifecycleListener,ThreadLocalLeakPreventionListener,NamingContextListener,触发before_init前事件,注册JMX,通过jconsole工具可以修改查看。tomcat基本上重要的对象都注册在这里面。

4.启动StandardService初始化init,启动StandardEngine初始化init,监听器EngineConfig,创建容器开始结束线程池,启动mapperListener初始化init,启动Connector初始化init,创建CoyoteAdapter并设置协议处理器Http11NioProtocol,启动Http11NioProtocol初始化init,启动NioEndpoint初始化init,这个endpoint是协议链接Http11NioProtocol初始化时设置的,绑定网络连接服务端,设置SHARED_SELECTOR = Selector.open();启动BlockPoller线程,触发after_init事件。

public void bind() throws Exception {

        serverSock = ServerSocketChannel.open();
        socketProperties.setProperties(serverSock.socket());
        InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
        serverSock.socket().bind(addr,getAcceptCount());
        serverSock.configureBlocking(true); //mimic APR behavior

        // 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;
        }
        setStopLatch(new CountDownLatch(pollerThreadCount));

        // Initialize SSL if needed
        initialiseSsl();

        selectorPool.open();
    }
二: 启动start

5.Bootstrap.start-》Catalina.start-》StandardServer.start()每一次状态的变动都会触发那六个监听器的处理-》StandardService.start();先启动StandardEngine.start-》Cluster.start-》Realm.start,用线程池异步启动StandardHost,这里的方法都在容器共同的父类ContainerBase里,可以递归调用

 Container children[] = findChildren();
        List<Future<Void>> results = new ArrayList<>();
        for (int i = 0; i < children.length; i++) {
            results.add(startStopExecutor.submit(new StartChild(children[i])));
        }
public Void call() throws LifecycleException {
            child.start();
            return null;
        }
这个时候StandardHost的状态为new,状态监听器为HostConfig,创建开始结束线程池,给管道增加处理器ErrorReportValve,getPipeline().addValve(valve); 这时StandardHost没有子容器,开始启动管道StandardPipeline.start(),循环启动AccessLogValve,他就是这个文件localhost_access_log.xxxx.txt的来源,ErrorReportValve->StandardHostValve

 while (current != null) {
            if (current instanceof Lifecycle)
                ((Lifecycle) current).start();
            current = current.getNext();
        }
6. StandardHost设置状态setState(LifecycleState.STARTING);-》 HostConfig接收事件触发start
if (host.getDeployOnStartup())
            deployApps();
 protected void deployApps() {

        File appBase = host.getAppBaseFile();
        File configBase = host.getConfigBaseFile();
        String[] filteredAppPaths = filterAppPaths(appBase.list());
        // Deploy XML descriptors from configBase
        deployDescriptors(configBase, configBase.list());
        // Deploy WARs
        deployWARs(appBase, filteredAppPaths);
        // Deploy expanded folders
        deployDirectories(appBase, filteredAppPaths);

    }
单纯启动tomcat没有war包,异步deployDirectories五个目录webapps下docs,examples,host-manager,manager,ROOT,他们就是StandardContext,也就是host的子容器,es.submit(new DeployDirectory(this, cn, dir))
 public void run() {
            config.deployDirectory(cn, dir);
        }
解析xml文件构建 context = (Context) digester.parse(xml);文件路径"META-INF/context.xml",这个digester是host容器的,给他添加ContextConfig监听,把自己加入host子容器里,给Context添加监听MemoryLeakTrackingListener,启动context .start(); ,触发事件,创建线程池,创建自己Context的Digester contextDigester = createContextDigester();解析META-INF/context.xml,创建new ApplicationContext(this)设置ApplicationContextFacade,StandardRoot,启动StandardRoot.start();DirResourceSet.start();给Context设置类加载器WebappLoader并且添加监听NamingContextListener,启动WebappLoader.start(),
通过createClassLoader()创建WebappClassLoaderBase并启动ParallelWebappClassLoader.start(),启动配置事件"configure_start",创建专属解析WebXmlParser,这里会获取全局的web.xml和host本身默认的文件并解析,再获取context自身的"/WEB-INF/web.xml"解析,给StandardContext设置解析到的属性configureContext(WebXml webxml) ,给每个Servlet创建容器StandardWrapper,并把它添加到StandardContext的子容器中
for (ServletDef servlet : webxml.getServlets().values()) {
            Wrapper wrapper = context.createWrapper();
            context.addChild(wrapper);
        }
7.和前面类似,子容器StandardWrapper.start(),创建线程池,启动管道 StandardWrapperValve.start()。处理一些重要的配置后启动 管道 StandardContextValve .start(),启动StandardManager.start(),创建new StandardSessionIdGenerator()用来生成sessionID并启动,加载Servlet并且初始化wrapper.load();这里面设置了很多属性。最后返回HostConfig保存记录,各个文件的最后修改时间等等。 启动 StandardEngine的 管道 StandardEngineValve .start(),监听 EngineConfig,具体应用容器启动完毕

8.mapperListener.start(),把他递归设置到所有的容器中(一个StandardEngine(一个Standardhost(五个StandardContext(ROOT(default,jsp),/examples(没有子容器)/host-manager(default,jsp,HostManager,HTMLHostManager),/manager(Status,JMXProxy,default,jsp,Manager,HTMLManager),/docs(default,jsp把容器信息存进Mapper对象中

private void addListeners(Container container) {
        container.addContainerListener(this);
        container.addLifecycleListener(this);
        for (Container child : container.findChildren()) {
            addListeners(child);
        }
    }
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);
            }
        }
    }
 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);

        }

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

    }

9.启动链接connector.start(),首先启动的是用于http链接的Http11NioProtocol.start(),

public void start() throws Exception {
       endpoint.start();

        // Start async timeout thread
        asyncTimeout = new AsyncTimeout();
        Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout");
        int priority = endpoint.getThreadPriority();
        if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
            priority = Thread.NORM_PRIORITY;
        }
        timeoutThread.setPriority(priority);
        timeoutThread.setDaemon(true);
        timeoutThread.start();
    }
启动网络接收服务类NioEndpoint .start(),自定的三个SynchronizedStack用于存储请求,作为一个缓冲,创建线程池,初始化最大连接阀门LimitLatch,它是根据AbstractQueuedSynchronizer扩展的,和CountDownLatch刚好相反,前者获取是递加,后者获取是递减,默认启动两个poller,一个对外接收请求的线程Acceptor,NioEndpoint启动完毕
public void startInternal() throws Exception {

        if (!running) {
            running = true;
            paused = false;

            processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                    socketProperties.getProcessorCache());
            eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                            socketProperties.getEventCache());
            nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                    socketProperties.getBufferPool());

            // Create worker collection
            if ( getExecutor() == null ) {
                createExecutor();
            }

            initializeConnectionLatch();

            // Start poller threads
            pollers = new Poller[getPollerThreadCount()];
            for (int i=0; i<pollers.length; i++) {
                pollers[i] = new Poller();
                Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
                pollerThread.setPriority(threadPriority);
                pollerThread.setDaemon(true);
                pollerThread.start();
            }

            startAcceptorThreads();
        }
    }
继续启动检查超时链接的线程AsyncTimeout,至此一个链接 connector启动完成,另一个用于和其他http链接的AJP协议的链接和上面类似。

StandardService启动完成,StandardServer发送最后启动事件"after_start"给那六个监听器进行处理,

10.添加关闭钩子Runtime.getRuntime().addShutdownHook(shutdownHook)做一些结尾工作,StandardServer监听端口获取"SHUTDOWN"命令。

if (await) {
            await();
            stop();
        }
awaitSocket = new ServerSocket(port, 1,
                    InetAddress.getByName(address));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值