ServletWebServerApplicationContext創(chuàng)建Web容器Tomcat示例
正文
ServletWebServerApplicationContext實(shí)現(xiàn)了父類AbstractApplicationContext的onRefresh模板方法,在這里進(jìn)行了拓展創(chuàng)建了Web容器。
@Override
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
創(chuàng)建Web服務(wù)
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
//一、獲取Web服務(wù)器工廠
ServletWebServerFactory factory = getWebServerFactory();
//二、獲取Web服務(wù)
this.webServer = factory.getWebServer(getSelfInitializer());
//三、注冊(cè)Bean生命周期(在容器啟動(dòng)和銷毀時(shí)調(diào)用)
getBeanFactory().registerSingleton("webServerGracefulShutdown",
new WebServerGracefulShutdownLifecycle(this.webServer));
getBeanFactory().registerSingleton("webServerStartStop",
new WebServerStartStopLifecycle(this, this.webServer));
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
//四、初始化上下文環(huán)境
initPropertySources();
}
一、獲取Web服務(wù)器工廠
protected ServletWebServerFactory getWebServerFactory() {
// Use bean names so that we don't consider the hierarchy
//獲取Web服務(wù)器工廠名稱
String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
if (beanNames.length == 0) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing "
+ "ServletWebServerFactory bean.");
}
if (beanNames.length > 1) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "
+ "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
}
//從容器中獲取Web服務(wù)器工廠實(shí)例
return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}
這里的Web服務(wù)器工廠是通過ServletWebServerFactoryAutoConfiguration自動(dòng)配置類導(dǎo)入進(jìn)來的。
@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
//Web啟動(dòng)環(huán)境
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
//2.1導(dǎo)入Web工廠
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
//導(dǎo)入Web服務(wù)器工廠自定義程序
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
return new ServletWebServerFactoryCustomizer(serverProperties);
}
//如果是Tomcat則導(dǎo)入Tomcat自定義程序
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
@Bean
@ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class)
@ConditionalOnProperty(value = "server.forward-headers-strategy", havingValue = "framework")
public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter);
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registration;
}
/**
* Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via
* {@link ImportBeanDefinitionRegistrar} for early registration.
*/
public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (beanFactory instanceof ConfigurableListableBeanFactory) {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (this.beanFactory == null) {
return;
}
registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
WebServerFactoryCustomizerBeanPostProcessor.class);
registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
ErrorPageRegistrarBeanPostProcessor.class);
}
private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {
if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(name, beanDefinition);
}
}
}
}
1.1 選擇導(dǎo)入Web工廠
@Configuration
class ServletWebServerFactoryConfiguration {
ServletWebServerFactoryConfiguration() {
}
//1.如果容器中有Servlet,Undertow,SslClientAuthMode就會(huì)創(chuàng)建Undertow工廠
@Configuration
@ConditionalOnClass({Servlet.class, Undertow.class, SslClientAuthMode.class})
@ConditionalOnMissingBean(
value = {ServletWebServerFactory.class},
search = SearchStrategy.CURRENT
)
public static class EmbeddedUndertow {
public EmbeddedUndertow() {
}
@Bean
public UndertowServletWebServerFactory undertowServletWebServerFactory() {
return new UndertowServletWebServerFactory();
}
}
//2.如果容器中有Servlet,Server,Loader就會(huì)創(chuàng)建Jetty工廠
@Configuration
@ConditionalOnClass({Servlet.class, Server.class, Loader.class, WebAppContext.class})
@ConditionalOnMissingBean(
value = {ServletWebServerFactory.class},
search = SearchStrategy.CURRENT
)
public static class EmbeddedJetty {
public EmbeddedJetty() {
}
@Bean
public JettyServletWebServerFactory JettyServletWebServerFactory() {
return new JettyServletWebServerFactory();
}
}
//3.如果容器中有Servlet,Tomcat,UpgradeProtocol就會(huì)創(chuàng)建Tomcat工廠
@Configuration
@ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class})
@ConditionalOnMissingBean(
value = {ServletWebServerFactory.class},
search = SearchStrategy.CURRENT
)
public static class EmbeddedTomcat {
public EmbeddedTomcat() {
}
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
}
二、getWebServer:獲取Web服務(wù)
public static final String DEFAULT_PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol";
private String protocol = DEFAULT_PROTOCOL;
public WebServer getWebServer(ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();
// 給嵌入式Tomcat創(chuàng)建一個(gè)臨時(shí)文件夾,用于存放Tomcat運(yùn)行中需要的文件
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
// Tomcat核心概念:Connector,默認(rèn)放入的protocol為NIO模式
Connector connector = new Connector(this.protocol);
// 給Service添加Connector
tomcat.getService().addConnector(connector);
// 執(zhí)行定制器,修改即將設(shè)置到Tomcat中的Connector
customizeConnector(connector);
tomcat.setConnector(connector);
// 關(guān)閉熱部署(嵌入式Tomcat不存在修改web.xml、war包等情況)
tomcat.getHost().setAutoDeploy(false);
// 設(shè)置backgroundProcessorDelay機(jī)制
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
// 2.1 創(chuàng)建TomcatEmbeddedContext
prepareContext(tomcat.getHost(), initializers);
// 2.2. 創(chuàng)建TomcatWebServer
return getTomcatWebServer(tomcat);
}
2.1 創(chuàng)建TomcatEmbeddedContext
(注釋均已在源碼中標(biāo)注好,小伙伴們對(duì)哪一步感興趣可以借助IDE自己動(dòng)手Debug體會(huì)一下實(shí)現(xiàn))
protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
File documentRoot = getValidDocumentRoot();
// 創(chuàng)建TomcatEmbeddedContext
TomcatEmbeddedContext context = new TomcatEmbeddedContext();
if (documentRoot != null) {
context.setResources(new LoaderHidingResourceRoot(context));
}
context.setName(getContextPath());
context.setDisplayName(getDisplayName());
// 設(shè)置contextPath,很熟悉了
context.setPath(getContextPath());
// 給嵌入式Tomcat創(chuàng)建docbase的臨時(shí)文件夾
File docBase = (documentRoot != null) ? documentRoot : createTempDir("tomcat-docbase");
context.setDocBase(docBase.getAbsolutePath());
// 注冊(cè)監(jiān)聽器
context.addLifecycleListener(new FixContextListener());
context.setParentClassLoader((this.resourceLoader != null) ? this.resourceLoader.getClassLoader()
: ClassUtils.getDefaultClassLoader());
// 設(shè)置默認(rèn)編碼映射
resetDefaultLocaleMapping(context);
addLocaleMappings(context);
context.setUseRelativeRedirects(false);
try {
context.setCreateUploadTargets(true);
}
catch (NoSuchMethodError ex) {
// Tomcat is < 8.5.39. Continue.
}
configureTldSkipPatterns(context);
// 自定義的類加載器,可以加載web應(yīng)用的jar包
WebappLoader loader = new WebappLoader(context.getParentClassLoader());
loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName());
// 指定類加載器遵循雙親委派機(jī)制
loader.setDelegate(true);
context.setLoader(loader);
// 注冊(cè)默認(rèn)的Servlet
if (isRegisterDefaultServlet()) {
addDefaultServlet(context);
}
// 如果需要jsp支持,注冊(cè)jsp的Servlet和Initializer
if (shouldRegisterJspServlet()) {
addJspServlet(context);
addJasperInitializer(context);
}
// 注冊(cè)監(jiān)聽器
context.addLifecycleListener(new StaticResourceConfigurer(context));
ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
host.addChild(context);
configureContext(context, initializersToUse);
postProcessContext(context);
}
2.2. 創(chuàng)建TomcatWebServer
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
}
進(jìn)入TomcatWebServer構(gòu)造方法中:
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
//初始化服務(wù)
initialize();
}
初始化TomcatWebServer
private void initialize() throws WebServerException {
logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
synchronized (this.monitor) {
try {
//設(shè)置Engine的id
addInstanceIdToEngineName();
//獲取Context(TomcatEmbeddedContext 2.1中創(chuàng)建出來的)
Context context = findContext();
//添加監(jiān)聽器 TomcatEmbeddedContext
//在服務(wù)啟動(dòng)時(shí)如果有連接進(jìn)來先刪除連接,以便在啟動(dòng)服務(wù)時(shí)不會(huì)發(fā)生協(xié)議綁定。
context.addLifecycleListener((event) -> {
if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
// Remove service connectors so that protocol binding doesn't
// happen when the service is started.
//刪除ServiceConnectors,以便在啟動(dòng)服務(wù)時(shí)不會(huì)發(fā)生協(xié)議綁定。
removeServiceConnectors();
}
});
// Start the server to trigger initialization listeners
//2.2.1 啟動(dòng)Tomcat
this.tomcat.start();
// We can re-throw failure exception directly in the main thread
//Tomcat啟動(dòng)有異常需要在主線程中拋出
rethrowDeferredStartupExceptions();
try {
ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
}
catch (NamingException ex) {
// Naming is not enabled. Continue
}
// Unlike Jetty, all Tomcat threads are daemon threads. We create a
// blocking non-daemon to stop immediate shutdown
//開啟阻塞非守護(hù)線程停止web容器
startDaemonAwaitThread();
}
catch (Exception ex) {
stopSilently();
destroySilently();
throw new WebServerException("Unable to start embedded Tomcat", ex);
}
}
}
2.2.1 啟動(dòng)Tomcat
創(chuàng)建和初始化Server和Service
public void start() throws LifecycleException {
//創(chuàng)建服務(wù)(Server和Service)
getServer();
server.start();
}
啟動(dòng)服務(wù)
public final synchronized void start() throws LifecycleException {
//如果是正在啟動(dòng)或啟動(dòng)狀態(tài)
if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
LifecycleState.STARTED.equals(state)) {
if (log.isDebugEnabled()) {
Exception e = new LifecycleException();
log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
} else if (log.isInfoEnabled()) {
log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
}
return;
}
//如果是新建狀態(tài)
if (state.equals(LifecycleState.NEW)) {
//2.2.1.1 初始化服務(wù)
init();
//如果是失敗狀態(tài)
} else if (state.equals(LifecycleState.FAILED)) {
//停止服務(wù)
stop();
//如果不是初始化也不是停止?fàn)顟B(tài)
} else if (!state.equals(LifecycleState.INITIALIZED) &&
!state.equals(LifecycleState.STOPPED)) {
//修改狀態(tài)
invalidTransition(Lifecycle.BEFORE_START_EVENT);
}
try {
//修改狀態(tài)為準(zhǔn)備啟動(dòng)
setStateInternal(LifecycleState.STARTING_PREP, null, false);
//2.2.1.2 啟動(dòng)Internal
startInternal();
if (state.equals(LifecycleState.FAILED)) {
// This is a 'controlled' failure. The component put itself into the
// FAILED state so call stop() to complete the clean-up.
stop();
} else if (!state.equals(LifecycleState.STARTING)) {
// Shouldn't be necessary but acts as a check that sub-classes are
// doing what they are supposed to.
invalidTransition(Lifecycle.AFTER_START_EVENT);
} else {
setStateInternal(LifecycleState.STARTED, null, false);
}
} catch (Throwable t) {
// This is an 'uncontrolled' failure so put the component into the
// FAILED state and throw an exception.
handleSubClassException(t, "lifecycleBase.startFail", toString());
}
}
2.2.1.1 初始化Server
public final synchronized void init() throws LifecycleException {
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
//設(shè)置狀態(tài)為初始化
setStateInternal(LifecycleState.INITIALIZING, null, false);
//初始化
initInternal();
//設(shè)置狀態(tài)為初始化完成
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
handleSubClassException(t, "lifecycleBase.initFail", toString());
}
}
初始化 Server
protected void initInternal() throws LifecycleException {
//調(diào)用父類初始化(設(shè)置名稱:Tomcat,類型:Server)
super.initInternal();
// Initialize utility executor
reconfigureUtilityExecutor(getUtilityThreadsInternal(utilityThreads));
//注冊(cè)線程池
register(utilityExecutor, "type=UtilityExecutor");
// Register global String cache
// Note although the cache is global, if there are multiple Servers
// present in the JVM (may happen when embedding) then the same cache
// will be registered under multiple names
//注冊(cè)字符串緩存
onameStringCache = register(new StringCache(), "type=StringCache");
// Register the MBeanFactory
MBeanFactory factory = new MBeanFactory();
factory.setContainer(this);
//注冊(cè)Bean工廠
onameMBeanFactory = register(factory, "type=MBeanFactory");
// Register the naming resources
//注冊(cè)命名資源
globalNamingResources.init();
// Populate the extension validator with JARs from common and shared
// class loaders
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();
}
}
// Initialize our defined Services
//2.2.1.1.1 初始化service(2.2.1最開始時(shí)創(chuàng)建)
for (Service service : services) {
service.init();
}
}
初始化Service
public final synchronized void init() throws LifecycleException {
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
//設(shè)置狀態(tài)為初始化
setStateInternal(LifecycleState.INITIALIZING, null, false);
//初始化
initInternal();
//設(shè)置狀態(tài)為初始化完成
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
handleSubClassException(t, "lifecycleBase.initFail", toString());
}
}
初始化Service
protected void initInternal() throws LifecycleException {
//調(diào)用父類初始化(設(shè)置名稱:Tomcat,類型:Server)
super.initInternal();
//2.2.1.1.1.1 初始化engine
if (engine != null) {
engine.init();
}
// Initialize any Executors
//2.2.1.1.1.2 初始化executor
for (Executor executor : findExecutors()) {
if (executor instanceof JmxEnabled) {
((JmxEnabled) executor).setDomain(getDomain());
}
executor.init();
}
// Initialize mapper listener
//2.2.1.1.1.3 初始化mapperListener
mapperListener.init();
// Initialize our defined Connectors
//2.2.1.1.1.4 初始化connector
synchronized (connectorsLock) {
for (Connector connector : connectors) {
connector.init();
}
}
}
初始化engine
protected void initInternal() throws LifecycleException {
// Ensure that a Realm is present before any attempt is made to start
// one. This will create the default NullRealm if necessary.
// 在嘗試啟動(dòng)一個(gè)Realm之前,請(qǐng)確保存在一個(gè)Realm。如有必要,這將創(chuàng)建默認(rèn)的NullRealm
getRealm();
super.initInternal();
}
public Realm getRealm() {
Realm configured = super.getRealm();
// If no set realm has been called - default to NullRealm
// This can be overridden at engine, context and host level
if (configured == null) {
configured = new NullRealm();
this.setRealm(configured);
}
return configured;
}
初始化executor
它還是調(diào)的父類 LifecycleMBeanBase 的方法
protected void initInternal() throws LifecycleException {
super.initInternal();
}
初始化mapperListener
protected void initInternal() throws LifecycleException {
// If oname is not null then registration has already happened via preRegister().
// 如果oname不為null,則已經(jīng)通過preRegister()進(jìn)行了注冊(cè)
if (oname == null) {
mserver = Registry.getRegistry(null, null).getMBeanServer();
oname = register(this, getObjectNameKeyProperties());
}
}
初始化connector
protected void initInternal() throws LifecycleException {
super.initInternal();
if (protocolHandler == null) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerInstantiationFailed"));
}
// Initialize adapter
adapter = new CoyoteAdapter(this);
protocolHandler.setAdapter(adapter);
if (service != null) {
protocolHandler.setUtilityExecutor(service.getServer().getUtilityExecutor());
}
// Make sure parseBodyMethodsSet has a default
if (null == parseBodyMethodsSet) {
setParseBodyMethods(getParseBodyMethods());
}
if (protocolHandler.isAprRequired() && !AprStatus.isInstanceCreated()) {
throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprListener",
getProtocolHandlerClassName()));
}
if (protocolHandler.isAprRequired() && !AprStatus.isAprAvailable()) {
throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprLibrary",
getProtocolHandlerClassName()));
}
if (AprStatus.isAprAvailable() && AprStatus.getUseOpenSSL() &&
protocolHandler instanceof AbstractHttp11JsseProtocol) {
AbstractHttp11JsseProtocol<?> jsseProtocolHandler =
(AbstractHttp11JsseProtocol<?>) protocolHandler;
if (jsseProtocolHandler.isSSLEnabled() &&
jsseProtocolHandler.getSslImplementationName() == null) {
// OpenSSL is compatible with the JSSE configuration, so use it if APR is available
jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
}
}
try {
//2.2.1.1.1.5 初始化protocolHandler
protocolHandler.init();
} catch (Exception e) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
}
}
初始化protocolHandler
public void init() throws Exception {
// Upgrade protocols have to be configured first since the endpoint
// init (triggered via super.init() below) uses this list to configure
// the list of ALPN protocols to advertise
// 必須先配置升級(jí)協(xié)議,因?yàn)槎它c(diǎn)初始化(通過下面的super.init()觸發(fā))使用此列表來配置要發(fā)布的ALPN協(xié)議列表
for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {
configureUpgradeProtocol(upgradeProtocol);
}
super.init();
}
Debug發(fā)現(xiàn)這個(gè) upgradeProtocols 為空,直接走下面父類(AbstractProtocol)的 init 方法:
public void init() throws Exception {
if (getLog().isInfoEnabled()) {
getLog().info(sm.getString("abstractProtocolHandler.init", getName()));
logPortOffset();
}
if (oname == null) {
// Component not pre-registered so register it
oname = createObjectName();
if (oname != null) {
Registry.getRegistry(null, null).registerComponent(this, oname, null);
}
}
if (this.domain != null) {
rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
Registry.getRegistry(null, null).registerComponent(
getHandler().getGlobal(), rgOname, null);
}
String endpointName = getName();
endpoint.setName(endpointName.substring(1, endpointName.length()-1));
endpoint.setDomain(domain);
//2.2.1.1.1.6 初始化endpoint
endpoint.init();
}
上面又是一堆初始化,這個(gè)咱暫且不關(guān)注,注意最底下有一個(gè) endpoint.init :
初始化endpoint
來到 AbstractEndPoint :
public final void init() throws Exception {
// Debug為false
if (bindOnInit) {
bindWithCleanup();
bindState = BindState.BOUND_ON_INIT;
}
if (this.domain != null) {
// Register endpoint (as ThreadPool - historical name)
oname = new ObjectName(domain + ":type=ThreadPool,name="" + getName() + """);
Registry.getRegistry(null, null).registerComponent(this, oname, null);
ObjectName socketPropertiesOname = new ObjectName(domain +
":type=ThreadPool,name="" + getName() + "",subType=SocketProperties");
socketProperties.setObjectName(socketPropertiesOname);
Registry.getRegistry(null, null).registerComponent(socketProperties, socketPropertiesOname, null);
for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
registerJmx(sslHostConfig);
}
}
}
這里面又是初始化 oname ,又是配置 socketProperties 的,但這里面再也沒見到 init 方法,證明這部分初始化過程已經(jīng)結(jié)束了。
初始化小結(jié)
嵌入式 Tomcat 的組件初始化步驟順序如下:
- Server
- Service
- Engine
- Executor
- MapperListener
- Connector
- Protocol
- EndPoint
startInternal:?jiǎn)?dòng)Internal
startInternal 方法中有兩部分啟動(dòng):globalNamingResources 啟動(dòng),services 啟動(dòng)。分別來看:
protected void startInternal() throws LifecycleException {
// 發(fā)布啟動(dòng)事件
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
// 2.2.1.2.1 NamingResources啟動(dòng)
globalNamingResources.start();
// Start our defined Services
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
// 2.2.1.2.2 Service啟動(dòng)
services[i].start();
}
}
if (periodicEventDelay > 0) {
monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
new Runnable() {
@Override
public void run() {
startPeriodicLifecycleEvent();
}
}, 0, 60, TimeUnit.SECONDS);
}
}
NamingResources啟動(dòng)
只是發(fā)布事件和設(shè)置狀態(tài)而已
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
}
Service啟動(dòng)
依次啟動(dòng) Engine 、Executor 、MapperListener 、Connector
protected void startInternal() throws LifecycleException {
if(log.isInfoEnabled())
log.info(sm.getString("standardService.start.name", this.name));
setState(LifecycleState.STARTING);
// Start our defined Container first
if (engine != null) {
synchronized (engine) {
// 2.2.1.2.2.1 啟動(dòng)Engine
engine.start();
}
}
synchronized (executors) {
for (Executor executor: executors) {
// 2.2.1.2.2.3 啟動(dòng)Executor
executor.start();
}
}
// 2.2.1.2.2.4 啟動(dòng)MapperListener
mapperListener.start();
// Start our defined Connectors second
synchronized (connectorsLock) {
for (Connector connector: connectors) {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
// 2.2.1.2.2.5 啟動(dòng)connector
connector.start();
}
}
}
}
啟動(dòng)Engine
protected synchronized void startInternal() throws LifecycleException {
// Log our server identification information
if (log.isInfoEnabled()) {
log.info(sm.getString("standardEngine.start", ServerInfo.getServerInfo()));
}
// Standard container startup
super.startInternal();
}
它直接調(diào)的父類 ContainerBase 的 startInternal 方法:
protected synchronized void startInternal() throws LifecycleException {
// Start our subordinate components, if any
logger = null;
getLogger();
// Cluster與集群相關(guān),SpringBoot項(xiàng)目中使用嵌入式Tomcat,不存在集群
Cluster cluster = getClusterInternal();
if (cluster instanceof Lifecycle) {
((Lifecycle) cluster).start();
}
// Realm與授權(quán)相關(guān)
Realm realm = getRealmInternal();
if (realm instanceof Lifecycle) {
((Lifecycle) realm).start();
}
// Start our child containers, if any
// Container的類型是StandardHost
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
for (int i = 0; i < children.length; i++) {
//異步初始化Host
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
MultiThrowable multiThrowable = null;
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);
}
}
if (multiThrowable != null) {
throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
multiThrowable.getThrowable());
}
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
setState(LifecycleState.STARTING);
// Start our thread
if (backgroundProcessorDelay > 0) {
monitorFuture = Container.getService(ContainerBase.this).getServer()
.getUtilityExecutor().scheduleWithFixedDelay(
new ContainerBackgroundProcessorMonitor(), 0, 60, TimeUnit.SECONDS);
}
}
StartChild 實(shí)現(xiàn)了帶返回值的異步多線程接口 Callable 核心方法就是在 call
private static class StartChild implements Callable<Void>
它實(shí)現(xiàn)了帶返回值的異步多線程接口 Callable !那里面的核心方法就是 call :
public Void call() throws LifecycleException {
child.start();
return null;
}
它在這里初始化 child,而通過Debug得知 child 的類型是 StandardHost,故來到 StandardHost 的 start 方法:
protected synchronized void startInternal() throws LifecycleException {
// Set error report valve
String errorValve = getErrorReportValveClass();
if ((errorValve != null) && (!errorValve.equals(""))) {
try {
boolean found = false;
Valve[] valves = getPipeline().getValves();
for (Valve valve : valves) {
if (errorValve.equals(valve.getClass().getName())) {
found = true;
break;
}
}
if(!found) {
Valve valve =
(Valve) Class.forName(errorValve).getConstructor().newInstance();
getPipeline().addValve(valve);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString(
"standardHost.invalidErrorReportValveClass",
errorValve), t);
}
}
super.startInternal();
}
上面的一個(gè)大if結(jié)構(gòu)是設(shè)置錯(cuò)誤提示頁面的,下面又調(diào)父類的 startInternal :
protected synchronized void startInternal() throws LifecycleException {
// ......
// Start our child containers, if any
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
又回來了。。。因?yàn)橐粋€(gè) Host 包含一個(gè) Context 。
Host 搜索children就會(huì)搜到它下面的 Context ,之后又是下面的初始化過程,進(jìn)入 Context 的初始化:
啟動(dòng)TomcatEmbeddedContext
在TomcatEmbeddedContext有如下組件被調(diào)用了 start 方法:
- StandardRoot
- DirResourceSet
- WebappLoader
- JarResourceSet
- StandardWrapper
- StandardPineline
- StandardWrapperValve
- NonLoginAuthenticator
- StandardContextValve
- StandardManager
- LazySessionIdGenerator
啟動(dòng)Executor
但由于 Executor 沒有實(shí)現(xiàn) startInternal 方法,所以不會(huì)啟動(dòng)
synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
}
啟動(dòng)MapperListener
接下來啟動(dòng) MapperListener :
public void startInternal() throws LifecycleException {
setState(LifecycleState.STARTING);
Engine engine = service.getContainer();
if (engine == null) {
return;
}
// 獲取當(dāng)前部署的主機(jī)名(本地調(diào)試為localhost)
findDefaultHost();
// 把當(dāng)前自身注冊(cè)到Engine、Host、Context、Wrapper中
addListeners(engine);
// 取出的Container的類型為Host
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
//將Host、Context、Wrapper注冊(cè)到當(dāng)前監(jiān)聽器中
registerHost(host);
}
}
}
啟動(dòng)Connector
最后一步是啟動(dòng) Connector 。
// Start our defined Connectors second
synchronized (connectorsLock) {
for (Connector connector: connectors) {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
connector.start();
}
}
}
啟動(dòng)總結(jié)
啟動(dòng)過程依次啟動(dòng)了如下組件:
- NamingResources
- Service
- Engine
- Host
- Context
- Wrapper
- Executor
- MapperListener
三、注冊(cè)Bean生命周期
3.1 WebServerStartStopLifecycle(Web服務(wù)器啟動(dòng)-停止生命周期)
WebServerStartStopLifecycle實(shí)現(xiàn)了Lifecycle,在容器刷新完成時(shí)會(huì)調(diào)用finishRefresh()
@Override
public void start() {
//啟動(dòng)Tomcat 容器
this.webServer.start();
this.running = true;
this.applicationContext
.publishEvent(new ServletWebServerInitializedEvent(this.webServer, this.applicationContext));
}
public void start() throws WebServerException {
synchronized (this.monitor) {
if (this.started) {
return;
}
try {
// 3.1.1 還原、啟動(dòng)Connector
addPreviouslyRemovedConnectors();
// 只拿一個(gè)Connector
Connector connector = this.tomcat.getConnector();
if (connector != null && this.autoStart) {
// 3.1.2 延遲啟動(dòng)
performDeferredLoadOnStartup();
}
// 檢查Connector是否正常啟動(dòng)
checkThatConnectorsHaveStarted();
this.started = true;
logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
+ getContextPath() + "'");
}
// catch ......
finally {
// 解除ClassLoader與TomcatEmbeddedContext的綁定關(guān)系
Context context = findContext();
ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
}
}
}
3.1.1 addPreviouslyRemovedConnectors:?jiǎn)?dòng)Connector
private void addPreviouslyRemovedConnectors() {
Service[] services = this.tomcat.getServer().findServices();
for (Service service : services) {
Connector[] connectors = this.serviceConnectors.get(service);
if (connectors != null) {
for (Connector connector : connectors) {
// 添加并啟動(dòng)
service.addConnector(connector);
if (!this.autoStart) {
stopProtocolHandler(connector);
}
}
this.serviceConnectors.remove(service);
}
}
}
可以發(fā)現(xiàn)它將一個(gè)緩存區(qū)的 Connector 一個(gè)一個(gè)取出放入 Service 中。注意在 service.addConnector 中有順便啟動(dòng)的部分:
public void addConnector(Connector connector) {
synchronized (connectorsLock) {
connector.setService(this);
Connector results[] = new Connector[connectors.length + 1];
System.arraycopy(connectors, 0, results, 0, connectors.length);
results[connectors.length] = connector;
connectors = results;
}
try {
if (getState().isAvailable()) {
// 啟動(dòng)Connector
connector.start();
}
} catch (LifecycleException e) {
throw new IllegalArgumentException(
sm.getString("standardService.connector.startFailed", connector), e);
}
// Report this property change to interested listeners
support.firePropertyChange("connector", null, connector);
}
前面的部分是取出 Connector ,并與 Service 綁定,之后中間部分的try塊,會(huì)啟動(dòng) Connector :
protected void startInternal() throws LifecycleException {
// Validate settings before starting
if (getPortWithOffset() < 0) {
throw new LifecycleException(sm.getString(
"coyoteConnector.invalidPort", Integer.valueOf(getPortWithOffset())));
}
setState(LifecycleState.STARTING);
try {
// 啟動(dòng)ProtocolHandler
protocolHandler.start();
} catch (Exception e) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
}
}
Connector 的啟動(dòng)會(huì)引發(fā) ProtocolHandler 的啟動(dòng):
public void start() throws Exception {
if (getLog().isInfoEnabled()) {
getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
logPortOffset();
}
// 啟動(dòng)EndPoint
endpoint.start();
monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
new Runnable() {
@Override
public void run() {
if (!isPaused()) {
startAsyncTimeout();
}
}
}, 0, 60, TimeUnit.SECONDS);
}
ProtocolHandler 的啟動(dòng)會(huì)引發(fā) EndPoint 的啟動(dòng),至此所有組件均已啟動(dòng)完畢。
performDeferredLoadOnStartup:延遲啟動(dòng)
這里面會(huì)延遲啟動(dòng) TomcatEmbeddedContext
private void performDeferredLoadOnStartup() {
try {
for (Container child : this.tomcat.getHost().findChildren()) {
if (child instanceof TomcatEmbeddedContext) {
// 延遲啟動(dòng)Context
((TomcatEmbeddedContext) child).deferredLoadOnStartup();
}
}
}
catch (Exception ex) {
if (ex instanceof WebServerException) {
throw (WebServerException) ex;
}
throw new WebServerException("Unable to start embedded Tomcat connectors", ex);
}
}
四、初始化上下文環(huán)境
這里在Spring中已經(jīng)刷新過一次,詳情:在文章 http://www.dbjr.com.cn/article/277946.htm 的 prepareRefresh:初始化前的預(yù)處理中
以上就是ServletWebServerApplicationContext創(chuàng)建Web容器Tomcat示例的詳細(xì)內(nèi)容,更多關(guān)于Web容器Tomcat創(chuàng)建的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實(shí)現(xiàn)提取QSV文件視頻內(nèi)容
QSV是一種加密的視頻文件格式。是愛奇藝公司研發(fā)的一種視頻文件格式,這篇文章主要為大家介紹了如何利用Java實(shí)現(xiàn)提取QSV文件視頻內(nèi)容,感興趣的可以了解一下2023-03-03
Spring根據(jù)URL參數(shù)進(jìn)行路由的方法詳解
這篇文章主要給大家介紹了關(guān)于Spring根據(jù)URL參數(shù)進(jìn)行路由的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起來看看吧。2017-12-12
SpringBoot整合Mybatis的知識(shí)點(diǎn)匯總
在本篇文章里小編給各位整理的是關(guān)于SpringBoot整合Mybatis的知識(shí)點(diǎn)匯總,有興趣學(xué)習(xí)的參考下。2020-02-02
Spring?Boot?中的?@HystrixCommand?注解原理及使用方法
通過使用 @HystrixCommand 注解,我們可以輕松地實(shí)現(xiàn)對(duì)方法的隔離和監(jiān)控,從而提高系統(tǒng)的可靠性和穩(wěn)定性,本文介紹了Spring Boot 中的@HystrixCommand注解是什么,其原理以及如何使用,感興趣的朋友跟隨小編一起看看吧2023-07-07
Java網(wǎng)絡(luò)編程中的TCP/UDP詳解
這篇文章主要介紹了Java網(wǎng)絡(luò)編程中的TCP/UDP詳解,網(wǎng)絡(luò)編程是指編寫運(yùn)行在多個(gè)設(shè)備的程序,這些設(shè)備都通過網(wǎng)絡(luò)連接起來,java.net 包中 J2SE 的 API 包含有類和接口,它們提供低層次的通信細(xì)節(jié),需要的朋友可以參考下2023-12-12

