- 浏览: 7100 次
- 性别:
- 来自: 北京
文章分类
最新评论
前面我们分析了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 协议的一个实现类,就是真正解析、处理请求的地方。接下来我们会去分析一下这个类以及由它引申出来的内容。
发表评论
-
tomcat源码分析系列之请求处理---大厨颠勺
2011-08-13 22:04 0上一回,我们已经吃上了香喷喷的狗肉,味道好是好,但作为 ... -
tomcat源码分析系列之请求处理---关门打狗
2011-08-13 17:06 1527上回我们把请求放进来了,这回我们关上门,好好修理修理它 ... -
tomcat源码分析系列之请求处理---请君入瓮
2011-08-13 14:31 1334费了九牛二虎之力 ... -
tomcat源码分析系列之启动---庐山真面目
2011-08-11 23:28 1493上回我们说到Http11Protocol,它的ini ... -
tomcat源码分析系列之启动
2011-07-31 16:36 1499对于tomcat这么一个庞大的东西,要去分析 ... -
tomcat源码分析系列之HTTP
2011-07-25 23:33 0tomcat是一个web容器,对于互联网来说,H ... -
tomcat源码分析系列之前言
2011-07-24 11:40 30我这人很懒,工作中经常使用tomcat,一直以来就 ...
相关推荐
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安装包 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-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源码分析系列文档"深入解析了Apache Tomcat服务器的内部工作原理,涵盖了一系列关键知识点,如HTTP协议、类加载机制、容器设计模式等。这些文档为理解Tomcat的运行机制提供了宝贵的资源。 【描述】...
解决tomcat8-maven-plugin-3.0-r1655215.jar阿里云同有的问题。放到路径org\apache\tomcat\maven\tomcat8-maven-plugin\3.0-r1655215\就可以了
使用这个插件,我们可以通过简单的命令如`mvn tomcat7:run`来启动本地的Tomcat服务器,并自动部署我们的应用。对于开发者来说,这意味着可以快速地进行测试和调试,无需手动管理服务器环境。 然而,"修改版"通常...
《深入解析Tomcat-Redis-Session-Manager源码》 在现代Web应用中,服务器端会话管理是一个至关重要的部分,特别是在高并发、分布式环境中。Tomcat作为最流行的Java Servlet容器,提供了丰富的功能来支持这一需求。...
tomcat6-dta-ssl-1.0.0.jar 此类文件将有助于tomcat支持ssl协议
标题中的“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-...
《深入理解Tomcat-Redis-Session-Manager:在Tomcat7和Tomcat8中的应用》 在现代Web应用程序开发中,session管理是一个至关重要的环节,它涉及到用户会话的持久化和跨请求的数据共享。传统的session管理方式在高...
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-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-...
3. **启动与停止**:在Tomcat的`bin`目录下,可以通过执行`startup.bat`启动Tomcat,执行`shutdown.bat`关闭Tomcat。也可以通过管理工具(如Windows服务)进行自动化管理。 4. **配置文件**:Tomcat的主要配置文件...
【TOMCAT源码分析(启动框架)】 Tomcat是一款广泛应用的开源Java Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,为Web应用程序提供了运行环境。本篇文章将深入探讨Tomcat的系统框架及其启动流程...
3. **源码分析**: - `apache-tomcat-6.0.35-src.zip`提供了Tomcat的完整源代码,开发者可以深入理解Tomcat的工作原理,学习Servlet容器的设计和实现,或者进行自定义扩展和调试。 - 源代码中的关键模块包括`...
- 可选地,配置`bin/startup.bat`和`bin/shutdown.bat`批处理脚本来启动和停止Tomcat服务。 **5. 运行和管理** - 使用`startup.bat`启动Tomcat服务器,`shutdown.bat`关闭它。 - 默认情况下,Tomcat启动后,你可以...
支持tomcat8的sessionManager,kuanrf-tomcat-redis-session-manager-1.0.jar
tomcat6-maven-plugin-2.1插件包
apache-tomcat-8.5.20.tar.gz源码包和context.xml文件,这套配置是我自己亲测可用的。。另外我用的redis4这个版本。注意:如果你使用的TOMCAT其他版本。例如tomcat6或者7这套JAR包可能不可用,tomcat8.0没有测试。...