01.安装tomcat 这里的版本是8.5
02.项目(文件系统的角度)
详细解释:
- bin
- bin目录主要是用来存放tomcat的脚本,如startup.sh , shutdown.sh
- conf
- catalina.policy: Tomcat安全策略文件,控制JVM相关权限,具体可以参考java. security.Permission
- catalina.properties : Tomcat Catalina行为控制配置文件,比如Common ClassLoader
- logging.properties : Tomcat日志配置文件, JDK Logging
- server.xml : Tomcat Server配置文件
- GlobalNamingResources :全局JNDI资源
- context.xml :全局Context配置文件
- tomcat-users.xml : Tomcat角色配置文件
- web.xml : Servlet标准的web.xml部署文件,
- Tomcat默认实现部分配置入内: org.apache.catalina.servlets.DefaultServlet
- org.apache.jasper.servlet.JspServlet
- lib 公共类库
- logs tomcat在运行过程中产生的日志文件
- webapps
用来存放应用程序,当tomcat启动时会去加载webapps目录下的应用程序 - work
用来存放tomcat在运行时的编译后文件,例如JSP编译后的文件
03.重要的文件是webapps
这里存放的各种应用,重要的是webapps中的WEB-INF文件夹,里面的web.xml
里面写的servlet
举个例子:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<display-name>Tomcat Host Manager Application</display-name>
<description>
A scriptable host management web application for the Tomcat Web Server;
Manager lets you view, create and remove virtual hosts.
</description>
<servlet>
<servlet-name>HostManager</servlet-name>
<servlet-class>org.apache.catalina.manager.host.HostManagerServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>HTMLHostManager</servlet-name>
<servlet-class>org.apache.catalina.manager.host.HTMLHostManagerServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
</servlet>
04.servlet类的doGet方法:怎么处理doGet方法呢?
先讨论Tomcat的几个组件的事情:四个组件
Engine :直接理解为一个Tomcat ,一个Engine
Host :虚拟主机,一个Host表示一个服务器,可以给服务器配置一个域名
Context:一个Context就是一个应用
Wrapper:servlet包装类
具体说明:
Context:中文是指上下文,其实就是一个Context就是一个应用。一个应用就会有一组servlet,用于响应应用中的不同请求List<servlet>
<Context path="/zhouyu" docBase="D:\JavaProjects\HelloServlet\target\HelloServlet"></Context>
path: 要访问的路径(URL上的),一般都是项目的名字
docBase:内容放的地方
Host :虚拟主机,类似服务器,有域名可以访问。一个Host,一个服务器,一个服务器上可以运行很多的应用。List<Context >
Host的配置在server.xml看
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Context path="/zhouyu" docBase="D:\JavaProjects\HelloServlet\target\HelloServlet-1.0-SNAPSHOT"></Context>
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<Host name="www.fuguang.com" appBase="webapps"
unpackWARs="true" autoDeploy="true">
</Host>
<Host name="www.zuozuozuo.com" appBase="webapps"
unpackWARs="true" autoDeploy="true">
</Host>
在xml文件中,Host的属性
name: 域名
appBase: webapps—对应的就是webapps文件夹
unpackWARs:是不是要解压war包
autoDeploy: 是不是要自动部署
Engine: 一个Engine 就代表一个Tomcat。一个Engine,一个引擎,一个引擎上可以运行很多的服务器。List<Host >
<Engine name="Catalina" defaultHost="localhost">
defaultHost 表示默认的服务器
Wrapper:servlet的包装类,有属性List<servlet>
问:如果如果面对同一种请求的话,servlet会怎么样?
多个请求共用一个servlet实例。这样会线程不安全。
问:怎么样改进?可以使用加锁的技术,用关键字synchronized,或者接口SingleThreadModel 来进行操作保证线程安全。这样,让一个请求面对一个servlet。
问:产生的后果呢?servlet数量太多,Context容器难以管理。
问:怎么改进?用Wrapper包装servlet,一类servlet是用一个Wrapper来包装。这样。Context容器的属性就会变成List<Wrapper>
线程不安全例子:
05.pipeline 和 valve 管道和阀门
public interface Valve {
public Valve getNext();
public void setNext(Valve valve);
public void backgroundProcess();
public void invoke(Request request, Response response)
throws IOException, ServletException;
public boolean isAsyncSupported();
}
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// Select the Host to be used for this Request
Host host = request.getHost();
if (host == null) {
// HTTP 0.9 or HTTP 1.0 request without a host when no default host
// is defined.
// Don't overwrite an existing error
if (!response.isError()) {
response.sendError(404);
}
return;
}
if (request.isAsyncSupported()) {
request.setAsyncSupported(host.getPipeline().isAsyncSupported());
}
// Ask this Host to process this request
host.getPipeline().getFirst().invoke(request, response);
}
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// Initialize local variables we may need
boolean unavailable = false;
Throwable throwable = null;
// This should be a Request attribute...
long t1=System.currentTimeMillis();
requestCount.incrementAndGet();
StandardWrapper wrapper = (StandardWrapper) getContainer();
Servlet servlet = null;
Context context = (Context) wrapper.getParent();
// Check for the application being marked unavailable
if (!context.getState().isAvailable()) {
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardContext.isUnavailable"));
unavailable = true;
}
// Check for the servlet being marked unavailable
if (!unavailable && wrapper.isUnavailable()) {
container.getLogger().info(sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
unavailable = true;
}
// Allocate a servlet instance to process this request
try {
if (!unavailable) {
servlet = wrapper.allocate();
}
} catch (UnavailableException e) {
container.getLogger().error(
sm.getString("standardWrapper.allocateException",
wrapper.getName()), e);
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
} catch (ServletException e) {
container.getLogger().error(sm.getString("standardWrapper.allocateException",
wrapper.getName()), StandardWrapper.getRootCause(e));
throwable = e;
exception(request, response, e);
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.allocateException",
wrapper.getName()), e);
throwable = e;
exception(request, response, e);
servlet = null;
}
MessageBytes requestPathMB = request.getRequestPathMB();
DispatcherType dispatcherType = DispatcherType.REQUEST;
if (request.getDispatcherType()==DispatcherType.ASYNC) {
dispatcherType = DispatcherType.ASYNC;
}
request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType);
request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
requestPathMB);
// Create the filter chain for this request
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
// Call the filter chain for this request
// NOTE: This also calls the servlet's service() method
Container container = this.container;
try {
if ((servlet != null) && (filterChain != null)) {
// Swallow output if needed
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
filterChain.doFilter(request.getRequest(),
response.getResponse());
}
} finally {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
context.getLogger().info(log);
}
}
} else {
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
}
}
} catch (ClientAbortException | CloseNowException e) {
if (container.getLogger().isDebugEnabled()) {
container.getLogger().debug(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
}
throwable = e;
exception(request, response, e);
} catch (IOException e) {
container.getLogger().error(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
throwable = e;
exception(request, response, e);
} catch (UnavailableException e) {
container.getLogger().error(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
// throwable = e;
// exception(request, response, e);
wrapper.unavailable(e);
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
// Do not save exception in 'throwable', because we
// do not want to do exception(request, response, e) processing
} catch (ServletException e) {
Throwable rootCause = StandardWrapper.getRootCause(e);
if (!(rootCause instanceof ClientAbortException)) {
container.getLogger().error(sm.getString(
"standardWrapper.serviceExceptionRoot",
wrapper.getName(), context.getName(), e.getMessage()),
rootCause);
}
throwable = e;
exception(request, response, e);
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
throwable = e;
exception(request, response, e);
} finally {
// Release the filter chain (if any) for this request
if (filterChain != null) {
filterChain.release();
}
// Deallocate the allocated servlet instance
try {
if (servlet != null) {
wrapper.deallocate(servlet);
}
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.deallocateException",
wrapper.getName()), e);
if (throwable == null) {
throwable = e;
exception(request, response, e);
}
}
// If this servlet has been marked permanently unavailable,
// unload it and release this instance
try {
if ((servlet != null) &&
(wrapper.getAvailable() == Long.MAX_VALUE)) {
wrapper.unload();
}
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.unloadException",
wrapper.getName()), e);
if (throwable == null) {
exception(request, response, e);
}
}
long t2=System.currentTimeMillis();
long time=t2-t1;
processingTime += time;
if( time > maxTime) {
maxTime=time;
}
if( time < minTime) {
minTime=time;
}
}
}