Tomcat系列4-内嵌Tomcat

我们在前边几篇文章分析了tomcat的初始化和启动流程,现在看下springboot等内嵌的tomcat是怎么启动的。

1.Tomcat7RunnerCli

内嵌tomcat的入口是在Tomcat7RunnerCli,看下它的main方法。

public static void main( String[] args )
        throws Exception
    {
        CommandLineParser parser = new GnuParser();
        CommandLine line = null;
        try
        {
            line = parser.parse( Tomcat7RunnerCli.options, args );
        }
        catch ( ParseException e )
        {
          ...//省略部分代码
        }
     ...//省略部分代码
        Tomcat7Runner tomcat7Runner = new Tomcat7Runner();

        tomcat7Runner.runtimeProperties = buildStandaloneProperties();

        if ( line.hasOption( serverXmlPath.getOpt() ) )
        {
            tomcat7Runner.serverXmlPath = line.getOptionValue( serverXmlPath.getOpt() );
        }

        String port = tomcat7Runner.runtimeProperties.getProperty( Tomcat7Runner.HTTP_PORT_KEY );
        if ( port != null)
        {
            tomcat7Runner.httpPort = Integer.parseInt( port );
        }

        // cli win for the port
        if ( line.hasOption( httpPort.getOpt() ) )
        {
            tomcat7Runner.httpPort = Integer.parseInt( line.getOptionValue( httpPort.getOpt() ) );
        }

        if ( line.hasOption( httpsPort.getOpt() ) )
        {
            tomcat7Runner.httpsPort = Integer.parseInt( line.getOptionValue( httpsPort.getOpt() ) );
        }
        if ( line.hasOption( ajpPort.getOpt() ) )
        {
            tomcat7Runner.ajpPort = Integer.parseInt( line.getOptionValue( ajpPort.getOpt() ) );
        }
        if ( line.hasOption( resetExtract.getOpt() ) )
        {
            tomcat7Runner.resetExtract = true;
        }
        if ( line.hasOption( debug.getOpt() ) )
        {
            tomcat7Runner.debug = true;
        }

        if ( line.hasOption( httpProtocol.getOpt() ) )
        {
            tomcat7Runner.httpProtocol = line.getOptionValue( httpProtocol.getOpt() );
        }

         ...//省略部分代码
        // here we go
        tomcat7Runner.run();
    }

其中创建了Tomcat7Runner对象,然后设置了属性,调用了run方法。

