Tomcat 소스 코드 분석: 4. Tomcat 초기 화

Bootstrap
org. apache. catalina. startup. bootstrap 류 는 Tomcat 의 입구 입 니 다. IDE 에서 Tomcat 를 실행 하여 디 버 깅 을 하려 면 이 종 류 를 직접 main 을 실행 하 는 방법 을 찾 을 수 있 습 니 다.
Bootstrap 의 main 방법 을 보 겠 습 니 다.
    public static void main(String args[]) {

        if (daemon == null) {
            //    Bootstrap  
            Bootstrap bootstrap = new Bootstrap();
            try {
            	 //   init  Tomcat   ,       
                bootstrap.init();
            } catch (Throwable t) {
                handleThrowable(t);
                t.printStackTrace();
                return;
            }
            daemon = bootstrap;
        } else {
            Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
        }

        try {
            String command = "start";
            // args    ,  command start
            if (args.length > 0) {
                command = args[args.length - 1];
            }

            if (command.equals("startd")) {
                args[args.length - 1] = "start";
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stopd")) {
                args[args.length - 1] = "stop";
                daemon.stop();
            } else if (command.equals("start")) {
                daemon.setAwait(true);
                // Tomcat     ,    start
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stop")) {
                daemon.stopServer(args);
            } else if (command.equals("configtest")) {
                daemon.load(args);
                if (null==daemon.getServer()) {
                    System.exit(1);
                }
                System.exit(0);
            } else {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        } catch (Throwable t) {
            // Unwrap the Exception for clearer error reporting
            if (t instanceof InvocationTargetException &&
                    t.getCause() != null) {
                t = t.getCause();
            }
            handleThrowable(t);
            t.printStackTrace();
            System.exit(1);
        }

    }

위의 코드 는 아래 와 같다.
	Bootstrap bootstrap = new Bootstrap();
	/*
	 *      
	 */
	bootstrap.init();
	daemon = bootstrap;
	daemon.setAwait(true);
    daemon.load(args);
    /*
	 *     
	 */
    daemon.start();

이 절 은 초기 화 만 말 하기 때문에 init, load 방법, start 방법 다음 절 은 분석 합 니 다.
init 방법
    public void init() throws Exception {
		
		 /*
		  *    ClassLoader
		  */
        initClassLoaders();
		
        Thread.currentThread().setContextClassLoader(catalinaLoader);

        SecurityClassLoad.securityClassLoad(catalinaLoader);

        // Load our startup class and call its process() method
        if (log.isDebugEnabled())
            log.debug("Loading startup class");
        /*         
         *   classLoader     org.apache.catalina.startup.Catalina 
         */
        Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
        Object startupInstance = startupClass.getConstructor().newInstance();

        // Set the shared extensions class loader
        if (log.isDebugEnabled())
            log.debug("Setting startup class properties");
        String methodName = "setParentClassLoader";
        Class<?> paramTypes[] = new Class[1];
        paramTypes[0] = Class.forName("java.lang.ClassLoader");
        Object paramValues[] = new Object[1];
        paramValues[0] = sharedLoader;
        Method method =
            startupInstance.getClass().getMethod(methodName, paramTypes);
        /*
         *     Catalina setParentClassLoader  
         */
        method.invoke(startupInstance, paramValues);
		
		//       
        catalinaDaemon = startupInstance;

    }

위의 init 방법 을 간단하게 정리 한 다음 에 순서대로 분석 합 니 다.
  • initClassLoaders (), ClassLoader 초기 화, lib / *. jar 불 러 오기, 모두 Tomcat 공공 자원
  • catalinaLoader. loadClass ("org. apache. catalina. startup. Catalina"), 반사 실례 화 카 탈리 나 류
  • 카 탈리 나의 setParent ClassLoader 를 반사 호출 하 는 방법
  •  		String methodName = "setParentClassLoader";
            Class<?> paramTypes[] = new Class[1];
            paramTypes[0] = Class.forName("java.lang.ClassLoader");
            Object paramValues[] = new Object[1];
            paramValues[0] = sharedLoader;
            Method method = startupInstance.getClass().getMethod(methodName, paramTypes);
            method.invoke(startupInstance, paramValues);
    

    initClassLoaders 방법
        private void initClassLoaders() {
            try {
                commonLoader = createClassLoader("common", null);
                if( commonLoader == null ) {
                    // no config file, default to this loader - we might be in a 'single' env.
                    commonLoader=this.getClass().getClassLoader();
                }
                catalinaLoader = createClassLoader("server", commonLoader);
                sharedLoader = createClassLoader("shared", commonLoader);
            } catch (Throwable t) {
                handleThrowable(t);
                log.error("Class loader creation threw exception", t);
                System.exit(1);
            }
        }
    
    

    실제로 createClassLoader 방법 을 호출 했 습 니 다.
        private ClassLoader createClassLoader(String name, ClassLoader parent)
            throws Exception {
    			
    		 /*
    		  *   conf/catalina.properties     name.loader  ,            
    		  */
            String value = CatalinaProperties.getProperty(name + ".loader");
            
            /*
             *   value  ,      parentClassLoader
             */
            if ((value == null) || (value.equals("")))
                return parent;
    		/*
    		 *  value  ${catalina.base}、${catalina.home}       
    		 */
            value = replace(value);
    
            List<Repository> repositories = new ArrayList<>();
    		 
    		 /*
    		  *   ""     ()   ,     
    		  */
            String[] repositoryPaths = getPaths(value);
    
    		 /*
    		  *   path,     Repository  
    		  */
            for (String repository : repositoryPaths) {
                // Check for a JAR URL repository
                try {
                    @SuppressWarnings("unused")
                    URL url = new URL(repository);
                    repositories.add(
                            new Repository(repository, RepositoryType.URL));
                    continue;
                } catch (MalformedURLException e) {
                    // Ignore
                    //e.printStackTrace();
                }
    
                // Local repository
                if (repository.endsWith("*.jar")) {
                    repository = repository.substring
                        (0, repository.length() - "*.jar".length());
                    repositories.add(
                            new Repository(repository, RepositoryType.GLOB));
                } else if (repository.endsWith(".jar")) {
                    repositories.add(
                            new Repository(repository, RepositoryType.JAR));
                } else {
                    repositories.add(
                            new Repository(repository, RepositoryType.DIR));
                }
            }
    			
    		 /* 
    		  *   URLClassLoader,          ,        
    		  */
            return ClassLoaderFactory.createClassLoader(repositories, parent);
        }
    

    간단하게 정리 해 볼 게 요. initClassLoaders.
  • 세 개의 CommonClassLoader, ServerClassLoader, Shared ClassLoader
  • 를 만 들 었 습 니 다.
  • conf / catalina. properties 디 렉 터 리 의 name + "loader" 경로 에 따라 ClassLoader
  • 를 만 듭 니 다.
  • 기본 적 인 상황 에서 server. loader, shared. loader 가 비어 있 기 때문에 ServerClassLoader 와 Shared ClassLoader 는 모두 CommonClassLoader
  • 입 니 다.
  • server. loader, shared. loader 가 비어 있 지 않 으 면 CommonClassLoader 는 ServerClassLoader 와 Shared ClassLoader 의 parentClassLoader
  • 입 니 다.
    그래서 init 방법 은 분석 이 끝 났 습 니 다. 주로 세 개의 ClassLoader 를 만 들 었 고 ClassLoader 를 Catalina 에 설정 하 였 습 니 다.
    이어서 load 방법 을 보 겠 습 니 다.
    load 방법
        private void load(String[] arguments)
            throws Exception {
    
            // Call the load() method
            String methodName = "load";
            Object param[];
            Class<?> paramTypes[];
            if (arguments==null || arguments.length==0) {
                paramTypes = null;
                param = null;
            } else {
                paramTypes = new Class[1];
                paramTypes[0] = arguments.getClass();
                param = new Object[1];
                param[0] = arguments;
            }
            Method method =
                catalinaDaemon.getClass().getMethod(methodName, paramTypes);
            if (log.isDebugEnabled())
                log.debug("Calling startup class " + method);
            method.invoke(catalinaDaemon, param);
        }
    

    위 에 서 는 실제로 카 탈리 나 류 의 load 방법 을 반사 적 으로 호출 했다.
    public void load() {
    
            if (loaded) {
                return;
            }
            loaded = true;
    
            long t1 = System.nanoTime();
    
            initDirs();
    
            // Before digester - it may be needed
            initNaming();
    
            //     Digester XML            
            Digester digester = createStartDigester();
    		
            InputSource inputSource = null;
            InputStream inputStream = null;
            File file = null;
            try {
                try {
                    /**
                     *   server.xml File  
                     */
                    file = configFile();
                    inputStream = new FileInputStream(file);
                    /**
                     *     JDK   SAX     server.xml
                     *     InputSource   
                     */
                    inputSource = new InputSource(file.toURI().toURL().toString());
                } catch (Exception e) {
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString("catalina.configFail", file), e);
                    }
                }
                /*
                 *   server.xml     
                 *    ClassLoader   conf/server.xml
                 */
                if (inputStream == null) {
                    try {
                        inputStream = getClass().getClassLoader()
                            .getResourceAsStream(getConfigFile());
                        inputSource = new InputSource
                            (getClass().getClassLoader()
                             .getResource(getConfigFile()).toString());
                    } catch (Exception e) {
                        if (log.isDebugEnabled()) {
                            log.debug(sm.getString("catalina.configFail",
                                    getConfigFile()), e);
                        }
                    }
                }
    
    			/*
    			 *              server.xml
    			 *    ClassLoader   server-embed.xml
    			 */
                if (inputStream == null) {
                    try {
                        inputStream = getClass().getClassLoader()
                                .getResourceAsStream("server-embed.xml");
                        inputSource = new InputSource
                        (getClass().getClassLoader()
                                .getResource("server-embed.xml").toString());
                    } catch (Exception e) {
                        if (log.isDebugEnabled()) {
                            log.debug(sm.getString("catalina.configFail",
                                    "server-embed.xml"), e);
                        }
                    }
                }
    
    			/*
    			 *        server.xml  server-embed.xml,           ,return
    			 */
                if (inputStream == null || inputSource == null) {
                    if  (file == null) {
                        log.warn(sm.getString("catalina.configFail",
                                getConfigFile() + "] or [server-embed.xml]"));
                    } else {
                        log.warn(sm.getString("catalina.configFail",
                                file.getAbsolutePath()));
                        if (file.exists() && !file.canRead()) {
                            log.warn("Permissions incorrect, read permission is not allowed on the file.");
                        }
                    }
                    return;
                }
    
                try {            
                    inputSource.setByteStream(inputStream);
                    //         Catalina,  Digester   ,     ,    
                    digester.push(this);
                    /**
                     *   server.xml            ,         
                     * 1、Server:org.apache.catalina.core.StandardServer
                     * 2、Server      :
                     *      1、org.apache.catalina.startup.VersionLoggerListener
                     *      2、org.apache.catalina.core.AprLifecycleListener
                     *      3、org.apache.catalina.core.JreMemoryLeakPreventionListener
                     *      4、org.apache.catalina.mbeans.GlobalResourcesLifecycleListener
                     *      5、org.apache.catalina.core.ThreadLocalLeakPreventionListener
                     * 3、Service:org.apache.catalina.core.StandardService
                     * 4、2 Connector,   
                     *      1、org.apache.coyote.http11.Http11NioProtocol:  HTTP  
                     *      2、org.apache.coyote.http11.Http11AprProtocol:  AJP  
                     * 5、Engine:org.apache.catalina.core.StandardEngine
                     * 6、Host:org.apache.catalina.core.StandardHost
                     */
                    digester.parse(inputSource);
                } catch (SAXParseException spe) {
                    log.warn("Catalina.start using " + getConfigFile() + ": " +
                            spe.getMessage());
                    return;
                } catch (Exception e) {
                    log.warn("Catalina.start using " + getConfigFile() + ": " , e);
                    return;
                }
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        // Ignore
                    }
                }
            }
            
            /**
             *  Server  Catalina  
             */
            getServer().setCatalina(this);
            getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
            getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
    
            // Stream redirection
            initStreams();
    
            // Start the new server
            try {
                /**
                 *   Server init  ,                  
                 */
                getServer().init();
            } catch (LifecycleException e) {
                if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
                    throw new java.lang.Error(e);
                } else {
                    log.error("Catalina.start", e);
                }
            }
    
            long t2 = System.nanoTime();
            if(log.isInfoEnabled()) {
                log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
            }
        }
    
    

    위의 내용 을 간단하게 요약 하면:
  • Digester 대상 을 만 들 고 초기 화 합 니 다. server. xml 또는 server - embed. xml 파일 을 분석 하 는 데 사 용 됩 니 다. 이 Digester 는 JDK SAX 가 분석 한 프레임 워 크
  • 입 니 다.
  • server. xml 파일 흐름 을 먼저 가 져 옵 니 다. 가 져 오지 못 하면 server - embed. xml 를 가 져 옵 니 다.모두 가 져 오지 못 하면 직접 return, 이상 정보 인쇄
  • Digester 를 사용 하여 server. xml 를 분석 하고 해당 대상 을 만 듭 니 다
  • 서버 [org. apache. catalina. core. StandardServer] 에 Catalina 정 보 를 설정 하고 서버 의 init 방법
  • 을 호출 합 니 다.
    다음은 서버 의 init 방법 을 살 펴 보 겠 습 니 다. StandardServer 류 는 LifecycleMBeanBase 를 계 속 했 기 때문에 실제 적 으로 템 플 릿 방법 인 initInternal 을 호출 했 습 니 다. 모 르 겠 습 니 다. 제 가 말 한 Lifestyle 실행 체 제 를 돌아 볼 수 있 습 니 다.
    protected void initInternal() throws LifecycleException {
    
    		/*
    		 *      initInternal,        JMX
    		 */
            super.initInternal(); 
    
    		/*
    		 *      StringCache MBeanFactory   JMX
    		 */     
            onameStringCache = register(new StringCache(), "type=StringCache");
    
            // Register the MBeanFactory
            MBeanFactory factory = new MBeanFactory();
            factory.setContainer(this);
            onameMBeanFactory = register(factory, "type=MBeanFactory");
    
            // Register the naming resources
            globalNamingResources.init();
    
            if (getCatalina() != null) {
                ClassLoader cl = getCatalina().getParentClassLoader();
                while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
                    if (cl instanceof URLClassLoader) {
                        URL[] urls = ((URLClassLoader) cl).getURLs();
                        for (URL url : urls) {
                            if (url.getProtocol().equals("file")) {
                                try {
                                    File f = new File (url.toURI());
                                    if (f.isFile() &&
                                            f.getName().endsWith(".jar")) {
                                        ExtensionValidator.addSystemResource(f);
                                    }
                                } catch (URISyntaxException e) {
                                    // Ignore
                                } catch (IOException e) {
                                    // Ignore
                                }
                            }
                        }
                    }
                    cl = cl.getParent();
                }
            }
            //    Service init  ,      
            for (int i = 0; i < services.length; i++) {
                services[i].init();
            }
        }
    

    여기 역시 Service 를 호출 하 는 init 방법 입 니 다. 이 Service 는 Standard Service 이 고 LifecycleMBeanBase 도 계승 되 었 기 때문에 템 플 릿 방법 initInternal 도 호출 되 었 습 니 다.
    protected void initInternal() throws LifecycleException {
    	
    		/*
    		 *        initInternal,        JMX
    		 */
            super.initInternal();
    		
    		/*
    		 *   Engine init  
    		 */
            if (engine != null) {
                engine.init();
            }
    
           /*
            *       server.xml Service     Executor
            *          Executor init  
            *   Executor Tomcat    JUC  Executor,
            *      Lifecycle,        ,
            *     StandardThreadExecutor
            */
            for (Executor executor : findExecutors()) {
                if (executor instanceof JmxEnabled) {
                    ((JmxEnabled) executor).setDomain(getDomain());
                }
                executor.init();
            }
    
     
            mapperListener.init();
    
            // Initialize our defined Connectors
            synchronized (connectorsLock) {
            	/*
            	 *     Connector init  
            	 *     2 Connector,1    AJP,1    Http
            	 */
                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);
                    }
                }
            }
        }
    

    간단하게 요약 하면 Standard Service 의 initInternal 방법:
  • 슈퍼. initInternal () 을 호출 하여 자신의 대상 을 JMX
  • 에 등록 합 니 다.
  • Engine 의 init 방법 을 호출 하여 Engine 초기 화
  • 사용자 정의 Executor 설정 이 있 으 면 findExecutors () 를 호출 하고 Executor 집합 을 옮 겨 다 니 며 Executor 를 호출 하 는 init 방법
  • 커 넥 터 집합 을 옮 겨 다 니 며 커 넥 터 의 init 방법 을 순서대로 호출 합 니 다
  • 이어서 우 리 는 Engine 의 init 방법, 즉 StandardEngine 의 initInternal 을 보 았 다.
    protected void initInternal() throws LifecycleException {
            // Ensure that a Realm is present before any attempt is made to start
            // one. This will create the default NullRealm if necessary.
            getRealm();
            super.initInternal();
    }
    

    간단 합 니 다. Realm 을 가 져 오고 자신 을 JMX 에 등록 하 며 부모 클래스 의 initInternal () 방법 을 호출 했 습 니 다.
    ContainerBase
        protected void initInternal() throws LifecycleException {
            BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
            /*
             *         ,  coreThread=1  maxThread=1,        
             *          start  
             */
            startStopExecutor = new ThreadPoolExecutor(
                    getStartStopThreadsInternal(),
                    getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
                    startStopQueue,
                    new StartStopThreadFactory(getName() + "-startStop-"));
            /*
             *   ThreadPoolExecutor.allowCoreThreadTimeOut   true
             *        Task  10s,    coreThread
             */
            startStopExecutor.allowCoreThreadTimeOut(true);
            super.initInternal();
        }
    

    이어서 커 넥 터 의 initInternal 방법 을 살 펴 보 겠 습 니 다. 먼저 커 넥 터 의 구조 방법 을 살 펴 보 겠 습 니 다.
    
        public Connector(String protocol) {
        	/*
        	 *   protocol HTTP/1.1,     protocolHandlerClassName = org.apache.coyote.http11.Http11NioProtocol
        	 *    AJP/1.3,     protocolHandlerClassName = org.apache.coyote.ajp.AjpAprProtocol
        	 */
            setProtocol(protocol);
            // Instantiate protocol handler
            ProtocolHandler p = null;
            try {
            	/*
            	 *        protocolHandlerClassName,       
            	 */
                Class<?> clazz = Class.forName(protocolHandlerClassName);
                p = (ProtocolHandler) clazz.getConstructor().newInstance();
            } catch (Exception e) {
                log.error(sm.getString(
                        "coyoteConnector.protocolHandlerInstantiationFailed"), e);
            } finally {
                this.protocolHandler = p;
            }
    
            if (Globals.STRICT_SERVLET_COMPLIANCE) {
                uriCharset = StandardCharsets.ISO_8859_1;
            } else {
                uriCharset = StandardCharsets.UTF_8;
            }
        }
        public void setProtocol(String protocol) {
    
            boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
                    AprLifecycleListener.getUseAprConnector();
    
            if ("HTTP/1.1".equals(protocol) || protocol == null) {
                if (aprConnector) {
                    setProtocolHandlerClassName("org.apache.coyote.http11.Http11AprProtocol");
                } else {
                    setProtocolHandlerClassName("org.apache.coyote.http11.Http11NioProtocol");
                }
            } else if ("AJP/1.3".equals(protocol)) {
                if (aprConnector) {
                    setProtocolHandlerClassName("org.apache.coyote.ajp.AjpAprProtocol");
                } else {
                    setProtocolHandlerClassName("org.apache.coyote.ajp.AjpNioProtocol");
                }
            } else {
                setProtocolHandlerClassName(protocol);
            }
        }
    	/*
    	 *      Nio2Endpoint ,           ,     
    	 * 
    	 */
        public Http11Nio2Protocol() {
            super(new Nio2Endpoint());
        }
    
        protected void initInternal() throws LifecycleException {
    		
    		/*
    		 *       JMX
    		 */
            super.initInternal();
    
            /*
             *      CoyoteAdapter   ,
             *  Request、Response  HttpServletRequest、HttpServletResponse
             */
            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()));
            }
            if (AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseOpenSSL() &&
                    protocolHandler instanceof AbstractHttp11JsseProtocol) {
                AbstractHttp11JsseProtocol<?> jsseProtocolHandler =
                        (AbstractHttp11JsseProtocol<?>) protocolHandler;
                if (jsseProtocolHandler.isSSLEnabled() &&
                        jsseProtocolHandler.getSslImplementationName() == null) {
                    // OpenSSL is compatible with the JSSE configuration, so use it if APR is available
                    jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
                }
            }
    
            try {
            	/*
            	 *      protocolHandler init  
            	 *   HTTP/1.1  ,   org.apache.coyote.http11.Http11NioProtocol
            	 */
                protocolHandler.init();
            } catch (Exception e) {
                throw new LifecycleException(
                        sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
            }
        }
    

    이 어 org. apache. coyote. http 11. Http 11 NioProtocol 의 init 방법 을 호출 하 였 으 며, 실제로 부모 클래스 org. apache. coyote. AbstractProtocol 의 init 를 호출 하 였 다.
    
        public void init() throws Exception {
            if (getLog().isInfoEnabled()) {
                getLog().info(sm.getString("abstractProtocolHandler.init", getName()));
            }
    
            if (oname == null) {
                // Component not pre-registered so register it
                oname = createObjectName();
                if (oname != null) {
                    Registry.getRegistry(null, null).registerComponent(this, oname, null);
                }
            }
    
            if (this.domain != null) {
                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));
            endpoint.setDomain(domain);
    		
    		/*         endpoint init,   Nio2Endpoint  ,
    		 *         Http11Nio2Protocol         ,    
    		 */
            endpoint.init();
        }
    

    Http11Nio2Protocol 의 init 방법 을 호출 하 는 것 도 실제 적 으로 부모 클래스 org. apache. tomcat. util. net. AbstractEndpoint 를 호출 하 는 init 입 니 다.
        public void init() throws Exception {
            if (bindOnInit) {
            	/*
            	 * bind()     ,        
            	 */
                bind();
                bindState = BindState.BOUND_ON_INIT;
            }
            if (this.domain != null) {
                // Register endpoint (as ThreadPool - historical name)
                oname = new ObjectName(domain + ":type=ThreadPool,name=\"" + getName() + "\"");
                Registry.getRegistry(null, null).registerComponent(this, oname, null);
    
                for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
                    registerJmx(sslHostConfig);
                }
            }
        }
    
    Nio2Endpoint
        public void bind() throws Exception {
    
            // Create worker collection
            /*
             *      server.xml   service         Executor,
             *      createExecutor(),     Executor   
             */
            if ( getExecutor() == null ) {
                createExecutor();
            }
            if (getExecutor() instanceof ExecutorService) {
                threadGroup = AsynchronousChannelGroup.withThreadPool((ExecutorService) getExecutor());
            }
            // AsynchronousChannelGroup currently needs exclusive access to its executor service
            if (!internalExecutor) {
                log.warn(sm.getString("endpoint.nio2.exclusiveExecutor"));
            }
    	
    		/*
    		 *       NIO   ,      
    		 */
            serverSock = AsynchronousServerSocketChannel.open(threadGroup);
            socketProperties.setProperties(serverSock);
            InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
            serverSock.bind(addr,getAcceptCount());
    
            // Initialize thread count defaults for acceptor, poller
            if (acceptorThreadCount != 1) {
                // NIO2 does not allow any form of IO concurrency
                acceptorThreadCount = 1;
            }
    
            // Initialize SSL if needed
            initialiseSsl();
        }
    

    지금까지 Tomcat 초기 화 완료.
    총결산
    간단하게 요약 하면 Tomcat 초기 화 는 주로 몇 가지 로 나 뉜 다.
  • CommonClassLoader, ServerClassLoader, Shared ClassLoader 등 3 개의 ClassLoader 를 만 듭 니 다.이 몇 개의 ClassLoader 는 기본적으로 CommonClassLoader 입 니 다. 그들 은 Tomcat 공공 Jar 를 불 러 왔 습 니 다. 예 를 들 어 lib 의 모든 jar
  • 입 니 다.
  • server. xml 설정 에 따라 해당 하 는 구성 요 소 를 만 듭 니 다. 예 를 들 어 Server, Service, Engine 등 구성 요소
  • Tomcat 초기 화 특징: 모든 구성 요 소 는 부모 구성 요소 에서 초기 화 를 호출 합 니 다. 이 를 통 해 각 구성 요 소 를 초기 화 합 니 다. HTTP 프로 토 콜 을 예 로 들 면 Nio2Endpoint 바 인 딩 포트 가 성공 하면 끝 납 니 다.

  • 그래서 Tomcat 이 초기 화 되 었 을 때 War 프로젝트 를 불 러 오지 않 았 습 니 다. start () 가 시 작 될 때 만 프로젝트 를 불 러 옵 니 다.

    좋은 웹페이지 즐겨찾기