实践

Please remember that a JSP page, even one that simply prints out “OK”, will create a session

编码相关

request的编码: server.xml Connector配置 URIEncoding="UTF-8”

response的编码: setCharecahterEncoding

tomcat默认字符集: /etc/init.d/tomcat7: export LANG=en_US.UTF-8

连接池相关

acceptCount:超出maxConnection后,还可以接受的链接数(accept queue大小),超出返回connnect refused,read timeout,connection reset by peer均有可能;
maxConnections:最大链接数;
maxThreads:做大工作线程数; 内网访问时,关注maxPerRoute参数,此时MaxThreads实际达不到。

配置多个host: 每个都作为独立应用,如果指向同一个app,则会导致重复加载!!!可以使用alias。

安装

1,tomcat下载:

http://tomcat.apache.org/

2,eclipse插件下载及安装

http://www.eclipsetotale.com/tomcatPlugin.html#A3

3,需要设置参数:

首选项中设置当前使用的tomcat版本号,以及tomcat home路径。
Context声明模式使用context file,此后eclipse中创建的tomcat工程,都会自动生成对应的context的文件,存储的路径就为contexts directory。结果文件的命名为:工程名.xml。
在web页面上访问时,首先会通过context的路径映射,找到对应的工程位置,然后再根据工程中的web.xml文件找到实际的servlet类进行执行。

4,创建tomcat工程

文件 –> 新建 –> 项目 –> (展开java,选择Tomcat Project)

5,编写代码

1) 业务逻辑代码:.java,放入WEB-INF/src下。
2) Web.xml,servlet配置脚本,放入WEB-INF下。
3) jsp??
4)静态资源文件,如图片,放在跟WEB-INF同级目录下,不可放到WEB-INF内部,否则访问不到。

6,执行代码

  • 方法1:直接点击中的tomcat图标,由于之前配置了相关路径,此处会加载新增的web应用。也可以通过浏览器进行访问。访问路径为:http://localhost:8080/classpath/classpath,此处第一个classpath是自动生成的context文件中指定的路径,第二个classpath是工程web.xml中配置的map路径。
  • 方法2:配置servers,配置成功后,会在资源管理器中显示,此时在需要执行的工程上右击,选择Run As –>Run On Server。建议使用最新版本,否则不同版本之间不匹配,会出现功能问题。此时通过与方法1相同的路径无法访问!!!–解决方法:需要配置servers的Sever Locations,右击servers下当前使用的tomcat,选择open,在servers的Sever Locations中选择use tomcat installation。

启动方式

有两种启动eclipse的方式,

  • 方式1:通过dos命令行调用startup启动,此时所有设置在.bat脚本中添加。
  • 方式2:通过eclipse插件启动,测试不会执行.bat脚本,直接启动tomcat,相关配置需要在而eclipse的tomcat插件窗口中输入。

项目部署

  • 方法1:在tomcat中的conf目录中,在server.xml中的,节点中添加:
<Context path="/hello" docBase="D:eclipse3.2.2forwebtoolsworkspacehelloWebRoot" debug="0" privileged="true"> 
</Context> 

path:表示访问的路径;如上述例子中,访问该应用程序为:http://localhost:8080/Mywebapps
reloadable:表示可以在运行时在classes与lib文件夹下自动加载类包
docbase:表示应用程序的地址,注意斜杠的方向“\”
workdir:表示缓存文件的放置地址

  • 方法2:将web项目文件件拷贝到webapps 目录中。

  • 方法3: 在conf目录中,新建 Catalina(注意大小写)\localhost目录,在该目录中新建一个xml文件,名字可以随意取,只要和当前文件中的文件名不重复就行了,该xml文件的内容为:

<Context path="/hello" docBase="D:eclipse3.2.2forwebtoolsworkspacehelloWebRoot" debug="0" privileged="true"> 
</Context> 

日志介绍

Linux:

Cataline引擎的日志文件,文件名catalina.日期.log
Tomcat下内部代码丢出的日志,文件名localhost.日期.log(jsp页面内部错误的异常,org.apache.jasper. runtime.HttpJspBase.service类丢出的,日志信息就在该文件!) Tomcat下默认manager应用日志,文件名manager.日期.log
控制台输出的日志,Linux下默认重定向到catalina.out
Access日志(Servlet.xml配置)
应用程序通过log4j.properties:${catalina.base}/logs/probe.log重定向过来的日志
JULIorg.apache.juli.FileHandler对应的日志文件名:{prefix}.{date}.{suffix} 默认juli.日期.log
默认控制台均输出到$CATALINA_BASE/logs/catalina.out。
针对每个应用可以单独设置对应的log4j.properties,来指定其输出。
Tomcat/lib目录下配置log4j时,输出信息为tomcat启动过程中,app的日志输出。
各个App下配置log4j时,输出为app运行过程中的日志。此时tomcat/lib下的配置将不生效,无输出。