2.Tomcat7Runner

 public void run()
        throws Exception
    {

            ...//省略部分代码

        // create tomcat various paths
      //这里创建了我们熟悉tomcat的4个目录
        new File( extractDirectory, "conf" ).mkdirs();
        new File( extractDirectory, "logs" ).mkdirs();
        new File( extractDirectory, "webapps" ).mkdirs();
        new File( extractDirectory, "work" ).mkdirs();
        File tmpDir = new File( extractDirectory, "temp" );
        tmpDir.mkdirs();

        ...//省略部分代码
        // start with a server.xml
        //如果有server.xml文件,直接创建Catalina对象,调用start方法
        if ( serverXmlPath != null || useServerXml() )
        {
            container = new Catalina();
            container.setUseNaming( this.enableNaming() );
            if ( serverXmlPath != null && new File( serverXmlPath ).exists() )
            {
                container.setConfig( serverXmlPath );
            }
            else
            {
                container.setConfig( new File( extractDirectory, "conf/server.xml" ).getAbsolutePath() );
            }
            container.start();
        }
        else
        {
                //如果没有server.xml文件,直接创建Tomcat对象
            tomcat = new Tomcat()
            {
                public Context addWebapp( Host host, String url, String name, String path )
                {
					//创建Context对象
                    Context ctx = new StandardContext();
                    ctx.setName( name );
                    ctx.setPath( url );
                    ctx.setDocBase( path );

                    ContextConfig ctxCfg = new ContextConfig();
                    ctx.addLifecycleListener( ctxCfg );

                    ctxCfg.setDefaultWebXml( new File( extractDirectory, "conf/web.xml" ).getAbsolutePath() );

                    if ( host == null )
                    {
                    	//创建Host对象
                        getHost().addChild( ctx );
                    }
                    else
                    {
                        host.addChild( ctx );
                    }

                    return ctx;
                }
            };

            if ( this.enableNaming() )
            {
                System.setProperty( "catalina.useNaming", "true" );
                tomcat.enableNaming();
            }
			//这里会一级级的找父容器,父容器没创建就创建
            tomcat.getHost().setAppBase( new File( extractDirectory, "webapps" ).getAbsolutePath() );

            String connectorHttpProtocol = runtimeProperties.getProperty( HTTP_PROTOCOL_KEY );

            if ( httpProtocol != null && httpProtocol.trim().length() > 0 )
            {
                connectorHttpProtocol = httpProtocol;
            }

            debugMessage( "use connectorHttpProtocol:" + connectorHttpProtocol );
					//创建Connector对象
            if ( httpPort > 0 )
            {
                Connector connector = new Connector( connectorHttpProtocol );
                connector.setPort( httpPort );

                if ( httpsPort > 0 )
                {
                    connector.setRedirectPort( httpsPort );
                }
                connector.setURIEncoding( uriEncoding );

                tomcat.getService().addConnector( connector );

                tomcat.setConnector( connector );
            }

            // add a default acces log valve
            AccessLogValve alv = new AccessLogValve();
            alv.setDirectory( new File( extractDirectory, "logs" ).getAbsolutePath() );
            alv.setPattern( runtimeProperties.getProperty( Tomcat7Runner.ACCESS_LOG_VALVE_FORMAT_KEY ) );
            tomcat.getHost().getPipeline().addValve( alv );

            // create https connector
            if ( httpsPort > 0 )
            {
                Connector httpsConnector = new Connector( connectorHttpProtocol );
                httpsConnector.setPort( httpsPort );
                httpsConnector.setSecure( true );
                httpsConnector.setProperty( "SSLEnabled", "true" );
                httpsConnector.setProperty( "sslProtocol", "TLS" );
                httpsConnector.setURIEncoding( uriEncoding );

                String keystoreFile = System.getProperty( "javax.net.ssl.keyStore" );
                String keystorePass = System.getProperty( "javax.net.ssl.keyStorePassword" );
                String keystoreType = System.getProperty( "javax.net.ssl.keyStoreType", "jks" );

                if ( keystoreFile != null )
                {
                    httpsConnector.setAttribute( "keystoreFile", keystoreFile );
                }
                if ( keystorePass != null )
                {
                    httpsConnector.setAttribute( "keystorePass", keystorePass );
                }
                httpsConnector.setAttribute( "keystoreType", keystoreType );

                String truststoreFile = System.getProperty( "javax.net.ssl.trustStore" );
                String truststorePass = System.getProperty( "javax.net.ssl.trustStorePassword" );
                String truststoreType = System.getProperty( "javax.net.ssl.trustStoreType", "jks" );
                if ( truststoreFile != null )
                {
                    httpsConnector.setAttribute( "truststoreFile", truststoreFile );
                }
                if ( truststorePass != null )
                {
                    httpsConnector.setAttribute( "truststorePass", truststorePass );
                }
                httpsConnector.setAttribute( "truststoreType", truststoreType );

                httpsConnector.setAttribute( "clientAuth", clientAuth );
                httpsConnector.setAttribute( "keyAlias", keyAlias );

                tomcat.getService().addConnector( httpsConnector );

                if ( httpPort <= 0 )
                {
                    tomcat.setConnector( httpsConnector );
                }
            }

            // create ajp connector
            if ( ajpPort > 0 )
            {
                Connector ajpConnector = new Connector( "org.apache.coyote.ajp.AjpProtocol" );
                ajpConnector.setPort( ajpPort );
                ajpConnector.setURIEncoding( uriEncoding );
                tomcat.getService().addConnector( ajpConnector );
            }

            // add webapps
            for ( Map.Entry<String, String> entry : this.webappWarPerContext.entrySet() )
            {
                String baseDir = null;
                Context context = null;
                if ( entry.getKey().equals( "/" ) )
                {
                    baseDir = new File( extractDirectory, "webapps/ROOT.war" ).getAbsolutePath();
                    context = tomcat.addWebapp( "", baseDir );
                }
                else
                {
                    baseDir = new File( extractDirectory, "webapps/" + entry.getValue() ).getAbsolutePath();
                    context = tomcat.addWebapp( entry.getKey(), baseDir );
                }

                URL contextFileUrl = getContextXml( baseDir );
                if ( contextFileUrl != null )
                {
                    context.setConfigFile( contextFileUrl );
                }
            }

            if ( codeSourceWar != null )
            {
                String baseDir = new File( extractDirectory, "webapps/" + codeSourceWar.getName() ).getAbsolutePath();
                Context context = tomcat.addWebapp( codeSourceContextPath, baseDir );
                URL contextFileUrl = getContextXml( baseDir );
                if ( contextFileUrl != null )
                {
                    context.setConfigFile( contextFileUrl );
                }
            }
			//调用tomcat方法
            tomcat.start();

            Runtime.getRuntime().addShutdownHook( new TomcatShutdownHook() );

        }

        waitIndefinitely();

    }

3.Tomcat

    public void start() throws LifecycleException {
        getServer();
        getConnector();
        server.start();
    }

这里就很熟悉了,调用了前面讲过的start方法。

4.总结

内嵌tomcat本质上最后也是调用了tomcat自身启动的api。只是在前面进行了很多初始化的、创建目录的其他操作。还有个有意思的地方就是如果有server.xml文件,直接创建Catalina对象,然后调用start方法,这也是我们前面几篇文章分析的启动方式。如果没有这个文件,就创建tomcat各容器,然后启动,这时候tomcat也没有应用在其中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值