springboot中如何利用Tomcat容器實(shí)現(xiàn)自啟動(dòng)

這篇“springboot中如何利用Tomcat容器實(shí)現(xiàn)自啟動(dòng)”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“springboot中如何利用Tomcat容器實(shí)現(xiàn)自啟動(dòng)”文章吧。

創(chuàng)新互聯(lián)建站是一家專業(yè)的成都網(wǎng)站建設(shè)公司,我們專注做網(wǎng)站、成都做網(wǎng)站、網(wǎng)絡(luò)營銷、企業(yè)網(wǎng)站建設(shè),賣鏈接,1元廣告為企業(yè)客戶提供一站式建站解決方案,能帶給客戶新的互聯(lián)網(wǎng)理念。從網(wǎng)站結(jié)構(gòu)的規(guī)劃UI設(shè)計(jì)到用戶體驗(yàn)提高,創(chuàng)新互聯(lián)力求做到盡善盡美。

一、Spring通過注解導(dǎo)入Bean大體可分為四種方式,我們主要來說以下Import的兩種實(shí)現(xiàn)方法:

1、通過實(shí)現(xiàn)ImportSerlector接口,實(shí)現(xiàn)Bean加載:

public class TestServiceImpl {
 public void testImpl() {
 System.out.println("我是通過importSelector導(dǎo)入進(jìn)來的service");
 }
}
public class TestService implements ImportSelector {
 @Override
 public String[] selectImports(AnnotationMetadata annotationMetadata) {
 return new String[]{"com.ycdhz.service.TestServiceImpl"};
 }
}
@Configuration
@Import(value = {TestService.class})
public class TestConfig {
}
public class TestController {
 @Autowired
 private TestServiceImpl testServiceImpl;
 
 @RequestMapping("testImpl")
 public String testTuling() {
 testServiceImpl.testImpl();
 return "Ok";
 }
}

2、 通過實(shí)現(xiàn)ImportSerlector接口,實(shí)現(xiàn)Bean加載:

public class TestService {
 public TestService() {
 System.out.println("我是通過ImportBeanDefinitionRegistrar導(dǎo)入進(jìn)來的組件");
 }
}
public class TestImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
 @Override
 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
 //定義一個(gè)BeanDefinition
 RootBeanDefinition beanDefinition = new RootBeanDefinition(TestService.class);
 //把自定義的bean定義導(dǎo)入到容器中
 registry.registerBeanDefinition("testService",beanDefinition);
 }
}
@Configuration
@Import(TestImportBeanDefinitionRegistrar.class)
public class TestConfig {
}

二、 Springboot啟動(dòng)過程中會(huì)自動(dòng)裝配

我們從spring-boot-autoconfigure-2.0.6.RELEASE.jar下搜索到Tomcat的相關(guān)配置,發(fā)現(xiàn)有兩個(gè)自動(dòng)裝配類,分別包含了三個(gè)定制器(面向?qū)ο蟮膯我宦氊?zé)原則),還有一個(gè)工廠類。

springboot中如何利用Tomcat容器實(shí)現(xiàn)自啟動(dòng)

2.1、TomcatWebServerFactoryCustomizer:定制Servlet和Reactive服務(wù)器通用的Tomcat特定功能。