Windows:

Tomcat/lib目录下配置log4j时,目前测试没有任何输出。
各个App下配置log4j时,输出为app启动以及运行过程中的日志。
主要是配置console输出到eclipse控制台。

输出日志格式:

  • %a – 远程主机的IP (Remote IP address)
  • %A – 本机IP (Local IP address)
  • %b – 发送字节数,不包含HTTP头,0字节则显示 ‘-’ (Bytes sent, excluding HTTP headers, or ‘-’ if no - bytes
  • were sent)
  • %B – 发送字节数,不包含HTTP头 (Bytes sent, excluding HTTP headers)
  • %h – 远程主机名 (Remote host name)
  • %H – 请求的具体协议,HTTP/1.0 或 HTTP/1.1 (Request protocol)
  • %l – 远程用户名,始终为 ‘-’ (Remote logical username from identd (always returns ‘-’))
  • %m – 请求方式,GET, POST, PUT (Request method)
  • %p – 本机端口 (Local port)
  • %q – 查询串 (Query string (prepended with a ‘?’ if it exists, otherwise
  • an empty string)
  • %r – HTTP请求中的第一行 (First line of the request)
  • %s – HTTP状态码 (HTTP status code of the response)
  • %S – 用户会话ID (User session ID)
  • %t – 访问日期和时间 (Date and time, in Common Log Format format)
  • %u – 已经验证的远程用户 (Remote user that was authenticated
  • %U – 请求的URL路径 (Requested URL path)
  • %v – 本地服务器名 (Local server name)
  • %D – 处理请求所耗费的毫秒数 (Time taken to process the request, in millis)
  • %T – 处理请求所耗费的秒数 (Time taken to process the request, in seconds) 你可以用以上的任意组合来定制你的访问日志格式,也可以用下面两个别名common和combined来指定常用的日志格式:

Servlet

servlet会自动将http header名转换为小写,遵从http协议,头域是大小写不敏感的。遵从servlet规范,所有同名的域(不区分大小写)的值会以列表方式给出。
Servlet在编写完毕后,必须先在web.xml中配置才能访问。在配置时,需要指定一个Servlet的访问地址。Servlet映射地址不是随便 怎么写都可以,必须要遵从一定的规则,这个规则在Servlet的规范中有详细的说明。按照Servlet规范的要求,Servlet映射地址形式只能有 四种,即:

  • 第一种、以“/”开头,以“/”结束的地址,这种地址映射称为路径映射。这种映射中使用了通配符,代表访问这个目录下的任意一个地址都将调用这个Servlet。比如,一个Servlet映射的地址是“/admin/”,那么当访问/admin这个目录下的任意一个地址,都会映射到这个Servlet上,除非这个地址已经明确地映射到其它的Servlet上了。也即,当另外一个Servlet映射的地址是 “/admin/listUser”,那么当访问这个地址时,请求还是会被映射到这人Servlet上。
  • 第二种、以“.”开头的地 址,这种地址映射称为扩展名映射。这也是一种模糊映射,代表访问相同扩展名的地址时,都会映射到这个Servlet上。这种地址映射在Struts中就得 到了应用,即所有访问以.do结束的地址时,都会映射到ActionServlet上。但不能将第一种与第二种地址映射形式结合起来用,即如果写成 “/admin/.do”,这就错了。没有原因,因为这是规范。
  • 第三种、只有一个“/”的地址映射,这种地址映射称为默认映射。也就是说,如果用户访问了一个地址,这个地址没有明确地在web.xml中映射,也不满足以上两种形式的模糊映射,这个时候就访问“/”映射的 Servlet。这种地址映射,我们在实际开发中很少应用,但它对服务器来说是很重要的。以Tomcat为例,Tomcat实际上是一个纯粹的 Servlet容器,也就是说,只有Servlet才能在Tomcat上运行。但有可能会说,我们将HTML文件部署到Tomcat上也运行得很好啊。没 错,但真正运行的还是Servlet。什么意思呢?大家可以想一下,我们部署到服务器上所有的HTML文件,我们从来都不会到web.xml中去映射的, 根据我们刚刚讲到的,如果访问了没有映射的地址,服务器会访问“/”所对应的Servlet,而正是这个Servlet帮我们找到HTML文件,并把它写 到客户端的。也就是说,Tomcat预先定义了一个Servlet,并把它的地址映射为“/”。这样其它静态资源的访问实际上都是在访问这个 Servlet,而它的职责则是简单地找到这个文件,并把它们写到响应中去。
  • 第四种、明确的地址映射,这是我们最常用的一种地址映射形式。规范中没有对这种地址映射有特殊的要求,但在配置地址时,必须以“/”开头才可以,否则将报错。

web.xml

<url-pattern>/</url-pattern> only matches the URL host/servlet 
<url-pattern>/*</url-pattern> matches everything under host/servlet, such as /index.html, /foo.jpg and, most importantly in this case, /WEB-INF/pages/apiForm.jsp the * is the wildcard, which says "anything" In the earlier suggestion, *.do matches anything that ends in .do, for example, /foo.do, /foo/bar.do. It doesn't match anything ending in jsp, so a request for /WEB-INF/pages/apiFrom.jsp is not matched, and is not routed to the DispatcherServlet 

具体Web应用的入口。这里通过servlet控制器实现业务的分发。 具体的设置包括,

指定监听者,在tomcat加载时,会启动listener,该listener继承ServletContextListener实现。


  • 指定context参数的键值对,在listener中可以通过ServletContextEvent的getServletContext获取context,进而通过context的getInitParameter获取该配置中的值。

对接收到的请求设置过滤器,这里可以通过设置额外的参数值,在对应的代码实现继承Filter,通过FilterConfig的getInitParameter方法获取配置的值,通常读取配置参数值都是在初始化阶段的init函数中完成。 可以同时配置多个filter。


  • 对需要应用过滤器的http请求,使用url-pattern进行设置。

http请求的总入口,这里可以通过设置额外的参数值,代码实现继承HttpServlet类,使用getServletConfig方法获取ServletConfig,然后使用ServletConfig的getInitParameter获取配置的参数值,通常读取配置参数值都是在初始化阶段的init函数中完成。
可以根据分工不同,同时设置多个servlet。
如果增加如下load-on-startup配置,则会在tomcat启动时初始化该servlet,否则需要在实际被调用到时初始化。

  • 这个元素的含义是在服务器启动的时候就加载这个servlet(实例化并调用init()方法).这个元素中的可选内容必须为一个整数,表明了这个servlet被加载的先后顺序.当是一个负数时或者没有指定时,则表示服务器在该servlet被调用时才加载。当值为0或者大于0时,表示服务器在启动时就加载这个servlet.该容器肯定可以保证被标记为更小的整数的servlet比被标记为更大的整数的servlet更先被调用,还可已选择同样的load-on-start-up值来夹在servlets.
    补充:正数的值越小,启动该servlet的优先级越高。

  • 对该servlet需要处理的http请求,通过url-pattern进行设置。

类加载机制

ClassLoader

被组织成树形,一般的工作原理是: 1) 线程需要用到某个类,于是contextClassLoader被请求来载入该类
2) contextClassLoader请求它的父ClassLoader来完成该载入请求
3) 如果父ClassLoader无法载入类,则contextClassLoader试图自己来载入

WebApp?ClassLoader

工作原理和上述有少许不同。它先试图自己载入类(在ContextBase?/WEB-INF/…中载入类),如果无法载入,再请求父ClassLoader完成 由此可得:

  • 对于WEB APP线程,它的contextClassLoader是WebAppClassLoader
  • 对于Tomcat Server线程,它的contextClassLoader是CatalinaClassLoader

Class和jar加载顺序

    1. $java_home/lib 目录下的java核心api
    1. $java_home/lib/ext 目录下的java扩展jar包
    1. java -classpath/-Djava.class.path所指的目录下的类与jar包
    1. $CATALINA_HOME/common目录下按照文件夹的顺序从上往下依次加载
    1. $CATALINA_HOME/server目录下按照文件夹的顺序从上往下依次加载
    1. $CATALINA_BASE/shared目录下按照文件夹的顺序从上往下依次加载
    1. 我们的项目路径/WEB-INF/classes下的class文件
    1. 我们的项目路径/WEB-INF/lib下的jar文件

其他

  • 1,在同一个文件夹下,jar包是按顺序从上到下依次加载。
  • 2, 由ClassLoader的双亲委托 模式加载机制我们可以知道,假设两个包名和类名完全相同的class文件不再同一个jar- 包,如果一个class文件已经被加载java虚拟机里了,那么后面的相同的class文件就不会被加载了。
  • 3,每个运行中的线程都有一个成员contextClassLoader,用来在运行时动态地载入其它类。
  • 4,系统默认的contextClassLoader是systemClassLoader,所以一般而言java程序在执行时可以使用JVM自带的类、- $JAVA_HOME/jre/lib/ext/中的类和$CLASSPATH/中的类。
  • 5,可以使用 Thread.currentThread().setContextClassLoader(…); 更改当前线程的contextClassLoader,- 来改变其载入类的行为。