程序小寨

Tomcat架构介绍及配置分析

2018-12-18  本文已影响3人  梦中一点心雨

在之前的项目中,需要对项目做集群,由于项目对系统的并发要求不大,所以就采取Session共享方式实现,虽然根据在网上找的资料完成了集群,但是对Tomcat的Session的共享的底层原理一直比较好奇,正好借此机会,调试一下Tomcat源码,略作分析。

1. conf/配置文件说明

1.1 catalina.properties

Tomcat的catalina.properties文件位于%CATALINA_HOME%/conf/目录下面,该文件主要配置tomcat的安全设置、类加载设置、不需要扫描的类设置、字符缓存设置四大块。

总结: Tomcat可以通过catalina.properties的server和shared,为webapp提供公用类库。使一些公用的、不需要与webapp放在一起的设置信息单独保存,在更新webapp的war的时候无需更改webapp的设置。

1.2 catalina.policy

包含由Java Security Manager实现的安全策略声明,它替换了安装java时带有的java.policy文件。这个文件用来防止欺骗代码或JSP执行带有像System.exit(0)这样可能影响容器的破坏性代码,只有当Tomcat用-security命令行参数启动时这个文件才会被使用。

1.3 context.xml

这个通用context.xml可被所有的web应用程序使用,这个文件默认地可以设置到何处访问各web应用程序中的web.xml文件。context.xml文件的作用和server.xml中<Context>标签作用相同。在tomcat5.5之后,对Context的配置不推荐在server.xml中进行配置,而是在/conf/context.xml中进行独立的配置。因为server.xml是不可动态重加载的资源,服务器一旦启动了以后,要修改这个文件,就得重启服务器才能重新加载。而context.xml文件则不然,tomcat服务器会定时去扫描这个文件。一旦发现文件被修改(时间戳改变了),就会自动重新加载这个文件,而不需要重启服务器。

默认的context.xml如下:

<Context>
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
</Context>

以下给出一个JNDI数据源的配置:

<Resource name="jdbc/mysql"
        auth="Container"
        type="com.alibaba.druid.pool.DruidDataSource"
        maxActive="100"
        maxIdle="30"
        maxWait="10000"
        username="root"
        password="root"
        driverClassName="com.mysql.jdbc.Driver"
        url="jdbc:mysql://localhost:3306/test"
/>

context.xml的作用范围

1.4 server.xml

tomcat的主要配置文件,解析器用这个文件在启动时根据规范创建容器。

默认的server.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
  <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>

Server是顶级元素,代表一个Tomcat实例。可以包含一个或多个Service,每个Service都有自己的Engines和Connectors。

Server元素

Listeners元素

Server可以包含多个监听器。一个监听器监听指定事件,并对其作出响应。

GlobalResourcesLifecycleListener作用于全局资源,保证JNDI对资源的可达性,比如数据库。

<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

GlobalNamingResources元素全局命名资源

GlobalNamingResources元素定义了JNDI(Java命名和目录接口)资源,其允许Java软件客户端通过名称搜寻和查找数据。默认配置定义了一个名称为UserDatabase的JNDI,通过“conf/tomcat-users.xml”得到一个用于用户授权的内存数据库。

<GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

也可以定义其他全句话JNDI资源来实现连接池,比如MySQL数据库。

Services元素

一个Service可以连接一个或多个Connectors到一个引擎。默认配置定义了一个名为“Catalina”的Service,连接了两个Connectors:HTTP和AJP到当前的引擎。

<Service name="Catalina">
   <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
   <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
   <Engine name="Catalina" defaultHost="localhost">
     <Realm className="org.apache.catalina.realm.LockOutRealm">
       <Realm className="org.apache.catalina.realm.UserDatabaseRealm"               
              resourceName="UserDatabase"/>
     </Realm>
     <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">
       <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
              prefix="localhost_access_log" suffix=".txt"
              pattern="%h %l %u %t &quot;%r&quot; %s %b" />
     </Host>
   </Engine>
</Service>

Connectors元素

一个Connector关联一个TCP端口,负责处理Service与客户端之间的交互。默认配置定义了两个Connectors。

容器

