当前位置:首页 > 生活百科

嵌入式tomcatn优缺点(简述嵌入式tomcat的原理)

栏目:生活百科日期:2024-12-13浏览:0

准备工作

我们知道SpringBoot的自动装配的秘密在
org.springframework.boot.autoconfigure包下的spring.factories文件中,而嵌入Tomcat的原理就在这个文件中加载的一个配置类:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration

@Configuration@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)@ConditionalOnClass(ServletRequest.class)@ConditionalOnWebApplication(type = Type.SERVLET)@EnableConfigurationProperties(ServerProperties.class)@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, ServletWebServerFactoryConfiguration.EmbeddedJetty.class, ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })public class ServletWebServerFactoryAutoConfiguration { @Bean public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer( ServerProperties serverProperties) { return new ServletWebServerFactoryCustomizer(serverProperties); } @Bean @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat") public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer( ServerProperties serverProperties) { return new TomcatServletWebServerFactoryCustomizer(serverProperties); } /** * 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); } } }}

首先看一下上方的几个注解

@AutoConfigureOrder这个注解是决定配置类的加载顺序的,当注解里的值越小越先加载,而Ordered.HIGHEST_PRECEDENCE的值是Integer.MIN_VALUE也就是说这个类肯定是最先加载的那一批@ConditionalOnXXX在之前的文章中已经无数次提到了,就不再阐述了@EnableConfigurationProperties开启ServerProperties类的属性值配置。而这个类里面包含的就是Web服务的配置

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)public class ServerProperties { private Integer port; private InetAddress address; @NestedConfigurationProperty private final ErrorProperties error = new ErrorProperties(); private Boolean useForwardHeaders; private String serverHeader; private int maxHttpHeaderSize = 0; // bytes private Duration connectionTimeout; @NestedConfigurationProperty private Ssl ssl; @NestedConfigurationProperty private final Compression compression = new Compression(); @NestedConfigurationProperty private final Http2 http2 = new Http2(); private final Servlet servlet = new Servlet(); private final Tomcat tomcat = new Tomcat(); private final Jetty jetty = new Jetty(); private final Undertow undertow = new Undertow();}

这个类的代码太多了,这里就不一一贴出来了,我们平常在application.properties中配置的server.xxx就是这个类中属性

@Import引入了4个类,看都是什么吧BeanPostProcessorsRegistrar

public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware { @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); } } }

这个类注册了两个bean:
WebServerFactoryCustomizerBeanPostProcessor和ErrorPageRegistrarBeanPostProcessor关于这两个bean的作用稍后再详细介绍

EmbeddedTomcat

@Configuration @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) public static class EmbeddedTomcat { @Bean public TomcatServletWebServerFactory tomcatServletWebServerFactory() { return new TomcatServletWebServerFactory(); } }

这个类会在存在Tomcat相关jar包时添加一个
TomcatServletWebServerFactorybean

其他两个相信大家都知道怎么回事了

除了这些这个类还注入了两个类ServletWebServerFactoryCustomizer和TomcatServletWebServerFactoryCustomizer

现在前期准备工作已经做好了,看一下这个Tomcat是如何启动的吧

启动

启动入口在
ServletWebServerApplicationContext中的onRefresh方法

protected void onRefresh() { super.onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); } }

Tomcat的启动就在createWebServer方法里面了

private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); //第一次访问的时候两个对象都为空 if (webServer == null &&&& servletContext == null) { ServletWebServerFactory factory = getWebServerFactory(); this.webServer = factory.getWebServer(getSelfInitializer()); } else if (servletContext != null) { try { getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } initPropertySources(); }

首先看一下getWebServerFactory

