这篇文章将为大家详细讲解有关Tomcat多虚拟主机配置及原理什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。
我们多数的Tomcat用户,对于Tomcat的使用基本使用都是部署应用,浏览器中进行应用的请求。而这个对应用请求的格式,是这个样子:
http://localhost:8080/Web
其中8080是Connector对应的监听端口,Web是对应请求的应用,而localhost就是本次的主角,对应的就是Tomcat中默认包含的一个虚拟主机,对应到Tomcat中的Host容器。
在Tomcat的配置文件server.xml中,默认包含这样的配置
默认情况下,我们所有的应用都部署到了这个虚拟主机上,所以前面对于应用的请求,也就都被Connector转到了localhost这个Host上。
我们再来看虚拟主机这个概念。其相对于实体主机,是在一个机器上虚拟出了多个可供不同站点运行的机制。
在Tomcat中,如果要支持多虚拟主机,配置起来也比较简单,
在Engine的组件内,增加关于Host的配置信息就可以了。对应的各个属性,可以参考默认的localhost主机。
在操作系统的hosts文件中,增加你新创建的虚拟主机名称对应到IP的映射。
可以选择在当前主机中增加类似于AccessLog之类的组件。
重启Tomcat,使改动生效。
假设我们新增的虚拟主机名是remoteHost,此时在浏览器中,我们就可以用
http://remoteHost:port/Webapp
这种形式来访问应用了。
新增虚拟主机的应用部署,可以通过配置主机的appBase属性来指定。
当然,除以上配置外,在Engine容器上,是可以配置一个defaultHost,也就是在Connector把请求交给Engine后,如果对应的Host不能响应请求,就会被转到defaultHost来处理。
此时,你可能会发现,多个虚拟主机之间的应用是隔离的,就和我们要搭个网站购买空间一样,我们只能访问到自己主机对应的资源与内容。这种主机间应用的隔离,在Tomcat内是如何实现的呢?
我们知道,在Tomcat中,整个服务对外提供,是抽象为Service,在server.xml中对应到Service的配置,service的默认实现是StandardService。在实现中,包含这样一个Field的声明:
protected final MapperListener mapperListener =
new MapperListener(mapper, this);
他本质上也相当于一个组件,根据LifeCycle的生命周期进行启动、停止等。以下是其对应的类声明:
public class MapperListener extends LifecycleMBeanBase
implements ContainerListener, LifecycleListener
在Service的start方法中,也会对MapperListener的start进行调用,在mapperListener启动过程中,会将自己注册到Engine的listener中,后续容器的所有生命周期,都会通知到。这里就是观察者模式的使用。(参见这里:和Tomcat学设计模式 | 发布-订阅模式)
Engine engine = (Engine) service.getContainer();
addListeners(engine); // 这里就是注册
Container[] conHosts = engine.findChildren();
for (Container conHost : conHosts) {
Host host = (Host) conHost;
if (!LifecycleState.NEW.equals(host.getState())) {
// Registering the host will register the context and wrappers
registerHost(host);
}
}
我们看到,在启动时,会将Engine下所有的Host注册一下。我们来看这里的注册是在做些啥。
private void registerHost(Host host) {
String[] aliases = host.findAliases();
mapper.addHost(host.getName(), aliases, host);
for (Container container : host.findChildren()) {
if (container.getState().isAvailable()) {
registerContext((Context) container);
}
}
}
这里的mapper,是StandardService中创建的另一个field。这里注册的Host,以及上面方法中对应的registerContext,都被添加到mapper中,用做后面请求处理时的解析。
这里的addHost,最主要的是做了这样一个操作
MappedHost[] newHosts = new MappedHost[hosts.length + 1];
MappedHost newHost = new MappedHost(name, host);
if (insertMap(hosts, newHosts, newHost)) {
hosts = newHosts;
}
后面注册Context时,方式基本一致。而到了应用请求解析时,则是类似下面的流程:(请求处理可以参考:和Tomcat学设计模式 | Facade模式与请求处理,Tomcat是如何处理请求参数的?)
在Connector将请求传递到CoyoteAdaptor时,会在请求头处理之后,对request和response对象做一些后处理,以此传递给peipeline,进行请求。
在这一过程中,会进行这样的一段处理:
connector.getService().getMapper().map(serverName, decodedURI,
version, request.getMappingData());
就会使用到前面为service关联的Mapper,以此根据request的mappingData进行判断,把请求URI和context建立映射。这个时候,前面说的注册的那些东西就要被用到了。
// Virtual host mapping
MappedHost[] hosts = this.hosts;
MappedHost mappedHost = exactFindIgnoreCase(hosts, host);
if (mappedHost == null) {
if (defaultHostName == null) {
return;
}
mappedHost = exactFind(hosts, defaultHostName);
if (mappedHost == null) {
return;
}
}
mappingData.host = mappedHost.object;
// Context mapping
ContextList contextList = mappedHost.contextList;
MappedContext[] contexts = contextList.contexts;
int pos = find(contexts, uri);
if (pos == -1) {
return;
}
上面几处标红的地方,hosts就是前面注册Host时候变更的对象,defaultHostName是开始时提到的,为Engine配置的默认主机,如果在其它主机找不到资源时,使用它来响应。我们看到,应用的mapping,是以Host为基础,从这里再寻找其对应的ContextList的。所以不同主机的应用就被隔离开了。
以上,就是Tomcat内多虚拟主机配置,以及其内部应用隔离和注册的原理。
在应用部署阶段,就会根据主机以及之上部署的应用进行分别register
在应用请求时,再根据部署时建立的mapping关系,去寻找对应主机上的Context
可以为Engine进行defaultHost的配置,在特定主机上找不到资源时以此响应
关于Tomcat多虚拟主机配置及原理什么就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。