包含了Engine、Host、Context和Cluster的Tomcat称为容器。最高级的是Engine,最底层的是Context。某些组件,比如Realm和Value,也可以放在容器中。

Engine引擎

引擎是容器中最高级别的部分。可以包含一个或多个Host。Tomcat服务器可以配置为运行在多个主机名上,包括虚拟主机。

<Engine name="Catalina" defaultHost="localhost">

Catalina引擎从HTTP connector接收HTTP请求,并根据请求头部信息中主机名或IP地址重定向到正确的主机上。

Realm元素

一个Realm(域)就是一个包含user、password和role认证(比如访问控制)的数据库。你可以在任何容器中定义Realm,例如Engine、Host、Context和Cluster。

<Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
</Realm>

默认配置定义了一个Catalina Engine的Realm(UserDatabaseRealm),对用户访问engine的权限进行控制。其使用定义在GlobalNamingResources中,名字为UserDatabase的JNDI。

除了UserDatabaseRealm以外,还有:JDBCRealm(授权用户是否可以通过JDBC驱动连接到关系型数据库);DataSourceRealm(通过JNDI连接到数据库);JNDIRealm(连接到一个LDAP目录);MemoryRealm(将XML文件加载到内存)。

Hosts

一个Host定义了在Engine下的一个虚拟机,反过来其又支持多个Context(web应用)。

<Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">

默认配置定义了一个名为localhost的主机。appBase属性定义了所有webapp的根目录,在这种情况下是webapps。默认情况下,每一个webapp的URL和它所在的目录名称相同。例如,默认的Tomcat安装目录的webapps下提供了四个web应用:docs、examples、host-manager和manager。只有ROOT是个例外,它用一个空字符串定义。也就是说,它的URL是http://localhost:8080/。unpackWARs属性指定了放到webapps目录下的WAR-file是否应该被解压。对于unpackWARs=“false”,Tomcat将会直接从WAR-file运行应用,而不解压,这可能导致应用运行变慢。autoDeploy属性指定了是否自动部署放到webapps目录下的应用。

Value

Value(阀门)作为请求的前置处理程序,可以在请求发送到应用之前拦截HTTP请求。可以定义在任何容器中,比如Engine、Host、Context和Cluster。默认配置中,AccessLogValue会拦截HTTP请求,并在日志文件中创建一个切入点

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

1.5 tomcat-users.xml

用于访问tomcat管理应用程序时的安全性设置,用server.xml中引用的默认的用户数据库域(UserDatabase Realm)使用它,所有的凭证默认都是被注释的,如需授权和访问控制,或配置角色,可参考以下配置。

<role rolename="manager"/>
<role rolename="manager-gui"/>
<role rolename="admin"/>
<role rolename="admin-gui"/>
<user username="admin" password="admin" roles="admin-gui,admin,manager-gui,manager"/>

这样tomcat7首页上的Server Status、Manager App、Host Manager就都可以点击登录进去。

tomcat6配置:

<role rolename="admin"/>
<role rolename="manager"/>
<user username="admin" password="admin" roles="admin,manager"/>

1.6 web.xml

默认的web.xml文件可被所有的web应用程序使用,这个web.xml文件会设置jspservlet以支持应用程序处理jsps,并设置一个默认的servlet来处理静态资源和html文件,它还设置默认的回话超时以及像index.jsp,index.html这类欢迎文件,并且它为最通用的扩展文件设置默认的MIME类型。

一般在Java工程中,web.xml用来初始化工程配置信息,比如welcome页面,filter,listener,servlet,servlet-mapping,启动加载级别等等。

当应用程序被部署到tomcat时,它会用[engine name]/[host name]/[context-path name].xml创建与context.xml等效的文件,如用户也在$CATALINA_BASE/conf/[enginename]/[hostname]/context.xml.default文件,在这个文件中特定主机下的所有web应用程序将对主机器虚拟环境采用一系列默认设置。

下面就详细介绍一下web.xml中常用的标签及其功能。

<description>,<display-name>,<icon>

<context-param>

<context-param>元素含有一对参数名和参数值,用作应用的servlet上下文初始化参数。参数名在整个web应用中必须是唯一的。

例如:

<context-param>
    <param-name>name</param-name>
    <param-value>haha</param-value>
