【Tomcat学习笔记】12-Tomcat的Mapper机制

说明,为了简洁,这里贴的代码可能有所删减。

【Tomcat学习笔记】2-整体架构 中有介绍过 Tomcat 中 Engine、Host、Context、Wrapper 这四个组件的关系。还是以 http://www.mydomain.com/app/index.html 为例。

300
当我们访问这个网址的时候,Tomcat 如何一步步路由找到对应的 Host、Context、Wrapper 的呢?Tomcat 中维护了一个 Mapper,在收到 Http 请求后,会去 Mapper 中查找对应的 Host、Context 和 Wrapper,放到 request 的 MappingData 中一路带下去。

Mapper的构建过程

【Tomcat学习笔记】11-Tomcat中的JMX

JMX 科普

JMX(Java Management Extensions)其实就是一套标准,定义了一套架构(设计模式或者说API)用于管理和监控Java应用程序。JMX官方介绍


这是 JMX 的架构,可以通过各种协议接入进来,然后通过 MBeanServer 操作各个 MBean.

这里的 MBean 分为静态Bean和动态Bean,静态Bean能力有限,只能用于获取一些静态信息。动态Bean, 可以在运行时改变它的属性,执行它的方法,动态Bean,必须继承 DynamicMBean 接口,动态 Bean 会定义 MBeanAttributeInfo(属性信息)/ MBeanOperationInfo(方法信息)等,然后一起注册到 MBeanServer 中去,使用的时候通过MBServer 获取该 MBean, 拿到属性信息或方法信息,然后通过反射的方式去动态的改变属性,执行方法。

关于DynamicBean最基础的用法可以参考动态MBean:DynamicMBean

后面的介绍假设你已经了解JMX了基本概念和使用方法,

还在整天写if else ?

缘起

在业务团队写代码,经常会遇到这种情况,产品经理来个需求,好的,我们加个字段,加个if else. 谢晞鸣最近总结了一些比 if else 优雅一点的套路,能够让自己代码的逼格看起来稍微高点。很多时候分支是不可避免的,不同的业务,肯定要走不同的分支,我这里所谓的优雅套路,本质上就是用一个 Map 将 “条件””业务处理逻辑“ 两者映射起来。

这里假设我们的项目是基于Spring的。文章中列的代码是不完整的,说明意思即可。

if else

有这样一种业务场景,我们做保险产品项目,不同产品核保的逻辑是不一样的(对年龄、限额、职业、性别等等的要求都不一样),假设有两个字段, productCategory, productSubCategory 用于区分不同类型的保险(万能险、投连险、养老险、产险等)。我们可以这么写

1
2
3
4
5
if (productCategory.equals("XXX")){
processXXX();
} else if(productCategory.equals("YYY")){
processYYY();
}

优雅的套路

我们也可以设计这样一个结构来处理这种业务,将我们的 ”条件”(即产品类型)“业务处理逻辑”(即核保逻辑) 映射起来, 下面是一个很简单的 demo:

【Tomcat学习笔记】10-代码变更时自动部署

一直在入门,但从未精通,所以不敢说深入分析 XXX,顶多就是一个学习笔记,但是是原创,转载请注明出处,好吧,说的好像有人会看一样。
说明,为了简洁,这里贴的代码都有所删减。

在看 ClassLoader 代码的过程中,我发现了 WebappLoader 的 reloadable 属性,通过分析代码,把自动部署的过程摸清楚了。这个属性在开发过程中挺有用的,有时候在Debug的时候改了代码,重启Tomcat又要等半天,reloadable 这个属性就可以派上用场了。

每个 Container 在start的最后,都会执行这样一段代码,ContainerBase#threadStart.

1
2
3
4
5
6
7
8
9
10
11
12
protected void threadStart() {
if (thread != null)
return;
if (backgroundProcessorDelay <= 0)
return;

threadDone = false;
String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
thread = new Thread(new ContainerBackgroundProcessor(), threadName);
thread.setDaemon(true);
thread.start();
}

【Tomcat学习笔记】9-ClassLoader

一直在入门,但从未精通,所以不敢说深入分析 XXX,顶多就是一个学习笔记,但是是原创,转载请注明出处,好吧,说的好像有人会看一样。
说明,为了简洁,这里贴的代码都有所删减。

先来张图:

ClassLoader基础

Java 自带了三个类加载器,BootstrapClassLoader、ExtClassLoader 和 AppClassLoader,它们之间的层级关系如图,上面的 ClassLoader 是下面 ClassLoader 的 parent.不同的 ClassLoader 有不同的职责:

  • BootstrapClassLoader, 引导类加载器,加载JDK最核心的类,比如 rt.jar, java.lang.String, java.lang.Integer 这些类都在这个 JAR 中
  • ExtClassLoader, 扩展类加载器,加载 jre/lib/ext 目录下的类
  • AppClassLoader, 系统类加载器,加载应用程序 classpath 目录下的所有jar和class文件

如果想看 ClassLoader 具体加载了哪些类,可以 getURLs, 然后将它们打印出来

1
2
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
URL[] urls = ((URLClassLoader)Thread.currentThread().getContextClassLoader()).getURLs();

【Tomcat学习笔记】8-Context创建过程(应用的部署过程)

之前说过,Context 和 Wrapper 的创建和其他组件的创建过程有点不一样,这两者没有在 server.xml 中配置,并不是在解析 server.xml 的时候创建的. 谢晞鸣 Debug 代码,发现。。。

HostConfig 是 StandardHost 的一个 LifeCycleListener,在 StandardHost start 的时候,会触发 START_EVENT 事件,
HostConfig 监听到该事件后,。。。。

1
2
3
4
5
6
7
//HostConfig#start
public void start() {
....
if (host.getDeployOnStartup())
deployApps();
...
}

【Tomcat学习笔记】7-分析各个组件的init和start

你TM写这种东西不烦吗?我也很无奈啊,太懒,只能靠写博客、吹牛逼驱动自己看代码啊。

下面分析每个组件时,只分析它初始化自己的那部分逻辑,其它各种如何调用子组件的逻辑就不一一赘述了。

StandardServer#initInternal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
if (getCatalina() != null) {
ClassLoader cl = getCatalina().getParentClassLoader();
// Walk the class loader hierarchy. Stop at the system class loader.
// This will add the shared (if present) and common class loaders
while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
if (cl instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) cl).getURLs();
for (URL url : urls) {
if (url.getProtocol().equals("file")) {
try {
File f = new File (url.toURI());
if (f.isFile() &&
f.getName().endsWith(".jar")) {
ExtensionValidator.addSystemResource(f);
}
} catch (URISyntaxException e) {
// Ignore
} catch (IOException e) {
// Ignore
}
}
}
}
cl = cl.getParent();
}
}

【Tomcat学习笔记】6-shutdown过程分析

缘起

在看 BootStrap 类代码的时候,突然想到一个问题,关闭 Tomcat 的入口也是从 BootStrap 的 main 方法开始的,但是从 main 方法开始执行就会另起了一个进程,它是如何关掉另一个进程的 Tomcat 的呢,不可能是简单的 kill 一个 pid, 因为很多组件都有 destroy 方法要执行。
于是我决定研究一下 shutdown 的过程是如何执行的。