`
yayagepei
  • 浏览: 7100 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

tomcat源码分析系列之启动---暗度陈仓

 
阅读更多

    前面我们分析了tomcat是如何启动的,但我们好像并没有看到我们期待发生的诸如在什么地方启动了服务,什么地方启动了监听,好像只是做了些加载资源、设置环境变量等鸡毛蒜皮的事,这到底是怎么回事?我们回顾一下前面提到的一个函数:解析server.xml的函数

 protected Digester createStartDigester() {
        long t1=System.currentTimeMillis();
        // Initialize the digester
        Digester digester = new Digester();
        digester.setValidating(false);
        digester.setRulesValidation(true);
        HashMap<Class<?>, List<String>> fakeAttributes =
            new HashMap<Class<?>, List<String>>();
        ArrayList<String> attrs = new ArrayList<String>();
        attrs.add("className");
        fakeAttributes.put(Object.class, attrs);
        digester.setFakeAttributes(fakeAttributes);
        digester.setClassLoader(StandardServer.class.getClassLoader());

        // Configure the actions we will be using
        digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");

        digester.addObjectCreate("Server/GlobalNamingResources",
                                 "org.apache.catalina.deploy.NamingResources");
        digester.addSetProperties("Server/GlobalNamingResources");
        digester.addSetNext("Server/GlobalNamingResources",
                            "setGlobalNamingResources",
                            "org.apache.catalina.deploy.NamingResources");

        digester.addObjectCreate("Server/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Listener");
        digester.addSetNext("Server/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");

        digester.addObjectCreate("Server/Service",
                                 "org.apache.catalina.core.StandardService",
                                 "className");
        digester.addSetProperties("Server/Service");
        digester.addSetNext("Server/Service",
                            "addService",
                            "org.apache.catalina.Service");

        digester.addObjectCreate("Server/Service/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Service/Listener");
        digester.addSetNext("Server/Service/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");

        //Executor
        digester.addObjectCreate("Server/Service/Executor",
                         "org.apache.catalina.core.StandardThreadExecutor",
                         "className");
        digester.addSetProperties("Server/Service/Executor");

        digester.addSetNext("Server/Service/Executor",
                            "addExecutor",
                            "org.apache.catalina.Executor");


        digester.addRule("Server/Service/Connector",
                         new ConnectorCreateRule());
        digester.addRule("Server/Service/Connector",
                         new SetAllPropertiesRule(new String[]{"executor"}));
        digester.addSetNext("Server/Service/Connector",
                            "addConnector",
                            "org.apache.catalina.connector.Connector");


        digester.addObjectCreate("Server/Service/Connector/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Service/Connector/Listener");
        digester.addSetNext("Server/Service/Connector/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");

        // Add RuleSets for nested elements
        digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
        digester.addRuleSet(new EngineRuleSet("Server/Service/"));
        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
        digester.addRuleSet(new ClusterRuleSet("Server/Service/Engine/Host/Cluster/"));
        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));

        // When the 'engine' is found, set the parentClassLoader.
        digester.addRule("Server/Service/Engine",
                         new SetParentClassLoaderRule(parentClassLoader));
        digester.addRuleSet(new ClusterRuleSet("Server/Service/Engine/Cluster/"));

        long t2=System.currentTimeMillis();
        if (log.isDebugEnabled())
            log.debug("Digester for server.xml created " + ( t2-t1 ));
        return (digester);

    }

    在前面我们并没有详细去看这个函数,只是知道它解析了server.xml文件,现在我们深入这个方法看一下。这个方法里反复调用了下面三个方法:

addObjectCreate,addSetProperties,addSetNext

 我们看一下这三个方法到底做了些什么。

/**
     * Add an "object create" rule for the specified parameters.
     *添加一个“创建对象”的规则
     * @param pattern Element matching pattern 匹配模式
     * @param className Default Java class name to be created 默认要实例的java类
     * @param attributeName Attribute name that optionally overrides
     *  the default Java class name to be created
     * @see ObjectCreateRule 
     */
    public void addObjectCreate(String pattern, String className,
                                String attributeName) {

        addRule(pattern,
                new ObjectCreateRule(className, attributeName));

    }

 这个方法就是定义了一个创建对象的规则:匹配的规则(遇到server.xml里什么样的表达式),默认要实例化的类名,默认的一个属性名(xml配置属性)。就是说如果server.xml里遇到跟规则相匹配的项,如果没有设定指定attributeName属性的值,则使用这里设置的默认的类。

/**
     * Add a "set properties" rule for the specified parameters.
     *
     * @param pattern Element matching pattern
     * @see SetPropertiesRule
     */
    public void addSetProperties(String pattern) {

        addRule(pattern,
                new SetPropertiesRule());

    }

 定义了一个调用setter方法的规则:把这个值设置给谁

/**
     * Add a "set next" rule for the specified parameters.
     *
     * @param pattern Element matching pattern
     * @param methodName Method name to call on the parent element
     * @param paramType Java class name of the expected parameter type
     *  (if you wish to use a primitive type, specify the corresponding
     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
     *  for a <code>boolean</code> parameter)
     * @see SetNextRule
     */
    public void addSetNext(String pattern, String methodName,
                           String paramType) {

        addRule(pattern,
                new SetNextRule(methodName, paramType));

    }

 这个方法很关键,第一个参数依旧是匹配的规则,第二个参数是要调用父元素的方法名,第三个参数是方法需要的参数类型。看到这个我们或许明白了点。我们再回头看下前面提到的方法:

digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");

 上面这几句话就是说,遇到Server,如果没有设置className属性,就实例化org.apache.catalina.core.StandardServer的一个对象(如果设置了className,就使用设置的Class),把这个对象赋值给Catalina的server属性(调用server的setter方法)。

 

digester.addObjectCreate("Server/GlobalNamingResources",
                                 "org.apache.catalina.deploy.NamingResources");
        digester.addSetProperties("Server/GlobalNamingResources");
        digester.addSetNext("Server/GlobalNamingResources",
                            "setGlobalNamingResources",
                            "org.apache.catalina.deploy.NamingResources");

匹配到server的下级节点: GlobalNamingResources,就创建一个org.apache.catalina.deploy.NamingResources的实例,调用server的setGlobalNamingResources方法。其他的类似,再次不一一赘述。但有一个方法我们不能漏掉:StandardServer下的addService方法(StandardService下的addExecutor方法、StandardServic下的addConnector方法与它类似):

/**
     * Add a new Service to the set of defined Services.
     *
     * @param service The Service to be added
     */
    @Override
    public void addService(Service service) {

        service.setServer(this);

        synchronized (services) {
            Service results[] = new Service[services.length + 1];
            System.arraycopy(services, 0, results, 0, services.length);
            results[services.length] = service;
            services = results;

            if (getState().isAvailable()) {
                try {
                    service.start();
                } catch (LifecycleException e) {
                    // Ignore
                }
            }

            // Report this property change to interested listeners
            support.firePropertyChange("service", null, service);
        }

    }

 这个方法除了调用setter外,还做了一件重要的事情: service.start();这个start方法属于Lifecycle接口,在LifecycleBase里实现,

@Override
    public final synchronized void init() throws LifecycleException {
        if (!state.equals(LifecycleState.NEW)) {
            invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
        }
        setStateInternal(LifecycleState.INITIALIZING, null, false);

        try {
            initInternal();
        } catch (LifecycleException e) {
            setStateInternal(LifecycleState.FAILED, null, false);
            throw e;
        }

        setStateInternal(LifecycleState.INITIALIZED, null, false);
    }
    
    
    protected abstract void initInternal() throws LifecycleException;
    
    /**
     * {@inheritDoc}
     */
    @Override
    public final synchronized void start() throws LifecycleException {
        
        if (LifecycleState.STARTING_PREP.equals(state) ||
                LifecycleState.STARTING.equals(state) ||
                LifecycleState.STARTED.equals(state)) {
            
            if (log.isDebugEnabled()) {
                Exception e = new LifecycleException();
                log.debug(sm.getString("lifecycleBase.alreadyStarted",
                        toString()), e);
            } else if (log.isInfoEnabled()) {
                log.info(sm.getString("lifecycleBase.alreadyStarted",
                        toString()));
            }
            
            return;
        }
        
        if (state.equals(LifecycleState.NEW)) {
            init();
        } else if (!state.equals(LifecycleState.INITIALIZED) &&
                !state.equals(LifecycleState.STOPPED)) {
            invalidTransition(Lifecycle.BEFORE_START_EVENT);
        }

        setStateInternal(LifecycleState.STARTING_PREP, null, false);

        try {
            startInternal();
        } catch (LifecycleException e) {
            setStateInternal(LifecycleState.FAILED, null, false);
            throw e;
        }

        if (state.equals(LifecycleState.FAILED) ||
                state.equals(LifecycleState.MUST_STOP)) {
            stop();
        } else {
            // Shouldn't be necessary but acts as a check that sub-classes are
            // doing what they are supposed to.
            if (!state.equals(LifecycleState.STARTING)) {
                invalidTransition(Lifecycle.AFTER_START_EVENT);
            }
            
            setStateInternal(LifecycleState.STARTED, null, false);
        }
    }


    /**
     * Sub-classes must ensure that the state is changed to
     * {@link LifecycleState#STARTING} during the execution of this method.
     * Changing state will trigger the {@link Lifecycle#START_EVENT} event.
     * 
     * If a component fails to start it may either throw a
     * {@link LifecycleException} which will cause it's parent to fail to start
     * or it can place itself in the error state in which case {@link #stop()}
     * will be called on the failed component but the parent component will
     * continue to start normally.
     * 
     * @throws LifecycleException
     */
    protected abstract void startInternal() throws LifecycleException;


  LifecycleBase的start方法是一个典型的Template Method 模式。在分析这个之前,我先看一下类关系图:

LifecycleBase最后又调用个实现类里的initInternal和startInternal方法,所以我们只需要看具体类里的这两个方法就可以了。

StandardService里的initInternal

/**
     * Invoke a pre-startup initialization. This is used to allow connectors
     * to bind to restricted ports under Unix operating environments.
     */
    @Override
    protected void initInternal() throws LifecycleException {

        super.initInternal();
        
        if (container != null) {
            container.init();
        }

        // Initialize any Executors
        for (Executor executor : findExecutors()) {
            if (executor instanceof LifecycleMBeanBase) {
                ((LifecycleMBeanBase) executor).setDomain(getDomain());
            }
            executor.init();
        }

        // Initialize our defined Connectors
        synchronized (connectors) {
            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);
                }
            }
        }
    }
    

 startInternal

/**
     * Start nested components ({@link Executor}s, {@link Connector}s and
     * {@link Container}s) and implement the requirements of
     * {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents this component from being used
     */
    @Override
    protected void startInternal() throws LifecycleException {

        if(log.isInfoEnabled())
            log.info(sm.getString("standardService.start.name", this.name));
        setState(LifecycleState.STARTING);

        // Start our defined Container first
        if (container != null) {
            synchronized (container) {
                container.start();
            }
        }

        synchronized (executors) {
            for (Executor executor: executors) {
                executor.start();
            }
        }

        // Start our defined Connectors second
        synchronized (connectors) {
            for (Connector connector: connectors) {
                try {
                    // If it has already failed, don't try and start it
                    if (connector.getState() != LifecycleState.FAILED) {
                        connector.start();
                    }
                } catch (Exception e) {
                    log.error(sm.getString(
                            "standardService.connector.startFailed",
                            connector), e);
                }
            }
        }
    }

 init和start的顺序都是这样的:Catalina->Server->Service.Service里启动了Container、Executor、Connector

ContainerBase的startInternal方法:

/**
     * Start this component and implement the requirements
     * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents this component from being used
     */
    @Override
    protected synchronized void startInternal() throws LifecycleException {

        // Start our subordinate components, if any
        if ((loader != null) && (loader instanceof Lifecycle))
            ((Lifecycle) loader).start();
        logger = null;
        getLogger();
        if ((logger != null) && (logger instanceof Lifecycle))
            ((Lifecycle) logger).start();
        if ((manager != null) && (manager instanceof Lifecycle))
            ((Lifecycle) manager).start();
        if ((cluster != null) && (cluster instanceof Lifecycle))
            ((Lifecycle) cluster).start();
        if ((realm != null) && (realm instanceof Lifecycle))
            ((Lifecycle) realm).start();
        if ((resources != null) && (resources instanceof Lifecycle))
            ((Lifecycle) resources).start();

        // Start our child containers, if any
        Container children[] = findChildren();
        for (int i = 0; i < children.length; i++) {
            children[i].start();
        }

        // Start the Valves in our pipeline (including the basic), if any
        if (pipeline instanceof Lifecycle)
            ((Lifecycle) pipeline).start();


        setState(LifecycleState.STARTING);

        // Start our thread
        threadStart();

    }

  Conector的initInternal和startInternal方法

 @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());

        try {
            protocolHandler.init();
        } catch (Exception e) {
            throw new LifecycleException
                (sm.getString
                 ("coyoteConnector.protocolHandlerInitializationFailed"), e);
        }

        // Initialize mapper listener
        mapperListener.init();
    }


    /**
     * Begin processing requests via this Connector.
     *
     * @exception LifecycleException if a fatal startup error occurs
     */
    @Override
    protected void startInternal() throws LifecycleException {

        // Validate settings before starting
        if (getPort() < 1) {
            throw new LifecycleException(sm.getString(
                    "coyoteConnector.invalidPort", Integer.valueOf(getPort())));
        }

        setState(LifecycleState.STARTING);

        try {
            protocolHandler.start();
        } catch (Exception e) {
            String errPrefix = "";
            if(this.service != null) {
                errPrefix += "service.getName(): \"" + this.service.getName() + "\"; ";
            }

            throw new LifecycleException
                (errPrefix + " " + sm.getString
                 ("coyoteConnector.protocolHandlerStartFailed"), e);
        }

        mapperListener.start();
    }

 从上面的代码我们可以看出,父容器在启动时会把下面所有的组件都启动起来。Connector在启动的时候调用了protocolHandler.start();这个protocolHandler会是什么呢?它是Http11Protocol的实例,这个类就是http1.1 协议的一个实现类,就是真正解析、处理请求的地方。接下来我们会去分析一下这个类以及由它引申出来的内容。

 

  • 大小: 169.9 KB
分享到:
评论

相关推荐

    tomcat-redis-session-manager-1.2-tomcat-7-java-7

    tomcat-redis-session-manager-1.2-tomcat-7-java-7tomcat-redis-session-manager-1.2-tomcat-7-java-7tomcat-redis-session-manager-1.2-tomcat-7-java-7tomcat-redis-session-manager-1.2-tomcat-7-java-7tomcat-...

    apache-tomcat-8.5.78-windows-x64安装包-kaic.rar

    apache-tomcat-8.5.78-windows-x64安装包 apache-tomcat-8.5.78-windows-x64安装包 apache-tomcat-8.5.78-windows-x64安装包 apache-tomcat-8.5.78-windows-x64安装包 apache-tomcat-8.5.78-windows-x64安装包 ...

    apache-tomcat-9.0.45-windows-x64

    apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-...

    tomcat 源码分析系列文档

    【标题】"Tomcat源码分析系列文档"深入解析了Apache Tomcat服务器的内部工作原理,涵盖了一系列关键知识点,如HTTP协议、类加载机制、容器设计模式等。这些文档为理解Tomcat的运行机制提供了宝贵的资源。 【描述】...

    tomcat8-maven-plugin-3.0-r1655215.jar

    解决tomcat8-maven-plugin-3.0-r1655215.jar阿里云同有的问题。放到路径org\apache\tomcat\maven\tomcat8-maven-plugin\3.0-r1655215\就可以了

    tomcat7-maven-plugin-2.2.jar

    使用这个插件,我们可以通过简单的命令如`mvn tomcat7:run`来启动本地的Tomcat服务器,并自动部署我们的应用。对于开发者来说,这意味着可以快速地进行测试和调试,无需手动管理服务器环境。 然而,"修改版"通常...

    tomcat-redis-session-manager源码

    《深入解析Tomcat-Redis-Session-Manager源码》 在现代Web应用中,服务器端会话管理是一个至关重要的部分,特别是在高并发、分布式环境中。Tomcat作为最流行的Java Servlet容器,提供了丰富的功能来支持这一需求。...

    tomcat6-dta-ssl-1.0.0.jar

    tomcat6-dta-ssl-1.0.0.jar 此类文件将有助于tomcat支持ssl协议

    Tomcat8亲测可用 tomcat-redis-session-manager的jar包

    标题中的“Tomcat8亲测可用 tomcat-redis-session-manager的jar包”指的是一个专为Tomcat8设计的,用于管理session的扩展组件。这个组件实现了将Tomcat应用服务器中的用户session数据存储到Redis分布式缓存系统中,...

    开发工具 apache-tomcat-8.0.41-windows-x86

    开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-...

    tomcat-redis-session-manager的jar包-包含Tomcat7和Tomcat8

    《深入理解Tomcat-Redis-Session-Manager:在Tomcat7和Tomcat8中的应用》 在现代Web应用程序开发中,session管理是一个至关重要的环节,它涉及到用户会话的持久化和跨请求的数据共享。传统的session管理方式在高...

    tomcat-redis-session-manager-master-2.0.0

    1.添加 redis session 集群依赖的jar包到 tomcat/lib 目录下 tomcat-redis-session-manager-2.0.0.jar jedis-2.5.2.jar commons-pool2-2.2.jar 2.修改 conf 目录下的 context.xml 文件 ...

    apache-tomcat-9.0.45-src

    apache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-...

    apache-tomcat-11.0.0-M17-windows-x64.zip

    3. **启动与停止**:在Tomcat的`bin`目录下,可以通过执行`startup.bat`启动Tomcat,执行`shutdown.bat`关闭Tomcat。也可以通过管理工具(如Windows服务)进行自动化管理。 4. **配置文件**:Tomcat的主要配置文件...

    TOMCAT源码分析(启动框架)

    【TOMCAT源码分析(启动框架)】 Tomcat是一款广泛应用的开源Java Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,为Web应用程序提供了运行环境。本篇文章将深入探讨Tomcat的系统框架及其启动流程...

    apache-tomcat-6.0.35和apache-tomcat-6.0.35 src

    3. **源码分析**: - `apache-tomcat-6.0.35-src.zip`提供了Tomcat的完整源代码,开发者可以深入理解Tomcat的工作原理,学习Servlet容器的设计和实现,或者进行自定义扩展和调试。 - 源代码中的关键模块包括`...

    apache-tomcat-8.5.99-windows-x64.zip

    - 可选地,配置`bin/startup.bat`和`bin/shutdown.bat`批处理脚本来启动和停止Tomcat服务。 **5. 运行和管理** - 使用`startup.bat`启动Tomcat服务器,`shutdown.bat`关闭它。 - 默认情况下,Tomcat启动后,你可以...

    支持tomcat8的sessionManager,kuanrf-tomcat-redis-session-manager-1.0.jar

    支持tomcat8的sessionManager,kuanrf-tomcat-redis-session-manager-1.0.jar

    tomcat6-maven-plugin-2.1

    tomcat6-maven-plugin-2.1插件包

    tomcat8.5.20-redis-session共享-JAR包大全

    apache-tomcat-8.5.20.tar.gz源码包和context.xml文件,这套配置是我自己亲测可用的。。另外我用的redis4这个版本。注意:如果你使用的TOMCAT其他版本。例如tomcat6或者7这套JAR包可能不可用,tomcat8.0没有测试。...

Global site tag (gtag.js) - Google Analytics