java protected abstract static class MapElement<T> {
public final String name;
public final T object;
public MapElement(String name, T object) {
this.name = name;
this.object = object;
}
}
// ------------
java protected static final class ContextVersion extends MapElement<Context> {
public final String path;
public final int slashCount;
public final WebResourceRoot resources;
public String[] welcomeResources;
public MappedWrapper defaultWrapper = null;
public MappedWrapper[] exactWrappers = new MappedWrapper[0];
public MappedWrapper[] wildcardWrappers = new MappedWrapper[0];
public MappedWrapper[] extensionWrappers = new MappedWrapper[0];
public int nesting = 0;
private volatile boolean paused;
public ContextVersion(String version, String path, int slashCount, Context context, WebResourceRoot resources,
String[] welcomeResources) {
super(version, context);
this.path = path;
this.slashCount = slashCount;
this.resources = resources;
this.welcomeResources = welcomeResources;
}
public boolean isPaused() {
return paused;
}
public void markPaused() {
paused = true;
}
}
javaprotected static final class MappedHost extends MapElement<Host> {
public volatile ContextList contextList;
/**
* Link to the "real" MappedHost, shared by all aliases.
*/
private final MappedHost realHost;
/**
* Links to all registered aliases, for easy enumeration. This field is available only in the "real" MappedHost.
* In an alias this field is <code>null</code>.
*/
private final List<MappedHost> aliases;
/**
* Constructor used for the primary Host
*
* @param name The name of the virtual host
* @param host The host
*/
public MappedHost(String name, Host host) {
super(name, host);
realHost = this;
contextList = new ContextList();
aliases = new CopyOnWriteArrayList<>();
}
/**
* Constructor used for an Alias
*
* @param alias The alias of the virtual host
* @param realHost The host the alias points to
*/
public MappedHost(String alias, MappedHost realHost) {
super(alias, realHost.object);
this.realHost = realHost;
this.contextList = realHost.contextList;
this.aliases = null;
}
public boolean isAlias() {
return realHost != this;
}
public MappedHost getRealHost() {
return realHost;
}
public String getRealHostName() {
return realHost.name;
}
public Collection<MappedHost> getAliases() {
return aliases;
}
public void addAlias(MappedHost alias) {
aliases.add(alias);
}
public void addAliases(Collection<? extends MappedHost> c) {
aliases.addAll(c);
}
public void removeAlias(MappedHost alias) {
aliases.remove(alias);
}
}
java protected static final class MappedContext extends MapElement<Void> {
public volatile ContextVersion[] versions;
public MappedContext(String name, ContextVersion firstVersion) {
super(name, null);
this.versions = new ContextVersion[] { firstVersion };
}
}
java protected static class MappedWrapper extends MapElement<Wrapper> {
public final boolean jspWildCard;
public final boolean resourceOnly;
public MappedWrapper(String name, Wrapper wrapper, boolean jspWildCard, boolean resourceOnly) {
super(name, wrapper);
this.jspWildCard = jspWildCard;
this.resourceOnly = resourceOnly;
}
}
这四个类是包含关系,一条链。
Mapper 的构建过程是在 MapperListener 中完成的, MapperListener 实现了 Tomcat 的生命周期接口,在 StandardService 启动的时候会调用 MapperListener 的 start 方法,这里会去构建 Mapper. MapperListener 也实现了 ContainerListener 和 LifecycleListener 接口,在发生容器事件和生命周期事件的时候,会往 Mapper 中添加或删除一些映射。
java@Override
public void containerEvent(ContainerEvent event) {
// 处理容器事件的方法
if (Container.ADD_CHILD_EVENT.equals(event.getType())) {
// 如果是添加子容器事件
Container child = (Container) event.getData();
addListeners(child);
// 如果子容器已经启动,则在这里注册子容器(根据子容器类型执行不同的注册操作)
if (child.getState().isAvailable()) {
if (child instanceof Host) {
// 如果子容器是 Host 类型
registerHost((Host) child);
} else if (child instanceof Context) {
// 如果子容器是 Context 类型
registerContext((Context) child);
} else if (child instanceof Wrapper) {
// 如果子容器是 Wrapper 类型
// 只有当 Context 已经启动时才注册 Wrapper
if (child.getParent().getState().isAvailable()) {
registerWrapper((Wrapper) child);
}
}
}
} else if (Container.REMOVE_CHILD_EVENT.equals(event.getType())) {
// 如果是移除子容器事件
Container child = (Container) event.getData();
removeListeners(child);
// 不需要取消注册,生命周期监听器会在子容器停止时处理此操作
} else if (Host.ADD_ALIAS_EVENT.equals(event.getType())) {
// 如果是添加主机别名事件
// 处理动态添加主机别名
mapper.addHostAlias(((Host) event.getSource()).getName(), event.getData().toString());
} else if (Host.REMOVE_ALIAS_EVENT.equals(event.getType())) {
// 如果是移除主机别名事件
// 处理动态移除主机别名
mapper.removeHostAlias(event.getData().toString());
} else if (Wrapper.ADD_MAPPING_EVENT.equals(event.getType())) {
// 如果是添加映射事件
// 处理动态添加映射器
Wrapper wrapper = (Wrapper) event.getSource();
Context context = (Context) wrapper.getParent();
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
String version = context.getWebappVersion();
String hostName = context.getParent().getName();
String wrapperName = wrapper.getName();
String mapping = (String) event.getData();
boolean jspWildCard = ("jsp".equals(wrapperName) && mapping.endsWith("/*"));
mapper.addWrapper(hostName, contextPath, version, mapping, wrapper, jspWildCard,
context.isResourceOnlyServlet(wrapperName));
} else if (Wrapper.REMOVE_MAPPING_EVENT.equals(event.getType())) {
// 如果是移除映射事件
// 处理动态移除映射器
Wrapper wrapper = (Wrapper) event.getSource();
Context context = (Context) wrapper.getParent();
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
String version = context.getWebappVersion();
String hostName = context.getParent().getName();
String mapping = (String) event.getData();
mapper.removeWrapper(hostName, contextPath, version, mapping);
} else if (Context.ADD_WELCOME_FILE_EVENT.equals(event.getType())) {
// 如果是添加欢迎文件事件
// 处理动态添加欢迎文件
Context context = (Context) event.getSource();
String hostName = context.getParent().getName();
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
String welcomeFile = (String) event.getData();
mapper.addWelcomeFile(hostName, contextPath, context.getWebappVersion(), welcomeFile);
} else if (Context.REMOVE_WELCOME_FILE_EVENT.equals(event.getType())) {
// 如果是移除欢迎文件事件
// 处理动态移除欢迎文件
Context context = (Context) event.getSource();
String hostName = context.getParent().getName();
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
String welcomeFile = (String) event.getData();
mapper.removeWelcomeFile(hostName, contextPath, context.getWebappVersion(), welcomeFile);
} else if (Context.CLEAR_WELCOME_FILES_EVENT.equals(event.getType())) {
// 如果是清除欢迎文件事件
// 处理动态清除欢迎文件
Context context = (Context) event.getSource();
String hostName = context.getParent().getName();
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
String version = context.getWebappVersion();
mapper.clearWelcomeFiles(hostName, contextPath, version);
}
}
javaprivate 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);
}
}
// 默认主机可能已更改
findDefaultHost();
if (log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.registerHost", host.getName(), domain, service));
}
}
/**
* 注销主机。
*/
private void unregisterHost(Host host) {
// 获取主机名称
String hostname = host.getName();
// 从映射器中移除主机
mapper.removeHost(hostname);
// 默认主机可能已更改
findDefaultHost();
if (log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.unregisterHost", hostname, domain, service));
}
}
/**
* 注销包装器。
*/
private void unregisterWrapper(Wrapper wrapper) {
// 获取包装器所在的上下文和相关信息
Context context = ((Context) wrapper.getParent());
String contextPath = context.getPath();
String wrapperName = wrapper.getName();
// 如果上下文路径是根路径,将其设置为空字符串
if ("/".equals(contextPath)) {
contextPath = "";
}
String version = context.getWebappVersion();
String hostName = context.getParent().getName();
// 获取包装器的映射路径数组
String[] mappings = wrapper.findMappings();
// 遍历映射路径数组,从映射器中移除对应的映射
for (String mapping : mappings) {
mapper.removeWrapper(hostName, contextPath, version, mapping);
}
if (log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.unregisterWrapper", wrapperName, contextPath, service));
}
}
/**
* 注册上下文。
*/
private void registerContext(Context context) {
// 获取上下文路径
String contextPath = context.getPath();
// 如果上下文路径是根路径,将其设置为空字符串
if ("/".equals(contextPath)) {
contextPath = "";
}
Host host = (Host) context.getParent();
// 获取上下文的资源、欢迎文件和包装器列表
WebResourceRoot resources = context.getResources();
String[] welcomeFiles = context.findWelcomeFiles();
List<WrapperMappingInfo> wrappers = new ArrayList<>();
// 遍历上下文的子容器
for (Container container : context.findChildren()) {
// 准备包装器的映射信息,并添加到包装器列表中
prepareWrapperMappingInfo(context, (Wrapper) container, wrappers);
if (log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.registerWrapper", container.getName(), contextPath, service));
}
}
// 将上下文和相关信息添加到映射器中
mapper.addContextVersion(host.getName(), host, contextPath, context.getWebappVersion(), context, welcomeFiles,
resources, wrappers);
if (log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.registerContext", contextPath, service));
}
}
/**
* 注销上下文。
*/
private void unregisterContext(Context context) {
// 获取上下文路径
String contextPath = context.getPath();
// 如果上下文路径是根路径,将其设置为空字符串
if ("/".equals(contextPath)) {
contextPath = "";
}
String hostName = context.getParent().getName();
// 如果上下文已暂停,暂停上下文的版本;否则从映射器中移除上下文的版本
if (context.getPaused()) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.pauseContext", contextPath, service));
}
mapper.pauseContextVersion(context, hostName, contextPath, context.getWebappVersion());
} else {
if (log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.unregisterContext", contextPath, service));
}
mapper.removeContextVersion(context, hostName, contextPath, context.getWebappVersion());
}
}
/**
* 注册包装器。
*/
private void registerWrapper(Wrapper wrapper) {
// 获取包装器所在的上下文、上下文路径、版本和主机名称
Context context = ((Context) wrapper.getParent());
String contextPath = context.getPath();
String version = context.getWebappVersion();
String hostName = context.getParent().getName();
// 准备包装器的映射信息,并添加到映射器中
List<WrapperMappingInfo> mappingInfoList = new ArrayList<>();
prepareWrapperMappingInfo(context, wrapper, mappingInfoList);
mapper.addWrappers(hostName, contextPath, version, mappingInfoList);
if (log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.registerWrapper", wrapper.getName(), contextPath, service));
}
}
registerHost(Host host) 方法:
unregisterHost(Host host) 方法:
unregisterWrapper(Wrapper wrapper) 方法:
registerContext(Context context) 方法:
unregisterContext(Context context) 方法:
registerWrapper(Wrapper wrapper) 方法:
本文作者:yowayimono
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!