Tomcat8.5.50
Tomcat 核心思想
servlet? web容器/servlet容器 tomcat是servlet的容器,每个请求是servlet ,每个servlet里面包含了request,response
tomcat 包含了很多servlet tomcat
使用Http11NioProtocol
Http11NioProtocol
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<Context path="/" docBase="/root/tomcat/apache-tomcat-8.0.30/fantasy" /> 以web项目为单位加载servlet
Context: A Context represents a web application. (代表一个web项目)
看server.xml,每一个标签都有对应的java 类,其他源码也可以参照如此学习
Context:
public interface Context extends Container, ContextBind {
StandardContext
public boolean loadOnStartup(Container children[]) { // Collect "load on startup" servlets that need to be initialized TreeMap<Integer, ArrayList<Wrapper>> map = new TreeMap<>(); for (int i = 0; i < children.length; i++) { Wrapper wrapper = (Wrapper) children[i]; int loadOnStartup = wrapper.getLoadOnStartup(); if (loadOnStartup < 0) continue; Integer key = Integer.valueOf(loadOnStartup); ArrayList<Wrapper> list = map.get(key); if (list == null) { list = new ArrayList<>(); map.put(key, list); }
//将每个servlet添加到容器中 list.add(wrapper); } // Load the collected "load on startup" servlets for (ArrayList<Wrapper> list : map.values()) { for (Wrapper wrapper : list) { try { wrapper.load(); } catch (ServletException e) { getLogger().error(sm.getString("standardContext.loadOnStartup.loadException", getName(), wrapper.getName()), StandardWrapper.getRootCause(e)); // NOTE: load errors (including a servlet that throws // UnavailableException from the init() method) are NOT // fatal to application startup // unless failCtxIfServletStartFails="true" is specified if(getComputedFailCtxIfServletStartFails()) { return false; } } } } return true; }
Wrapper 是否是Servlet?
public class ContextConfig implements LifecycleListener {
protected void webConfig() {
WebXmlParser webXmlParser = new WebXmlParser(context.getXmlNamespaceAware(),
context.getXmlValidation(), context.getXmlBlockExternal());
Set<WebXml> defaults = new HashSet<>();
defaults.add(getDefaultWebXmlFragment(webXmlParser));
WebXml webXml = createWebXml();
// Parse context level web.xml
InputSource contextWebXml = getContextWebXmlSource();
if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {
ok = false;
}
}
//1 创建webXml
WebXml webXml = createWebXml();
public class WebXml {
//加载web.xml
private static final StringManager sm =
StringManager.getManager(Constants.PACKAGE_NAME);
}
public class Constants {
public static final String PACKAGE_NAME =
Constants.class.getPackage().getName();
public static final String WEB_XML_LOCATION = "/WEB-INF/web.xml";
}
getContextWebXmlSource
stream = servletContext.getResourceAsStream
(Constants.ApplicationWebXml);
try {
url = servletContext.getResource(
Constants.ApplicationWebXml);
} catch (MalformedURLException e) {
log.error(sm.getString("contextConfig.applicationUrl"));
}
Constants { public static final String Package = "org.apache.catalina.startup"; public static final String ApplicationContextXml = "META-INF/context.xml";
//找到 web-inf/web.xml public static final String ApplicationWebXml = "/WEB-INF/web.xml"; public static final String DefaultContextXml = "conf/context.xml"; public static final String DefaultWebXml = "conf/web.xml"; public static final String HostContextXml = "context.xml.default"; public static final String HostWebXml = "web.xml.default"; public static final String WarTracker = "/META-INF/war-tracker";
// Step 9. Apply merged web.xml to Context if (ok) { configureContext(webXml); } // 加载web.xml,将servlet 进行包装 ,包装为wrapper for (ServletDef servlet : webxml.getServlets().values()) { Wrapper wrapper = context.createWrapper(); // Description is ignored // Display name is ignored // Icons are ignored // jsp-file gets passed to the JSP Servlet as an init-param if (servlet.getLoadOnStartup() != null) { wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue()); } if (servlet.getEnabled() != null) { wrapper.setEnabled(servlet.getEnabled().booleanValue()); } wrapper.setName(servlet.getServletName()); Map<String,String> params = servlet.getParameterMap(); for (Entry<String, String> entry : params.entrySet()) { wrapper.addInitParameter(entry.getKey(), entry.getValue()); } wrapper.setRunAs(servlet.getRunAs()); Set<SecurityRoleRef> roleRefs = servlet.getSecurityRoleRefs(); for (SecurityRoleRef roleRef : roleRefs) { wrapper.addSecurityReference( roleRef.getName(), roleRef.getLink()); } wrapper.setServletClass(servlet.getServletClass()); MultipartDef multipartdef = servlet.getMultipartDef(); if (multipartdef != null) { if (multipartdef.getMaxFileSize() != null && multipartdef.getMaxRequestSize()!= null && multipartdef.getFileSizeThreshold() != null) { wrapper.setMultipartConfigElement(new MultipartConfigElement( multipartdef.getLocation(), Long.parseLong(multipartdef.getMaxFileSize()), Long.parseLong(multipartdef.getMaxRequestSize()), Integer.parseInt( multipartdef.getFileSizeThreshold()))); } else { wrapper.setMultipartConfigElement(new MultipartConfigElement( multipartdef.getLocation())); } } if (servlet.getAsyncSupported() != null) { wrapper.setAsyncSupported( servlet.getAsyncSupported().booleanValue()); } wrapper.setOverridable(servlet.isOverridable()); context.addChild(wrapper); }
监听端口
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
Connector查找监听端口
第一步 入口类:Bootstrap
//Bootstrap 当执行命令的时候执行的改方法 public static void main(String args[]) { synchronized (daemonLock) { if (daemon == null) { // Don't set daemon until init() has completed Bootstrap bootstrap = new Bootstrap(); try { bootstrap.init(); } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } daemon = bootstrap; } else { // When running as a service the call to stop will be on a new // thread so make sure the correct class loader is used to // prevent a range of class not found exceptions. Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } } try { String command = "start"; if (args.length > 0) { command = args[args.length - 1]; } if (command.equals("startd")) { args[args.length - 1] = "start"; daemon.load(args); daemon.start(); } else if (command.equals("stopd")) { args[args.length - 1] = "stop"; daemon.stop(); } else if (command.equals("start")) { daemon.setAwait(true); daemon.load(args); daemon.start(); if (null == daemon.getServer()) { System.exit(1); } } else if (command.equals("stop")) { daemon.stopServer(args); } else if (command.equals("configtest")) { daemon.load(args); if (null == daemon.getServer()) { System.exit(1); } System.exit(0); } else { log.warn("Bootstrap: command \"" + command + "\" does not exist."); } } catch (Throwable t) { // Unwrap the Exception for clearer error reporting if (t instanceof InvocationTargetException && t.getCause() != null) { t = t.getCause(); } handleThrowable(t); t.printStackTrace(); System.exit(1); } }
2 启动命令;
if (command.equals("startd")) { args[args.length - 1] = "start";
// 加载 tomcat 下面的conf/server.xml daemon.load(args);
// 启动 基于对这些对象合作完成相应的功能 daemon.start();
}
private void load(String[] arguments) throws Exception { // Call the load() method String methodName = "load"; Object param[]; Class<?> paramTypes[]; if (arguments==null || arguments.length==0) { paramTypes = null; param = null; } else { paramTypes = new Class[1]; paramTypes[0] = arguments.getClass(); param = new Object[1]; param[0] = arguments; } Method method = catalinaDaemon.getClass().getMethod(methodName, paramTypes); if (log.isDebugEnabled()) { log.debug("Calling startup class " + method); } method.invoke(catalinaDaemon, param); }
public class Catalina {
// Start a new server instance. 创建一个server对象
public void load() {} }
file = configFile();
//加载tomcat的server.xml文件
protected String configFile = "conf/server.xml";
// Start the new server 创建server并初始化
try {
getServer().init();
}
//生命周期Lifecycle
//默认实现类:LifecycleBase
//initInternal()
//StandardServer->initInternal->globalNamingResources
// Initialize our defined Services
//初始化services是
for (int i = 0; i < services.length; i++) {
//1 初始化service LifecycleBase->init->initInternal->StandardService->initInternal
services[i].init();
//2 初始化Connector LifecycleBase->init->initInternal->Connector->initInternal
synchronized (connectorsLock) {
for (Connector connector : connectors) {
connector.init();
}
//3 初始化protocol protocolHandler.init()->AbstractProtocol.init()->endpoint.init()->AbstractEndpoint
if (bindOnInit) {
bind();
//选择不同的IO tomcat8 默认NIO tomcat7默认 BIO 在server.xml中的protocol="HTTP/1.1" 可以查看默认IO方式
在Connector 中构造函数public Connector(String protocol)->setProtocol 查看具体实现IO方式
bindState = BindState.BOUND_ON_INIT;
}
}
Host发布方式
HostConfig -deployApps
protected void deployApps() { File appBase = host.getAppBaseFile(); File configBase = host.getConfigBaseFile(); String[] filteredAppPaths = filterAppPaths(appBase.list()); // Deploy XML descriptors from configBase 基于xml发布 deployDescriptors(configBase, configBase.list()); // Deploy WARs 基于war发布 deployWARs(appBase, filteredAppPaths); // Deploy expanded folders 文件夹方式发布 deployDirectories(appBase, filteredAppPaths); }
Digester解析 xml文件