• tomcat源码分析(一)


    tomcat的启动从Bootstrap类的main方法开始。

     public static void main(String args[]) {
    
            //单例
            if (daemon == null) {
                daemon = new Bootstrap();//实例化Bootstrap对象
                try {
                    //实例化Catalina 并装载3个classloader,设置Catalina的父加载器
                    daemon.init();
                } catch (Throwable t) {
                    t.printStackTrace();
                    return;
                }
            }
    
            try {
                String command = "start";
                if (args.length > 0) {
                    command = args[args.length - 1];
                }
    
                if (command.equals("startd")) {
                    args[0] = "start";
                    daemon.load(args);
                    daemon.start();
                } else if (command.equals("stopd")) {
                    args[0] = "stop";
                    daemon.stop();
                } else if (command.equals("start")) {
                    daemon.setAwait(true);
                    daemon.load(args);//加载
                    daemon.start();//启动
                } else if (command.equals("stop")) {
                    daemon.stopServer(args);
                } else {
                    log.warn("Bootstrap: command "" + command + "" does not exist.");
                }
            } catch (Throwable t) {
                t.printStackTrace();
            }
    
        }
    /**
         * 一些初始化工作  初始化一个守护线程
         * Initialize daemon.
         */
        public void init()
            throws Exception
        {
    
            // Set Catalina path 初始化Tomcat的安装路径 homease
            setCatalinaHome();
            setCatalinaBase();
    
            initClassLoaders();//初始化变量classloader:catalinaloader、commonloader、sharedloader  三个加载器
            
            Thread.currentThread().setContextClassLoader(catalinaLoader);//设置上下文的类加载器
    
            SecurityClassLoad.securityClassLoad(catalinaLoader);
    
            // Load our startup class and call its process() method
            if (log.isDebugEnabled())
                log.debug("Loading startup class");
            Class startupClass =
                catalinaLoader.loadClass
                ("org.apache.catalina.startup.Catalina");
            Object startupInstance = startupClass.newInstance();//得到了Catalina的实例
    
            // 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);//方法名、参数类型
            method.invoke(startupInstance, paramValues);//利用反射调用Catalina的setParentClassLoader方法 设置共享扩展类装入器
    
            catalinaDaemon = startupInstance;  //赋值给Catalina的成员变量。
    }
     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);//利用反射调用Catalina的load()方法
            method.invoke(catalinaDaemon, param);
    
        }

    Catalina的load方法。主要是解析conf下的service.xml文件

        public void load() {
    
            long t1 = System.nanoTime();
    
            initDirs();//System.setPropertity("catalina.home")和catalina.home  设置系统目录
    
            // Before digester - it may be needed
            
            initNaming();//设置propertity  naming
    
            // Create and execute our Digester
            Digester digester = createStartDigester();
    
            InputSource inputSource = null;
            InputStream inputStream = null;
            File file = null;
            try {
                file = configFile();//读取con/server.xml的配置文件
                inputStream = new FileInputStream(file);
                inputSource = new InputSource("file://" + file.getAbsolutePath());
            } catch (Exception e) {
                ;
            }
            if (inputStream == null) {
                try {
                    inputStream = getClass().getClassLoader()
                        .getResourceAsStream(getConfigFile());
                    inputSource = new InputSource
                        (getClass().getClassLoader()
                         .getResource(getConfigFile()).toString());
                } catch (Exception e) {
                    ;
                }
            }
    
            // This should be included in catalina.jar
            // Alternative: don't bother with xml, just create it manually.
            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 ((inputStream == null) && (file != null)) {
                log.warn("Can't load server.xml from " + file.getAbsolutePath());
                return;
            }
    
            try {
                inputSource.setByteStream(inputStream);
                digester.push(this);
                digester.parse(inputSource);//解析service.xml配置文件
                inputStream.close();
            } catch (Exception e) {
                log.warn("Catalina.start using "
                                   + getConfigFile() + ": " , e);
                return;
            }
    
            // Stream redirection
            initStreams();
    
            // Start the new server
            if (server instanceof Lifecycle) {
                try {
                    server.initialize();
                } catch (LifecycleException e) {
                    log.error("Catalina.start", e);
                }
            }
    
            long t2 = System.nanoTime();
            if(log.isInfoEnabled())
                log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
    
        }

    tomcat从Catalina的start方法开启了。

     public void start() {
    
            if (server == null) {
                load();
            }
    
            long t1 = System.nanoTime();
            
            // Start the new server
            if (server instanceof Lifecycle) {
                try {
                    ((Lifecycle) server).start();//这里的server是StandardService,在这里启动服务。
                } catch (LifecycleException e) {
                    log.error("Catalina.start: ", e);
                }
            }
    
            long t2 = System.nanoTime();
            if(log.isInfoEnabled())
                log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
    
            try {
                // Register shutdown hook
                if (useShutdownHook) {
                    if (shutdownHook == null) {
                        shutdownHook = new CatalinaShutdownHook();
                    }
                    Runtime.getRuntime().addShutdownHook(shutdownHook);
                }
            } catch (Throwable t) {
                // This will fail on JDK 1.2. Ignoring, as Tomcat can run
                // fine without the shutdown hook.
            }
    
            if (await) {
                await();
                stop();
            }
    
        }

     启动完成后,等待客户端的链接。

     public void await() {
    
            server.await();
    
        }

    建立Socket,等待客户端的链接

    public void await() {
            // Negative values - don't wait on port - tomcat is embedded or we just don't like ports
            if( port == -2 ) {
                // undocumented yet - for embedding apps that are around, alive.
                return;
            }
            if( port==-1 ) {
                while( true ) {
                    try {
                        Thread.sleep( 10000 );
                    } catch( InterruptedException ex ) {
                    }
                    if( stopAwait ) return;
                }
            }
            
            // Set up a server socket to wait on
            ServerSocket serverSocket = null;
            try {
                serverSocket =
                    new ServerSocket(port, 1,
                                     InetAddress.getByName("localhost"));//创建了服务端Socket,绑定了localhost/127.0.0.1地址,端口号是8005
            } catch (IOException e) {
                log.error("StandardServer.await: create[" + port
                                   + "]: ", e);
                System.exit(1);
            }
    
            // Loop waiting for a connection and a valid command
            while (true) {
                //循环等待客户端连接
                // Wait for the next connection
                Socket socket = null;
                InputStream stream = null;
                try {
                    socket = serverSocket.accept();//启动完成了,在等待客户端的链接
                    socket.setSoTimeout(10 * 1000);  // Ten seconds
                    stream = socket.getInputStream();//得到socket的输入流
                } catch (AccessControlException ace) {
                    log.warn("StandardServer.accept security exception: "
                                       + ace.getMessage(), ace);
                    continue;
                } catch (IOException e) {
                    log.error("StandardServer.await: accept: ", e);
                    System.exit(1);
                }
    
                // Read a set of characters from the socket
                StringBuffer command = new StringBuffer();
                int expected = 1024; // Cut off to avoid DoS attack
                while (expected < shutdown.length()) {
                    if (random == null)
                        random = new Random();
                    expected += (random.nextInt() % 1024);
                }
                while (expected > 0) {
                    int ch = -1;
                    try {
                        ch = stream.read();//读取流中的数据
                    } catch (IOException e) {
                        log.warn("StandardServer.await: read: ", e);
                        ch = -1;
                    }
                    if (ch < 32)  // Control character or EOF terminates loop
                        break;
                    command.append((char) ch);//将数据添加到stringbuffer中
                    expected--;
                }
    
                // Close the socket now that we are done with it
                try {
                    socket.close();
                } catch (IOException e) {
                    ;
                }
    
                // Match against our command string
                boolean match = command.toString().equals(shutdown);//判断是否关闭应用
                if (match) {
                    break;
                } else
                    log.warn("StandardServer.await: Invalid command '" +
                                       command.toString() + "' received");
    
            }
    
            // Close the server socket and return
            try {
                serverSocket.close();//退出循环,关闭服务端socket
            } catch (IOException e) {
                ;
            }
    
        }
  • 相关阅读:
    Objective--C三大特性:封装,继承,多态(零碎笔记)
    零碎的知识点
    Objective--C之《文件操作》练习代码
    Objective--C的Foundation frame之NSMutableDictionary代码
    Objective--C的Foundation frame之NSMutableArray代码
    Objective--C随笔2016年8月7日
    关于OC中的委托delegate
    javascript 绝对路径工具类
    IE 弹出框处理经验
    InputStream和OutputStream 何时使用
  • 原文地址:https://www.cnblogs.com/hjy9420/p/4284908.html
Copyright © 2020-2023  润新知