Web服务器
Web服务器是运行及发布Web应用的容器,只有将开发的Web项目放置到该容器中,才能使网络中的所有用户通过浏览器进行访问。开发Java Web应用所采用的服务器主要是与JSP/Servlet兼容的Web服务器,比较常用的有Tomcat、Resin、JBoss、WebSphere 和 WebLogic 等。
Apache
Nginx
反向代理web服务器
反向代理
Http代理 | 特点 |
---|---|
正向代理 | 客户端的代理 |
反向代理 | 服务器端的代理 |
正向代理
反向代理
负载均衡
Nginx提供的负载均衡策略有2种:内置策略和扩展策略。内置策略为轮询,加权轮询,Ip hash。扩展策略,就天马行空,只有你想不到的没有他做不到的。
内置策略
轮询
加权轮询
Ip hash
iphash对客户端请求的ip进行hash操作,然后根据hash结果将同一个客户端ip的请求分发给同一台服务器进行处理,可以解决session不共享的问题。
但是如果代理服务器挂掉了,所有的Session信息也会丢失,一般不使用nginx的iphash作Session共享,而是使用Redis作Session共享。
扩展策略
动静分离
动静分离,在我们的软件开发中,有些请求是需要后台处理的,有些请求是不需要经过后台处理的(如:css、html、jpg、js等等文件),这些不需要经过后台处理的文件称为静态文件。让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作。提高资源响应的速度。
WebServer应用服务器
Tomcat
Tomcat是一个Web应用服务器,同时也是一个Servlet/JSP容器。Tomcat作为Servlet容器,负责处理客户端请求,把请求传送给Servlet,并将Servlet的响应返回给客户端。
目录结构
bin 脚本
主要有两大类,一类是以.sh结尾的(linux命令),另一类是以.bat结尾的(windows命令)。
很多环境变量的设置都在此处,例如可以设置JDK路径、TOMCAT路径
startup 用来启动tomcat
shutdown 用来关闭tomcat
修改catalina可以设置tomcat的内存
conf 配置文件
server.xml | 服务器配置:端口号、域名或IP、默认加载的项目、请求编码等 |
web.xml | 服务器启动时加载的配置文件 |
context.xml | 用来配置数据源之类的 |
tomcat-users.xml | 配置管理tomcat的用户与权限 |
在Catalina/localhost目录下ROOT.xml可以设置默认加载的项目lib
每当我们访问一个地址的时候,tomcat
首先到conf\Catalina\ localhost目录下去查看是否存在主目录或虚拟目录的xml文件,
如果有该xml文件,就按该xml里的路径进行访问,
如果没有该xml文件,就到 server.xml文件里去查看是否配置context标签,
如果配置了context标签,则在conf\Catalina\localhost目录下生成一个对应的xml文件,以便于下次直接验证而不再访问server.xml,与此同时打开context里指定的路径,
如果没有配置context标签,则返回访问错误页面。
虚拟目录和主目录
虚拟目录和主目录:
1)conf/server.xml
2)conf/Catalina/localhost/ROOT.xml
具体是主目录的配置还是虚拟目录的配置取决于path的值
path="" 主目录。同时tomcat会生成一个/conf/Catalina/localhost目录里面,自动生成一个ROOT.xml文件。
path不为空 虚拟目录。path为访问路径,docBase为程序包的物理绝对路径。
如果docBase目录不在Webapps目录下,有可能出现Cookie和session互窜的问题,比如用户1登录看到用户2的登录信息。
如果docBase目录在Webapps目录下,会导致项目加载两次。
设置虚拟目录和主目录后,都会在conf\Catalina\localhost目录下生成相应的xml文件。当我们在server.xml里面删除了主目录和虚拟目录的设置后,
如果系统还没有生效,这时候需要查看conf\Catalina\localhost目录下的xml文件是不是已经被删除了;如果没有被删除,该xml还是对tomcat起作用的,我们必须手动删除。
web.xml
webapps\ROOT\WEB-INF
配置虚拟目录
<Context … />
server.xml
https://blog.csdn.net/klx502/article/details/53606872
Server->Service->Engine->Host->Context 组成的四层结构,从里层向外层分别是:
- Context: 即 Web 应用程序,一个 Context 即对于一个 Web 应用程序。
- Host:即虚拟主机,比如 www.dog.com 对应一个虚拟主机,api.dog.com 对于另一个虚拟主机。一个 Host 用于定义一个虚拟主机。(所谓的”一个虚拟主机”可简单理解为”一个网站”)
- Engine:一组虚拟主机的集合。比如www.dog.com 和 api.dog.com 可以组成一组虚拟主机集合。
- Service:一组 Engine 的集合,包括线程池 Executor 和连接器 Connector 的定义。
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<Executor ...... />
<Connector port="端口" protocol="HTTP/1.1" connectionTimeout="" redirectPort="" />
<Connector ...... />
<Engine name="Catalina" ... >
<Host name="localhost" ... >
<!--配置虚拟目录。虚拟目录可以有多个,保持path唯一性即可-->
<Context path="浏览器访问虚拟路径" docBase="项目真实路径" />
</Host>
</Engine>
</Service>
</Server>
<?xml version='1.0' encoding='utf-8'?>
<!-- 完整的HTTP请求过程
用户(这里指的是使用同一台电脑的用户)发出一个请求,如http://localhost:8080/hello/index.jsp。
Conector发现是http/1.1协议,而且还是8080端口,于是就把请求接收后交给符合条件的Engine
Engine通过请求中的主机名localhost查找满足条件的虚拟主机(Host)
找到后就去此虚拟主机指定的appBase(指项目所存放的目录)中去找名称为hello的项目
找到后就去此hello项目中的配置文件web.xml中找满足条件的虚拟路径/index.jsp
查找方式为:遍历所有<servlet-mapping>元素,看谁的<url-pattern>的值和用户请求的/index.jsp匹配(匹配逻辑)
找到后就根据<servlet-mapping>元素的<servlet-name>的值找<servlet>元素,看谁的<servlet-name>的值和它是一样的
找到后就执行此<servlet>元素中 <servlet-class>的值所指定的本项目src目录下的servlet类,如com.itheima.bqt.Login
执行后将产生的结果返回给用户 -->
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<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"> <!-- 在<Server>中只能有一个<Service>元素,它表示服务 -->
<!-- 在<Service>中可以有N个<Connector>元素,它表示连接,不同的Connector针对不同的协议,我们只需关心处理HTTP协议的元素 -->
<!-- port表示端口号,默认值为8080,修改为80以后在访问项目时就不用再给出端口号了,因为80是HTTP默认端口 -->
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<!-- 在<Service>中只能有一<Engine>元素,它是处理引擎,用户最终连接最终是由Connector导入的Engine处理的 -->
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
<!-- 在<Engine>中可以有N个<Host>元素,每个<Host>元素表示一个虚拟主机,每个主机都有自己的主机名name和项目目录appBase -->
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
<!-- 在<Host>中可以有N个<Context>元素,其中path指定的是项目虚拟路径,可以随意给出,docBase指定你的项目的真实存放的路径。指定后,访问时就不再通过项目名访问资源,而是通过path的值访问 -->
<Context path="" docBase="D:\JAVA\tomcat6\我的主页"/><!--配置为此虚拟主机(即某个网站)的主页-->
</Host>
<!--定义了另一个虚拟主机及其此主机的相对路径,相当于可以将搜狐和新浪的网站在同一台服务器中运行-->
<Host name="localhost2" appBase="webapps2"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
</Host>
</Engine>
</Service>
</Server>
web.xml
启动一个web项目的时候,web容器去读取它的配置文件web.xml。
读取节点的顺序是:context-param -> listener -> filter -> servlet -> spring 。
上下文参数 -> 过滤器 -> 监听器 -> servlet -> spring 。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
//每定义一个servlet,eclipse都会自动配置<servlet>和 <servlet-mapping>标签
<servlet>
<servlet-name>Login</servlet-name> //随意起一个【名字】,不要有空格和中文
<servlet-class>com.itheima.bqt.Login</servlet-class> //此名字对应的类(即要调用的servlet)
</servlet>
/*关于/conf/web.xml中的DefaultServlet
首先所有的请求进入tomcat,都会流经servlet,如果没有匹配到任何应用指定的servlet,那么就会流到默认的DefaultServlet。
DefaultServlet被定义在/conf/web.xml中,配置文件中被定义的东西会在Tomcat启动的时候被加载,对所有的webapp都有效。
DefaultServlet在Tomcat中主要是做目录列表(Directory Listing)用。
静态资源(JSP,HTML等)都走这个DefaultServlet~*/
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Login</servlet-name> //和上面的那个 <servlet-name>完全一致
<url-pattern>/servlet/Login</url-pattern> //为此名称对应的servlet指定一个【虚拟路径】
//注意:不管怎么配置,访问的时候前面都必须加上web应用的名称,如http://localhost:8888【/Login】/servlet/Login
//注意:配置时不要忘了要在前面加上【“/”】,另外如果在后面加了“/”,访问时此“/”也必须在后面加上才可以
//注意:配置时只有一种情况是不需要在前面加“/”的,那就是使用【*.扩展名】通配符,但访问时,此“/”也不能少
//另外一种统配符格式为:【/xxx/*】,当然【/*】也是可以的,此时,仅http://localhost:8888/Login便可访问
//注意:【*】不可以!,另外【*.扩展名】的匹配级别最低!
//注意:【/*】和【/】(缺省servlet)效果不太一样,都不建议配置
//解疑:之所以不和<servlet>组合成一个标签,是为了实现一个<servlet>可以对应多个<servlet-mapping>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file> //会自动生成一个名为index.jsp的文件,并设置为
</welcome-file-list>
</web-app>
lib jar包
例如,像连接数据库的jdbc的包我们可以加入到lib目录中来。
jsp-api.jar
servlet-api.jar
logs 日志文件
用来存放tomcat在运行过程中产生的日志文件,非常重要的是在控制台输出的日志。(清空不会对tomcat运行带来影响)
在windows环境中,控制台的输出日志在catalina.xxxx-xx-xx.log文件中
在linux环境中,控制台的输出日志在catalina.out文件中
temp 临时文件
用户存放tomcat在运行过程中产生的临时文件。(清空不会对tomcat运行带来影响)
webapps web应用程序
用来存放应用程序
当tomcat启动时会去加载webapps目录下的应用程序。
可以以文件夹、war包、jar包的形式发布应用。
当然,你也可以把应用程序放置在磁盘的任意位置,在()配置文件中映射好就行。
index.html首页
web.xml配置
work 编译后文件
存放tomcat在运行时的编译后文件,例如JSP编译后的 Servlet 文件。
清空work目录,然后重启tomcat,可以达到清除缓存的作用。
https://www.cnblogs.com/w-wfy/p/6241471.html
Tomcat的体系结构
Tomcat的两个核心组件:Connector和Container。其中一个集装箱Container可以选择多个连接器Connector。
Connector
一个Connector组件将在某个指定的端口上侦听客户请求,接收浏览器发过来的tcp连接请求,创建一个Request和一个Response对象分别用于和其你去端交换数据,然后会产生一个线程来处理这个请求并把产生的Request和Response对象传给Engine,从Engine中获得响应并返回给客户端。 Tomcat有两个经典的Connector,一个直接侦听来自浏览器的HTTP请求,另外一个侦听来自其他的WebServer的请求。Cotote HTTP/1.1 Connector在端口8080处侦听来自客户浏览器的HTTP请求,Coyote JK2 Connector在端口8009处侦听其他WebServer的Servlet/JSP请求。 Connector 最重要的功能就是接收连接请求然后分配线程让 Container来处理这个请求,所以这必然是多线程的,多线程的处理是 Connector 设计的核心。
Container
Container组件的体系结构如下:
Container是容器的父接口,该容器的设计用的是典型的责任链的设计模式,它由四个自容器组件构成,分别是Engine、Host、Context、Wrapper。这四个组件是负责关系,存在包含关系。通常一个Servlet class对应一个Wrapper,如果有多个Servlet则定义多个Wrapper,如果有多个Wrapper就要定义一个更高的Container,如Context。 Context定义在父容器 Host 中,其中Host 不是必须的,但是要运行 war 程序,就必须要 Host,因为 war 中必有 web.xml 文件,这个文件的解析就需要 Host 了,如果要有多个 Host 就要定义一个 top 容器 Engine 了。而 Engine 没有父容器了,一个 Engine 代表一个完整的 Servlet 引擎。
Engine
Engine 容器比较简单,它只定义了一些基本的关联关系 Host 容器
Host
Host 是 Engine 的字容器,一个 Host 在 Engine 中代表一个虚拟主机,这个虚拟主机的作用就是运行多个应用,它负责安装和展开这些应用,并且标识这个应用以便能够区分它们。它的子容器通常是 Context,它除了关联子容器外,还有就是保存一个主机应该有的信息。
Context
Context 代表 Servlet 的 Context,它具备了 Servlet 运行的基本环境,理论上只要有 Context 就能运行 Servlet 了。简单的 Tomcat 可以没有 Engine 和 Host。Context 最重要的功能就是管理它里面的 Servlet 实例,Servlet 实例在 Context 中是以 Wrapper 出现的,还有一点就是 Context 如何才能找到正确的 Servlet 来执行它呢? Tomcat5 以前是通过一个 Mapper 类来管理的,Tomcat5 以后这个功能被移到了 request 中,在前面的时序图中就可以发现获取子容器都是通过 request 来分配的
Wrapper
Wrapper 代表一个 Servlet,它负责管理一个 Servlet,包括的 Servlet 的装载、初始化、执行以及资源回收。Wrapper 是最底层的容器,它没有子容器了,所以调用它的 addChild 将会报错。 Wrapper 的实现类是 StandardWrapper,StandardWrapper 还实现了拥有一个 Servlet 初始化信息的 ServletConfig,由此看出 StandardWrapper 将直接和 Servlet 的各种信息打交道。
说明:除了上述组件外,Tomcat中还有其他重要的组件,如安全组件security、logger日志组件、session、mbeans、naming等其他组件。这些组件共同为Connector和Container提供必要的服务。
应用加载顺序
方法:分析catalina.jar源码
应用加载顺序 :
1)conf/server.xml context 配置的项目
如果path为/,/ROOT,那么baseName就是ROOT,否则就为它本身
如果docBase是war包,并且war包对应的文件夹不存在,就解压到刚刚的baseName下面。如果docBase是文件夹,什么都不做。
如果docBase文件夹不存在,再去目录下查找docBase(文件目录)对应的war包存在不存在,如果存在解压 war包到baseName(url路径,ROOT就是域名根目录)
2)conf/Catalina/localhost 配置的项目
3)conf/server.xml Host中appBase配置的项目,一般为webapps
appBase的war包项目,最后是appBase目录下的文件夹项目
tomcat是以path来判断项目是否已经启动的
HTTP请求的过程
Tomcat Server处理一个HTTP请求的过程如下图所示:
1.用户在浏览器中输入网址localhost:8080/test/index.jsp,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得;
2.Connector把该请求交给它所在的Service的Engine(Container)来处理,并等待Engine的回应;
3.Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host;
4.Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机),名为localhost的Host获得请求/test/index.jsp,匹配它所拥有的所有Context。Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为“ ”的Context去处理);
5.path=“/test”的Context获得请求/index.jsp,在它的mapping table中寻找出对应的Servlet。Context匹配到URL Pattern为*.jsp的Servlet,对应于JspServlet类;
6.构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet()或doPost(),执行业务逻辑、数据存储等;
7.Context把执行完之后的HttpServletResponse对象返回给Host;
8.Host把HttpServletResponse对象返回给Engine;
9.Engine把HttpServletResponse对象返回Connector;
10.Connector把HttpServletResponse对象返回给客户Browser。
实现Tomcat
MyRequest
MyResponse
MyServer
MyHttpServlet接口
MyServlet子类
MyMapping映射关系web.xml
package myTomcat;
public abstract class MyHttpServlet {
//定义常量
public static final String METHOD_GET = "GET";
public static final String METHOD_POST = "POST";
public abstract void doGet(MyRequest request,MyResponse response) throws Exception;
public abstract void doPost(MyRequest request,MyResponse response) throws Exception;
/**
* 根据请求方式来判断调用哪种处理方法
* @param request
* @param response
*/
public void service(MyRequest request,MyResponse response) throws Exception{
if(METHOD_GET.equals(request.getRequestMethod())){
doGet(request,response);
}else if(METHOD_POST.equals(request.getRequestMethod())){
doPost(request,response);
}
}
}
package myTomcat;
import java.util.HashMap;
public class MyMapping {
public static HashMap<String,String> mapping = new HashMap<String,String>();
static {
mapping.put("/mytomcat","com.mashibing.MyServlet");
}
public HashMap<String,String> getMapping(){
return mapping;
}
}
package myTomcat;
import java.io.InputStream;
public class MyRequest {
//请求方法 GET/POST
private String requestMethod;
//请求地址
private String requestUrl;
public MyRequest(InputStream inputStream) throws Exception{
//缓冲区域
byte[] buffer = new byte[1024];
//读取数据的长度
int len = 0;
//定义请求的变量
String str = "";
if((len = inputStream.read(buffer))>0){
str = new String(buffer,0,len);
}
// GET / HTTP/1.1
String data = str.split("\n")[0];
String[] params = data.split(" ");
this.requestMethod = params[0];
this.requestUrl = params[1];
}
public String getRequestMethod() {
return requestMethod;
}
public void setRequestMethod(String requestMethod) {
this.requestMethod = requestMethod;
}
public String getRequestUrl() {
return requestUrl;
}
public void setRequestUrl(String requestUrl) {
this.requestUrl = requestUrl;
}
}
package myTomcat;
import java.io.OutputStream;
public class MyResponse {
private OutputStream outputStream;
public MyResponse(OutputStream outputStream) {
this.outputStream = outputStream;
}
public void write(String str) throws Exception{
StringBuilder builder = new StringBuilder();
builder.append("HTTP/1.1 200 OK\n")
.append("Content-Type:text/html\n")
.append("\r\n")
.append("<html>")
.append("<body>")
.append("<h1>"+str+"</h1>")
.append("</body>")
.append("</html>");
this.outputStream.write(builder.toString().getBytes());
this.outputStream.flush();
this.outputStream.close();
}
}
package myTomcat;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class MyServer {
/**
* 定义服务端的接受程序,接受socket请求
* @param port
*/
public static void startServer(int port) throws Exception{
//定义服务端套接字
ServerSocket serverSocket = new ServerSocket(port);
//定义客户端套接字
Socket socket = null;
while (true){
socket = serverSocket.accept();
//获取输入流和输出流
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
//定义请求对象
MyRequest request = new MyRequest(inputStream);
//定义响应对象
MyResponse response = new MyResponse(outputStream);
String clazz = new MyMapping().getMapping().get(request.getRequestUrl());
if(clazz!=null){
Class<MyServlet> myServletClass = (Class<MyServlet>)Class.forName(clazz);
//根据myServletClass创建对象
MyServlet myServlet = myServletClass.newInstance();
myServlet.service(request,response);
}
}
}
public static void main(String[] args) {
try {
startServer(10086);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package myTomcat;
public class MyServlet extends MyHttpServlet{
@Override
public void doGet(MyRequest request, MyResponse response) throws Exception {
response.write("mytomcat get");
}
@Override
public void doPost(MyRequest request, MyResponse response) throws Exception {
response.write("post tomcat");
}
}
Tomcat本地配置
server location:选择user tomcat选项
doploy path :tomcat安装目录至webapps
web工程
javaresources/src:java代码文件
webcontent:页面文件
webcontent/WEB-INF/lib:jar包
Tomcat优化配置
https://blog.csdn.net/ihuangweiwei/article/details/84059463