public class TomcatWebServerFactoryCustomizer implements
 WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>, Ordered {
 @Override
 public void customize(ConfigurableTomcatWebServerFactory factory) {
 ServerProperties properties = this.serverProperties;
 ServerProperties.Tomcat tomcatProperties = properties.getTomcat();
 PropertyMapper propertyMapper = PropertyMapper.get();
 propertyMapper.from(tomcatProperties::getBasedir).whenNonNull()
 .to(factory::setBaseDirectory);
 propertyMapper.from(tomcatProperties::getBackgroundProcessorDelay).whenNonNull()
 .as(Duration::getSeconds).as(Long::intValue)
 .to(factory::setBackgroundProcessorDelay);
 customizeRemoteIpValve(factory);
 propertyMapper.from(tomcatProperties::getMaxThreads).when(this::isPositive)
 .to((maxThreads) -> customizeMaxThreads(factory,
  tomcatProperties.getMaxThreads()));
 propertyMapper.from(tomcatProperties::getMinSpareThreads).when(this::isPositive)
 .to((minSpareThreads) -> customizeMinThreads(factory, minSpareThreads));
 propertyMapper.from(() -> determineMaxHttpHeaderSize()).when(this::isPositive)
 .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory,
  maxHttpHeaderSize));
 propertyMapper.from(tomcatProperties::getMaxHttpPostSize)
 .when((maxHttpPostSize) -> maxHttpPostSize != 0)
 .to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory,
  maxHttpPostSize));
 propertyMapper.from(tomcatProperties::getAccesslog)
 .when(ServerProperties.Tomcat.Accesslog::isEnabled)
 .to((enabled) -> customizeAccessLog(factory));
 propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull()
 .to(factory::setUriEncoding);
 propertyMapper.from(properties::getConnectionTimeout).whenNonNull()
 .to((connectionTimeout) -> customizeConnectionTimeout(factory,
  connectionTimeout));
 propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive)
 .to((maxConnections) -> customizeMaxConnections(factory, maxConnections));
 propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive)
 .to((acceptCount) -> customizeAcceptCount(factory, acceptCount));
 customizeStaticResources(factory);
 customizeErrorReportValve(properties.getError(), factory);
 }
}

2.2、ServletWebServerFactoryCustomizer:WebServerFactoryCustomizer 將ServerProperties屬性應(yīng)用于Tomcat web服務(wù)器。

public class ServletWebServerFactoryCustomizer implements
 WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
 private final ServerProperties serverProperties;
 public ServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
 this.serverProperties = serverProperties;
 }
 @Override
 public int getOrder() {
 return 0;
 }
 @Override
 public void customize(ConfigurableServletWebServerFactory factory) {
 PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
 map.from(this.serverProperties::getPort).to(factory::setPort);
 map.from(this.serverProperties::getAddress).to(factory::setAddress);
 map.from(this.serverProperties.getServlet()::getContextPath)
 .to(factory::setContextPath);
 map.from(this.serverProperties.getServlet()::getApplicationDisplayName)
 .to(factory::setDisplayName);
 map.from(this.serverProperties.getServlet()::getSession).to(factory::setSession);
 map.from(this.serverProperties::getSsl).to(factory::setSsl);
 map.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp);
 map.from(this.serverProperties::getCompression).to(factory::setCompression);
 map.from(this.serverProperties::getHttp2).to(factory::setHttp2);
 map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);
 map.from(this.serverProperties.getServlet()::getContextParameters)
 .to(factory::setInitParameters);
 }
}

2.3、ServletWebServerFactoryCustomizer :WebServerFactoryCustomizer 將ServerProperties屬性應(yīng)用于Tomcat web服務(wù)器。

public class TomcatServletWebServerFactoryCustomizer
 implements WebServerFactoryCustomizer<TomcatServletWebServerFactory>, Ordered {
 private final ServerProperties serverProperties;
 public TomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
 this.serverProperties = serverProperties;
 }
 @Override
 public void customize(TomcatServletWebServerFactory factory) {
 ServerProperties.Tomcat tomcatProperties = this.serverProperties.getTomcat();
 if (!ObjectUtils.isEmpty(tomcatProperties.getAdditionalTldSkipPatterns())) {
 factory.getTldSkipPatterns()
  .addAll(tomcatProperties.getAdditionalTldSkipPatterns());
 }
 if (tomcatProperties.getRedirectContextRoot() != null) {
 customizeRedirectContextRoot(factory,
  tomcatProperties.getRedirectContextRoot());
 }
 if (tomcatProperties.getUseRelativeRedirects() != null) {
 customizeUseRelativeRedirects(factory,
  tomcatProperties.getUseRelativeRedirects());
 }
 }
}

三、有了TomcatServletWebServerFactory,相當(dāng)于有了Spring加載的入口