</context-param>

此处设定的参数,在JSP页面可以使用${initParam.name}来获取。

在Servlet中可以使用下列方式获取:

String name = getServletContext().getInitParamter("name");

<filter>

filter元素用于指定web容器中的过滤器。

在请求和响应对象被servlet处理之前或之后,可以使用过滤器对这两个对象进行操作。通过filter-mapping元素,过滤器被映射到一个servlet或一个URL模式。这个过滤器的filter元素和filter-mapping元素必须具有相同的名称。

filter元素用来声明filter的相关设定,filter元素除了下面介绍的子元素之外,还包括<icon>,<display-name>,<description>,<init-param>,其用途一样。

例如:

<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>

<filter-mapping>

filter-mapping元素用来声明web应用中的过滤器映射。过滤器可被映射到一个servlet或一个URL模式。将过滤器映射到一个servlet中会造成过滤器作用于servlet上。将过滤器映射到一个URL模式中则可以将过滤器应用于任何资源,只要该资源的URL与URL模式匹配。过滤是按照部署描述符的filter-mapping元素出现的顺序执行的。

filter-mapping元素的两个主要子元素filter-name和url-pattern用来定义Filter对应的URL。还有servlet-name和dispatcher子元素,不是很常用。

特别说明一下dispatcher,设置Filter对应的请求方式,有:REQUEST,INCLUDE,FORWAR,ERROR四种,默认为REQUEST。

例如:

<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>

在web.xml中完成一个最常见的任务是对servlet或JSP页面给出名称和定制的URL。用servlet元素分配名称,使用servlet-mapping元素将定制的URL与刚分配的名称相关联。

例如:

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>

<servlet-mapping>

servlet-mapping元素包含两个子元素servlet-name和url-pattern,用来定义servlet所对应的URL。

例如:

<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

<listener>

listener元素用来注册一个监听器类,可以在web应用中包含该类。使用listener元素,可以收到事件什么时候发生以及用什么作为响应的通知。

listener元素用来定义Listener接口,它的主要子元素为<listener-class>

例如:

<listener>
    <listener-class>com.gnd.web.listener.TestListener</listener-class>
</listener>

<session-config>

session-config包含一个子元素session-timeout,定义web应用中session的有效期限。

例如:

<session-config>
    <session-timeout>900</session-timeout>
</session-config>

<mime-mapping>

mime-mapping包含两个子元素extension和mime-type,定义某个扩展名和某一MIME Type做对应。

<extension>扩展名名称</extension>

<mime-type>MIME格式</mime-type>

例如:

<mime-mapping>
    <extension>doc</extension>
    <mime-type>application/vnd.ms-word</mime-type>
</mime-mapping>
<mime-mapping>
    <extension>xls</extension>
    <mime-type>application/vnd.ms-excel</mime-type>
</mime-mapping>
<mime-mapping>
    <extension>ppt</extension>
    <mime-type>application/vnd.ms-powerpoint</mime-type>
</mime-mapping>

<welcome-file-list>

welcome-file-list包含一个子元素welcome-file,用来定义首页列表。

welcome-file用来指定首页文件名称,服务器会按照设定的顺序来找首页。

例如:

<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>

<error-page>

error-page元素包含三个子元素error-code,exception-type和location。

将错误代码后异常的种类对应到web应用资源路径。

例如:

<error-page>
    <error-code>404</error-code>
    <location>error404.jsp</location>
</error-page>
<error-page>
    <exception-type>java.lang.Exception</exception-type>
    <location>error404.jsp</location>
</error-page>

<jsp-config>

jsp-config元素主要用来设定jsp的相关配置,jsp-config包括taglib和jsp-property-group两个子元素,其中taglib元素在JSP1.2时就已经存在,而jsp-property-group是JSP2.0新增的元素。

<taglib>

taglib元素包含两个子元素taglib-uri和taglib-location,用来设定JSP网页用到的TagLibrary路径。

<taglib-uri>URI</taglib-uri>

taglib-uri定义TLD文件的URI,JSP网页的taglib指令可以经由这个URI存取到TLD文件。

<taglib-location>/WEB-INF/lib/xxx.tld</taglib-location>

