Tomca组件结构
connector:主要负责接受浏览器发送过来的tcp连接请求,创建一个request和response
container:接受request和response,并开启线程处理请求封装结果
service:结合connector和container,对外提供接口服务,一个service可以有多个connector(多种连接协议)和一个container(engine,可以理解为servlet容器)
server:为service提供生存环境,负责他的生命周期,它可以包含多个service服务
Tomcat容器结构
Engine:servlect的顶层容器,包含一个或多个Host子容器;
Host:虚拟主机,负责web应用的部署和context的创建
Context:web应用上下文,包含多个wrapper,负责web配置的解析、管理所有的web资源
Wrapper:最底层的容器,是对servlet的封装,负责servlet实例的创建、执行、销毁
Tomcat启动过程
Tomcat启动时,执行启动脚本startup.sh->catalina.sh->Bootstrap->Bootstrap.main方法
public static void main(String args[]) {
// ....
if (daemon == null) {
// Don't set daemon until init() has completed
Bootstrap bootstrap = new Bootstrap();
try {
// 1)如果daemon是空的话,先执行init方法
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
}
// ....
// 2)不同命令会调用不同daemon的不同方法,daemon是Bootstrap
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);
// 3)若命令是start,调用Boostrap的load方法和start方法
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.");
}
// ...
}
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;
}
// 4)此处通过反射调用,catalinaDaemon的load方法,catalinaDaemon是啥呢?
Method method =
catalinaDaemon.getClass().getMethod(methodName, paramTypes);
if (log.isDebugEnabled()) {
log.debug("Calling startup class " + method);
}
method.invoke(catalinaDaemon, param);
}
// 1.1) Boostrap的init方法会在main中先执行,由此可知catalinaDaemon就是Catalina类
public void init() throws Exception {
// ...
Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.getConstructor().newInstance();
// ...
catalinaDaemon = startupInstance;
}
public void start() throws Exception {
if (catalinaDaemon == null) {
init();
}
Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
method.invoke(catalinaDaemon, (Object [])null);
}
1. Catalina.load()
所以最后Bootstrap.main()->Catalina.load(),load方法中主要做了2个事情:
- 创建Digester类,解析conf/server.xml文件
- 调用server.init()进行初始化server
protected String configFile = "conf/server.xml";
protected File configFile() {
File file = new File(configFile);
if (!file.isAbsolute()) {
file = new File(Bootstrap.getCatalinaBase(), configFile);
}
return file;
}
public void load() {
// 1)Create and execute our Digester
Digester digester = createStartDigester();
InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
try {
// 1.1)创建文件
file = configFile();
inputStream = new FileInputStream(file);
inputSource = new InputSource(file.toURI().toURL().toString());
// ...
inputSource.setByteStream(inputStream);
digester.push(this);
// 1.2) 解析文件:conf/server.xml
digester.parse(inputSource);
// ...
} catch (Exception e) {
log.warn("Catalina.start using " + getConfigFile() + ": " , e);
return;
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// Ignore
}
}
}
getServer().setCatalina(this);
getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
// ...
// 2) Start the new server
try {
getServer().init();
} catch (LifecycleException e) {
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
throw new java.lang.Error(e);
} else {
log.error("Catalina.start", e);
}
}
// ...
}
getServer.init()->LiftcycleBase.init():
- 更新server的LifecycleState,并发布状态变化事件
- 调用StandServer.initInternal()进行server的初始化
public abstract class LifecycleBase implements Lifecycle {
@Override
public final synchronized void init() throws LifecycleException {
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
// 1) 设置状态为initalizing,并发布状态变化的事件
// LifecycleState有12种状态,每种状态都有对应的Event
setStateInternal(LifecycleState.INITIALIZING, null, false);
// 2)初始化
initInternal();
// 3)设置状态为initialized,并发布状态变化事件
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
handleSubClassException(t, "lifecycleBase.initFail", toString());
}
}
private synchronized void setStateInternal(LifecycleState state, Object data, boolean check)
throws LifecycleException {
// ...
// 1)设置新状态
this.state = state;
// 2)获取状态的事件并发布
String lifecycleEvent = state.getLifecycleEvent();
if (lifecycleEvent != null) {
fireLifecycleEvent(lifecycleEvent, data);
}
}
protected void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(this, type, data);
// 循环监听:lifecycleListeners并发布事件LifecycleEvent ??监听器有哪些?如何初始化的?
for (LifecycleListener listener : lifecycleListeners) {
listener.lifecycleEvent(event);
}
}
}
public enum LifecycleState {
NEW(false, null),
INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT),
INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT),
STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT),
STARTING(true, Lifecycle.START_EVENT),
STARTED(true, Lifecycle.AFTER_START_EVENT),
STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT),
STOPPING(false, Lifecycle.STOP_EVENT),
STOPPED(false, Lifecycle.AFTER_STOP_EVENT),
DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT),
DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT),
FAILED(false, null);
private final boolean available;
private final String lifecycleEvent;
}
protected void initInternal() throws LifecycleException {
super.initInternal();
// Initialize our defined Services
for (Service service : services) {
service.init();
}
}
StandServer.initInternal()->LeftcycelBase.init()->StandService.initeInternal(),standService.initernel()主要实现:
- 初始化engine
- 初始化connectors
protected void initInternal() throws LifecycleException {
super.initInternal();
// 1) 初始化engine
if (engine != null) {
engine.init();
}
// ...
synchronized (connectorsLock) {
for (Connector connector : connectors) {
try {
// 2)初始化connectors
connector.init();
} catch (Exception e) {
// ...
}
}
}
}
初始化engine.init()->LifecycleBase.init()->StandardEngine.initernal()
初始化connetor.init()->LiftcycleBase.init()->Connector.initernal()->ProtocolHandler.init()
2. Catalina.start()
public void start() {
// ...
long t1 = System.nanoTime();
// 1) Start the new server
try {
getServer().start();
} catch (LifecycleException e) {
log.fatal(sm.getString("catalina.serverStartFail"), e);
try {
getServer().destroy();
} catch (LifecycleException e1) {
log.debug("destroy() failed for failed Server ", e1);
}
return;
}
// 2) Register shutdown hook
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(shutdownHook);
// If JULI is being used, disable JULI's shutdown hook since
// shutdown hooks run in parallel and log messages may be lost
// if JULI's hook completes before the CatalinaShutdownHook()
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager) logManager).setUseShutdownHook(
false);
}
}
if (await) {
await();
stop();
}
}
Catalina.start()->LifecycleBase.start()->StandardServer.startIniternal()
@Override
protected void startInternal() throws LifecycleException {
// 1)更新server状态为starting,并发布状态变更事件
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
globalNamingResources.start();
// 2)初始化service
synchronized (servicesLock) {
for (Service service : services) {
service.start();
}
}
}
StandardServer.startIniternal()->LifecycleBase.start()->StandardService.startIniternal()
protected void startInternal() throws LifecycleException {
// 1) Start our defined Container first
if (engine != null) {
synchronized (engine) {
engine.start();
}
}
// ...
// 2) Start our defined Connectors second
synchronized (connectorsLock) {
for (Connector connector: connectors) {
try {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
connector.start();
}
} catch (Exception e) {
log.error(sm.getString(
"standardService.connector.startFailed",
connector), e);
}
}
}
}
1)engine.start()->LifecycleBase.start()->engine.startInternal()->ContainerBase.startInternal()
protected synchronized void startInternal() throws LifecycleException {
// ...
// 1)启动子容器们的任务提交到线程池中
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
for (Container child : children) {
results.add(startStopExecutor.submit(new StartChild(child)));
}
MultiThrowable multiThrowable = null;
// 2)采用异步获取结果的方式,启动容器的结果
for (Future<Void> result : results) {
try {
result.get();
} catch (Throwable e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
if (multiThrowable == null) {
multiThrowable = new MultiThrowable();
}
multiThrowable.add(e);
}
}
// ...
// Start our thread
threadStart();
}
StandardEngine的子容器是Host,所以:ContainerBase.startInternal()->LifecycleBase.start()->发布事件->HostConfig监听此事件
public void lifecycleEvent(LifecycleEvent event) {
// ...
if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
check();
} else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
beforeStart();
} else if (event.getType().equals(Lifecycle.START_EVENT)) {
// 调用这个方法
start();
} else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
stop();
}
}
public void start() {
// 发布项目
if (host.getDeployOnStartup()) {
deployApps();
}
}
protected void deployApps() {
File appBase = host.getAppBaseFile();
File configBase = host.getConfigBaseFile();
String[] filteredAppPaths = filterAppPaths(appBase.list());
// Deploy XML descriptors from configBase
deployDescriptors(configBase, configBase.list());
// 发布war包项目
deployWARs(appBase, filteredAppPaths);
// Deploy expanded folders
deployDirectories(appBase, filteredAppPaths);
}
protected void deployWARs(File appBase, String[] files) {
// ...
for (String file : files) {
// ...
File war = new File(appBase, file);
if (file.toLowerCase(Locale.ENGLISH).endsWith(".war") && war.isFile() && !invalidWars.contains(file)) {
ContextName cn = new ContextName(file, true);
if (tryAddServiced(cn.getName())) {
try {
// ...
// 发布war的任务提交到线程池中
results.add(es.submit(new DeployWar(this, cn, war)));
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
removeServiced(cn.getName());
throw t;
}
}
}
}
// 异步获取发布结果
for (Future<?> result : results) {
try {
result.get();
} catch (Exception e) {
log.error(sm.getString("hostConfig.deployWar.threaded.error"), e);
}
}
}
private static class DeployWar implements Runnable {
// ...
@Override
public void run() {
// 发布单个war
config.deployWAR(cn, war);
}
}
protected void deployWAR(ContextName cn, File war) {
// ...
Context context = null;
boolean deployThisXML = isDeployThisXML(war, cn);
try {
// ...
context.addLifecycleListener(listener);
context.setName(cn.getName());
context.setPath(cn.getPath());
context.setWebappVersion(cn.getVersion());
context.setDocBase(cn.getBaseName() + ".war");
// 添加StandardContext到当前Host中
host.addChild(context);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString("hostConfig.deployWar.error", war.getAbsolutePath()), t);
} finally {
// ...
}
// ...
}
到这里StandardContext算是创建了,并且是Host的子容器,然后回到LifecycleBase.start(),执行startInternal()->StandardHaost.startInternal()->ContainerBase.startInternal(),最终又回到父类ContainerBase的startIniternal()方法中,重复执行StandardContext的事件监听ContextConfig和startInternal():
-
ContextConfig的事件监听中,会加载项目的web.xml文件
@Override public void lifecycleEvent(LifecycleEvent event) { // ... // Process the event that has occurred if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) { // 加载web.xml文件 configureStart(); } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) { beforeStart(); } else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) { // Restore docBase for management tools if (originalDocBase != null) { context.setDocBase(originalDocBase); } } else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) { configureStop(); } else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) { init(); } else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) { destroy(); } } protected synchronized void configureStart() { // ... webConfig(); // ... } // 为了简单理解,省略了很多步骤的代码 protected void webConfig() { // ... WebXml webXml = createWebXml(); // ... if (!webXml.isMetadataComplete()) { // ... // Step 9. Apply merged web.xml to Context if (ok) { configureContext(webXml); } } // ... } // 解析web.xml配置的信息 private void configureContext(WebXml webxml) { // ... // 加载Filter们 for (FilterDef filter : webxml.getFilters().values()) { if (filter.getAsyncSupported() == null) { filter.setAsyncSupported("false"); } context.addFilterDef(filter); } for (FilterMap filterMap : webxml.getFilterMappings()) { context.addFilterMap(filterMap); } // ... // 加载Servlet们 for (ServletDef servlet : webxml.getServlets().values()) { Wrapper wrapper = context.createWrapper(); // ... wrapper.setOverridable(servlet.isOverridable()); // 添加到StandardContext的child中,且之后在startInternal()中初始化 context.addChild(wrapper); } for (Entry<String, String> entry : webxml.getServletMappings().entrySet()) { context.addServletMappingDecoded(entry.getKey(), entry.getValue()); } // 加载默认页面 for (String welcomeFile : webxml.getWelcomeFiles()) { if (welcomeFile != null && welcomeFile.length() > 0) { context.addWelcomeFile(welcomeFile); } } // ... }
-
进入StandardContext.startIniternal()中
protected synchronized void startInternal() throws LifecycleException { // ... // Call ServletContainerInitializers,调用ServletContainerInitializers的方法 for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry : initializers.entrySet()) { try { entry.getKey().onStartup(entry.getValue(), getServletContext()); } catch (ServletException e) { log.error(sm.getString("standardContext.sciFail"), e); ok = false; break; } } // 运行项目中配置的监听器方法 if (ok) { if (!listenerStart()) { log.error(sm.getString("standardContext.listenerFail")); ok = false; } } // ... // 初始化servlet们 if (ok) { if (!loadOnStartup(findChildren())){ log.error(sm.getString("standardContext.servletFail")); ok = false; } } } public boolean listenerStart() { // ... for (Object instance : instances) { if (!(instance instanceof ServletContextListener)) { continue; } ServletContextListener listener = (ServletContextListener) instance; try { fireContainerEvent("beforeContextInitialized", listener); if (noPluggabilityListeners.contains(listener)) { // 应用上下文监听 listener.contextInitialized(tldEvent); } else { listener.contextInitialized(event); } fireContainerEvent("afterContextInitialized", listener); } catch (Throwable t) { // ... } } return ok; } public boolean loadOnStartup(Container children[]) { // ... for (ArrayList<Wrapper> list : map.values()) { for (Wrapper wrapper : list) { try { // 循环加载servlets wrapper.load(); } catch (ServletException e) { // ... } } } return true; }
监听:这个监听就是web.xml中配置的,就是启动spring容器的入口
<!-- listener --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
初始化servlet:StandardContext.loadOnStartup()->StandardWrapper.load()
@Override public synchronized void load() throws ServletException { instance = loadServlet(); if (!instanceInitialized) { initServlet(instance); } // ... } private synchronized void initServlet(Servlet servlet) throws ServletException { // ... servlet.init(facade); // ... }
最后调用的是:GenericServlet.init()
@Override public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); }
GenericServlet.init()->HttpServletBean.init()->FramworkServlet.initServletBean(),此时已经进入spring-webmvc.jar
public final void init() throws ServletException { // ... this.initServletBean(); // ... }
protected final void initServletBean() throws ServletException { // ... try { // 初始化spring容器 this.webApplicationContext = this.initWebApplicationContext(); this.initFrameworkServlet(); } // ... } protected WebApplicationContext initWebApplicationContext() { // ... if (!this.refreshEventReceived) { // 此处就是启动DispatcherServlet七大组件的地方!!! this.onRefresh(wac); } // ... return wac; }
最后的最后进入:DispatcherServlet.onRefresh()
protected void onRefresh(ApplicationContext context) { this.initStrategies(context); } protected void initStrategies(ApplicationContext context) { this.initMultipartResolver(context); this.initLocaleResolver(context); this.initThemeResolver(context); this.initHandlerMappings(context); this.initHandlerAdapters(context); this.initHandlerExceptionResolvers(context); this.initRequestToViewNameTranslator(context); this.initViewResolvers(context); this.initFlashMapManager(context); }
最后附上一张DispatcherSerlvet的类图:
2)还有个Connector的初始化:connector.start()->LifecycleBase.start()->Connector.startIniternal()->protocalHandler.start()
protected void startInternal() throws LifecycleException {
// Validate settings before starting
if (getPort() < 0) {
throw new LifecycleException(sm.getString(
"coyoteConnector.invalidPort", Integer.valueOf(getPort())));
}
setState(LifecycleState.STARTING);
try {
protocolHandler.start();
} catch (Exception e) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
}
}
总结一下子:
Tomcat的启动
启动脚本startup.sh,最终执行Bootstrap.main(),且会把命令(start、stop等)作为参数传入,不同参数会调用不同的方法
当命令是start时,Bootstrap.main()会调用Catalina.load()和Catalina.start()
Tomcat组件的加载:load()
- 在Catalina.load()中,解析conf/server.xml,最后调用getServer.init(),对server初始化
- 调用getServer.init(),会进入LifecycleBase.init(),这个方法中会先这是server状态为initializing且发布事件,再调用StandardServer.initInternal()
- 在StandardServer.initInternal()中,会循环调用service.init()方法,会先进入LifecycleBase.init(),然后进入StandardService.initInternal()
- 在StandardService.initInternal()中会初始化engine和connectors
Tomcat容器的加载:start()
- Catalina.start(),最后调用getServer.start(),进入LifecycleBase.start(),最后进入StandardServer.startIniternal()
- 在StandardServer.startIniternal()中,会启动engine.start()和connector.start()
- 在engine.start()中,调用ContainerBase.startIniternal(),会将子容器Host的启动任务提交到线程池中,Host容器启动过程:
- 先发布事件,且HostConfig监听到这个事件,在HostConfig中会发布web项目,且创建当前web项目的StandardContext,然后把这个StandardContext添加到Host的子容器中
- 然后执行StandardHost.startIniternal(),这个方法中又回到父类ContainerBase.startIniternal(),然后重复提交StandardContext的启动任务到线程池中
- StandardContext的启动过程:
- 发布事件,ContextConfig监听到这个事件,ContextConfig中加载并解析项目的web.xml文件,初始化配置的Listener、Filter、Servlet等信息,servlet会解析成Wrapper,然后添加到Context的子容器中
- 然后调用StandardContext.startIniternal(),启动Context,这里会调用web.xml配置的监听contextInitialized(),spring容器在这里得到创建
- 在StandardContext.startIniternal()中,然后加载Servlet,最终会调用spring-webmvc.jar中DispatcherSerlvet.onRefresh(),加载Serlvet的七大组件
再来个简单版的总结
Tomcat启动分成2个部分:
- 组件的初始化
- 容器的启动
其中组件包括:Server->Services->Engine->Connectors
容器包括:Engine->StandardHost->StandardContext->StandardWrapperweb项目的加载、Spring容器的初始化入口、Servlet容器的加载都在第二步,也就是Catalina.start()中
- web项目的加载:在启动Host容器前发布的事件,也就是监听HostConfig.start()中,并且创建子容器StandardContext
- Spring容器的初始化入口:在StandardContext启动过程中执行了web.xml中配置的ServletContextListener的实现类的contextInitialized()
- Servlet容器的加载:在StandardContext启动过程中执行的loadOnStartup(),最终调用DispatcherServlet.onRefresh(),初始化了Servlet的七大组件
留个大疑问
上文中的ServletContainerInitializer的作用是啥?有什么应用?可以怎么拓展?
作用:它是Servlet3.0提供的接口,只有一个方法,主要作用替代web.xml,通过初始化自定义的Listener、Filter、Servlet等信息
public interface ServletContainerInitializer {
/**
* @param c 启动时初始化的类
* @param ctx web应用的servlet上下文
*/
void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException;
}
应用:spring-web.jar中,SpringServletContainerInitializer实现了此接口
// 1)通过此注解将WebApplicationInitializer类,添加到onStartup方法的第一个参数中
@HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {
public SpringServletContainerInitializer() {
}
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList();
Iterator var4;
if (webAppInitializerClasses != null) {
var4 = webAppInitializerClasses.iterator();
while(var4.hasNext()) {
Class<?> waiClass = (Class)var4.next();
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
// 2)创建WebApplicationInitializer对象
initializers.add((WebApplicationInitializer)waiClass.newInstance());
} catch (Throwable var7) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
} else {
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
var4 = initializers.iterator();
while(var4.hasNext()) {
WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
// 3)调用WebApplicationInitializer的方法初始化
initializer.onStartup(servletContext);
}
}
}
}
SpringServletContainerInitializer在Tomcat启动时,容器初始化阶段初始化StandardContext时,被调用:
protected synchronized void startInternal() throws LifecycleException {
// Call ServletContainerInitializers
for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry : initializers.entrySet()) {
try {
// 循环多个ServletContainerInitializer,并调用onStartup()
entry.getKey().onStartup(entry.getValue(), getServletContext());
} catch (ServletException e) {
log.error(sm.getString("standardContext.sciFail"), e);
ok = false;
break;
}
}
}
SpringServletContainerInitializer是如何加载到的?毕竟在第三方jar包中,也是在Tomcat启动初始化容器StandardContext之前,发布的事件,在事件监听ContextConfig中加载的:(方法链路:lifecycleEvent()->configureStart()->webConfig()->processServletContainerInitializers()->WebappServiceLoader.load()),spring-web.jar的classpath/META-INF/services/路径下配置了需要初始化的ServletContianerInitializer,由Tomcat的ContextConfig加载初始化,在StandardContext中调用
protected void processServletContainerInitializers(){
// 1) 指定类型为ServletContainerInitializer
WebappServiceLoader<ServletContainerInitializer> loader = new WebappServiceLoader<>(context);
detectedScis = loader.load(ServletContainerInitializer.class);
// ...
}
// 2)加载META-INF/services/路径下
private static final String SERVICES = "META-INF/services/";
public List<T> load(Class<T> serviceType) throws IOException {
String configFile = SERVICES + serviceType.getName();
// ...
}
自定义:ServletContainerInitializer
//容器启动的时候会将@HandlesTypes指定的这个类型下面的子类(实现类,子接口等)传递过来;
//传入感兴趣的类型;
@HandlesTypes(value={HelloService.class})
public class MyServletContainerInitializer implements ServletContainerInitializer {
/**
* 应用启动的时候,会运行onStartup方法;
*
* Set<Class<?>> arg0:感兴趣的类型的所有子类型;
* ServletContext arg1:代表当前Web应用的ServletContext;一个Web应用一个ServletContext;
*
* 1)、使用ServletContext注册Web组件(Servlet、Filter、Listener)
* 2)、使用编码的方式,在项目启动的时候给ServletContext里面添加组件;
* 必须在项目启动的时候来添加;
* 1)、ServletContainerInitializer得到的ServletContext;
* 2)、ServletContextListener得到的ServletContext;
*/
@Override
public void onStartup(Set<Class<?>> arg0, ServletContext sc) throws ServletException {
// TODO Auto-generated method stub
System.out.println("感兴趣的类型:");
for (Class<?> claz : arg0) {
System.out.println(claz);
}
//注册组件 ServletRegistration
ServletRegistration.Dynamic servlet = sc.addServlet("userServlet", new UserServlet());
//配置servlet的映射信息
servlet.addMapping("/user");
//注册Listener
sc.addListener(UserListener.class);
//注册Filter FilterRegistration
FilterRegistration.Dynamic filter = sc.addFilter("userFilter", UserFilter.class);
//配置Filter的映射信息
filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
}
}
参考:
😈如果有错误请大家指正...