protected ServletWebServerFactory getWebServerFactory() { // 这里获取的beanname就是上方注册的tomcatServletWebServerFactory了 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)); } return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class); }

准备环境里注册的bean现在出来一个了。注意,上方还注册了一个后置处理器
EmbeddedServletContainerCustomizerBeanPostProcessor,获取beantomcatServletWebServerFactory的时候就会执行后置处理器的postProcessBeforeInitialization方法

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof WebServerFactory) { postProcessBeforeInitialization((WebServerFactory) bean); } return bean;}private void postProcessBeforeInitialization(WebServerFactory webServerFactory) { LambdaSafe .callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory) .withLogger(WebServerFactoryCustomizerBeanPostProcessor.class) .invoke((customizer) -&> customizer.customize(webServerFactory)); } private Collection&<WebServerFactoryCustomizer&<?&>&> getCustomizers() { if (this.customizers == null) { // Look up does not include the parent context this.customizers = new ArrayList&<&>(getWebServerFactoryCustomizerBeans()); this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE); this.customizers = Collections.unmodifiableList(this.customizers); } return this.customizers; } @SuppressWarnings({ "unchecked", "rawtypes" }) private Collection&<WebServerFactoryCustomizer&<?&>&> getWebServerFactoryCustomizerBeans() { return (Collection) this.beanFactory .getBeansOfType(WebServerFactoryCustomizer.class, false, false).values(); }

这个处理器的作用是获得所有定制器,然后执行定制器的方法

接着往下看

这个时候就可以启动Tomcat了

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); tomcat.getHost().setAutoDeploy(false); configureEngine(tomcat.getEngine()); for (Connector additionalConnector : this.additionalTomcatConnectors) { tomcat.getService().addConnector(additionalConnector); } prepareContext(tomcat.getHost(), initializers); return getTomcatWebServer(tomcat); }protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) { return new TomcatWebServer(tomcat, getPort() &>= 0); }public TomcatWebServer(Tomcat tomcat, boolean autoStart) { Assert.notNull(tomcat, "Tomcat Server must not be null"); this.tomcat = tomcat; this.autoStart = autoStart; initialize(); }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) { throw new WebServerException("Unable to start embedded Tomcat", ex); } } }

“嵌入式tomcatn优缺点(简述嵌入式tomcat的原理)” 的相关文章

创业投资基金概念及案例,创投基金备案有哪些要求

创业投资定义创业投资在国外被称为风险投资(venturecapital)简称VC。创业投资有广义和狭义之分。广义的创业投资泛指一切具有高风险、高潜在收益的投资;...

databinding原理面试(底层原理剖析系列)

前言在前几年兴起了MVVM架构设计模式,最具有代表的框架就是DataBinding,虽然这种设计架构非常新颖,但是在使用中仍然还有很多痛点,所以我当时觉得短时间...

微信朋友圈软文大全分享,教你如何写出吸引人的微信软文

前面几篇静静一直在强调不管怎么发软文,图文并茂很重要,都是图片不配文字看不懂你的意思,都是文字没有图片没人爱看,不管你在哪个渠道发布,一定要记住图文并茂,因为这...

养老保险哪个好,最划算的三个商业养老保险方案

很多朋友对于养老保险不了解,也不知道如何缴纳才是最适合自己的,才能让自己利益最大化。根据我多年的社保工作经验,从切实保障参保人的利益考虑,给您建议如下:一、城镇...

对传统开关于无线动能开关的分析,看看自己能了解到多少

现在说到灯开关,不知道有多少朋友会有同感,经历过那些灯开关时代,1990-95年之前的应该都会多多少少了解些,相信大部分1990年前的朋友还是经历过旧开关时代和...

如何查询商标是否注册,其实很简单只需几个步骤就完成

商标注册查询流程可以自己到中国商标网官方网站进行查询:注册香港商标的费用商标近似查询:查询按图形、文字等商标组成要素分别提供近似检索功能,用户可以自行检索在相同...

00后创业干什么好,最适合00后创业的项目推荐

很多人想知道现在00后适合做哪些工作,做什么职业比较吃香呢?下面小编为大家介绍一下!00后最吃香的十大职业排行榜1、销售提名理由:在每一个发展正常的公司,销售人...

11月LPR报价均与前期保持一致(连续第19月维持不变)

伴随着四季度降准、降息预期逐渐落空,贷款市场报价利率(LPR)依旧岿然不动。11月22日周一,中国货币网数据显示,中国11月一年期和五年期LPR保持不变,分别维...

otg功能是什么(小米手机开启OTG功能)

OTG全称On-The-Go,是一种用于不同可移动设备间数据交换的技术,它兼容USB标准协议,通过该技术可以将USB周边设备转化为主机,与其它设备进行数据交换。...

今日头条作者号怎么注册,今日头条签约作者条件

在今天头条这个平台持续更文已经有一段时间了,我越来越喜欢这个写作平台。尤其是最近参加平台的运营培训后,我对经营一个头条号有了基本的了解,我不再像无头苍蝇一样四处...