TLD文件对应web应用的存放位置。

<jsp-property-group>

jsp-property-group元素包含8个子元素,分别为:

<description>Description</description> 此设定的说明

<display-name>Name</display-name> 此设定的名称

<url-pattern>URL</url-pattern> 设定值所影响的范围,如*.jsp

<el-ignored>true/false</el-ignored> 是否支持EL语法

<scripting-invalid>true/false</scripting-invalid> 是否支持java代码片段<%...%>

<page-encoding>UTF-8</page-encoding> 设置JSP页面的编码

<include-prelude>.jspf</include-prelude> 设置JSP页面的抬头,扩展名为.jspf

<include-coda>.jspf</include-coda> 设置JSP页面的结尾,扩展名为.jspf

例如:

<jsp-config>
        <taglib>
            <taglib-uri>Taglib</taglib-uri>
            <taglib-location>/WEB-INF/tlds/MyTaglib.tld</taglib-location>
        </taglib>
        <jsp-property-group>
            <description>Configuration JSP example</description>
            <display-name>JspConfig</display-name>
            <url-pattern>/*</url-pattern>
            <el-ignored>true</el-ignored>
            <page-encoding>UTF-8</page-encoding>
            <scripting-invalid>true</scripting-invalid>
        </jsp-property-group>
    </jsp-config>

<resource-ref>

resource-ref元素包含五个子元素description,res-ref-name,res-type,res-auth,res-sharing-scope,利用JNDI取得应用可利用资源。

<res-auth>Application/Container</res-auth> 资源由Application或Container来许可。

<res-sharing-scope/>Shareable|Unshareable<res-sharing-scope/> 资源是否可以共享,默认值为Shareable

例如:

<resource-ref>
        <res-ref-name>jdbc/Druid</res-ref-name>
        <res-type>com.alibaba.druid.pool.DruidDataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>

1.7 loggin.properties

JULI记录器使用默认日志配置,它默认地使用ConsoleHandler和fileHandler设置应用程序或者程序包的日志级别。

2. 启动流程分析

2.1 Idea调试Tomcat源码环境搭建

首先下载Tomcat源码,读者可自行去Tomcat官网 下载,若执行力差的同学也可直接从此处pull。

Tomcat源码导入到开发工具中的方法有多种,笔者采用最直接的方式,解压源码包后直接导入到开发工具中,导入之后的源码并不能直接运行,还需要几个依赖包,读者可从此处的lib目录下获取,也可自行搜集。

找好依赖包也并不能让Tomcat源码正常运行,还需要为Bootstrap这个启动类增加几个启动参数。

-Dcatalina.home=/Users/chenmin/GitHub/tomcat
-Dcatalina.base=/Users/chenmin/GitHub/tomcat
-Djava.endorsed.dirs=/Users/chenmin/GitHub/tomcat/endorsed
-Djava.io.tmpdir=/Users/chenmin/GitHub/tomcat/temp
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file=/Users/chenmin/GitHub/tomcat/conf/logging.properties

上面的参数具体代表的意思就不一一详述了,其实光看名字就知道都是干嘛用的了。

以上准备步骤做好之后,就可以直接运行Bootstrap类,运行Tomcat源码进行调试了。

2.2 Tomcat Server的组成

2.2.1 整体说明

在上面对配置文件的说明中,通过server.xml的解释,我们知道server.xml中最顶级的元素是server,而server.xml中的每一个元素我们都可以把它看做是Tomcat中的某一个部分。所以我们可以参照着server.xml来分析源码。

Tomcat最顶层的容器叫Server,它代表着整个Tomcat服务器。Server中至少要包含一个Service来提供服务。Service包含两部分:Connector和Container。Connector负责网络连接,request/response的创建,并对Socket和request、response进行转换等,Container用于封装和管理Servlet,并处理具体的request请求。

一个Tomcat中只有一个Server,一个Server可以有多个Service来提供服务,一个Service只有一个Container,但是可以有多个Connector(一个服务可以有多个连接)。

[图片上传失败...(image-e1071d-1545114777128)]

2.2.2 各组件详解

可结合conf/配置文件说明中的server.xml的说明来看

上一篇 下一篇

猜你喜欢

热点阅读