通過AbstractApplicationContext#onReFresh()在IOC 容器中的帶動(dòng)tomcat啟動(dòng),然后在接著執(zhí)行 ioc容器的其他步驟。

我們通過斷點(diǎn)可以觀察Tomcat加載的整個(gè)生命周期,以及三個(gè)定制器的加載過程。

springboot中如何利用Tomcat容器實(shí)現(xiàn)自啟動(dòng)

@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
 Tomcat tomcat = new Tomcat();
 File baseDir = (this.baseDirectory != null) ? this.baseDirectory
 : createTempDir("tomcat");
 tomcat.setBaseDir(baseDir.getAbsolutePath());
 Connector connector = new Connector(this.protocol);
 tomcat.getService().addConnector(connector);
 customizeConnector(connector);
 tomcat.setConnector(connector);
 //設(shè)置是否自動(dòng)啟動(dòng)
 tomcat.getHost().setAutoDeploy(false);
 //創(chuàng)建Tomcat引擎
 configureEngine(tomcat.getEngine());
 for (Connector additionalConnector : this.additionalTomcatConnectors) {
 tomcat.getService().addConnector(additionalConnector);
 }
 //刷新上下文
 prepareContext(tomcat.getHost(), initializers);
 //準(zhǔn)備啟動(dòng)
 return getTomcatWebServer(tomcat);
}
private void initialize() throws WebServerException {
 TomcatWebServer.logger
 .info("Tomcat initialized with port(s): " + getPortsDescription(false));
 synchronized (this.monitor) {
 try {
 addInstanceIdToEngineName();
 Context context = findContext();
 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.
  removeServiceConnectors();
 }
 });
 // Start the server to trigger initialization listeners
 this.tomcat.start();
 // We can re-throw failure exception directly in the main thread
 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
 startDaemonAwaitThread();
 }
 catch (Exception ex) {
 stopSilently();
 throw new WebServerException("Unable to start embedded Tomcat", ex);
 }
 }
}

備注: 在這個(gè)過程中我們需要了解Bean的生命周期,Tomcat的三個(gè)定制器均在BeanPostProcessorsRegistrar(Bean后置處理器)過程中加載;

構(gòu)造方法-->Bean后置處理器Before-->InitializingBean-->init-method-->Bean后置處理器After

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
  org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
 throws BeanCreationException {
 // Instantiate the bean.
 BeanWrapper instanceWrapper = null;
 if (mbd.isSingleton()) {
 instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
 }
 if (instanceWrapper == null) {
 //構(gòu)造方法
 instanceWrapper = createBeanInstance(beanName, mbd, args);
 }
 final Object bean = instanceWrapper.getWrappedInstance();
 Class<?> beanType = instanceWrapper.getWrappedClass();
 if (beanType != NullBean.class) {
 mbd.resolvedTargetType = beanType;
 }
 // Initialize the bean instance.
 ......
 return exposedObject;
}
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
 if (System.getSecurityManager() != null) {
 AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
 invokeAwareMethods(beanName, bean);
 return null;
 }, getAccessControlContext());
 }
 else {
 invokeAwareMethods(beanName, bean);
 }
 Object wrappedBean = bean;
 if (mbd == null || !mbd.isSynthetic()) {
 //Bean后置處理器Before
 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
 }
 try {
 invokeInitMethods(beanName, wrappedBean, mbd);
 }
 catch (Throwable ex) {
 throw new BeanCreationException(
 (mbd != null ? mbd.getResourceDescription() : null),
 beanName, "Invocation of init method failed", ex);
 }
 if (mbd == null || !mbd.isSynthetic()) {
 //Bean后置處理器After
 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 }
 return wrappedBean;
}

以上就是關(guān)于“springboot中如何利用Tomcat容器實(shí)現(xiàn)自啟動(dòng)”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

標(biāo)題名稱:springboot中如何利用Tomcat容器實(shí)現(xiàn)自啟動(dòng)
文章位置:http://muchs.cn/article20/jeppjo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站微信公眾號(hào)、微信小程序、網(wǎng)站排名、服務(wù)器托管、做網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化