<menu id="ycqsw"></menu><nav id="ycqsw"><code id="ycqsw"></code></nav>
<dd id="ycqsw"><menu id="ycqsw"></menu></dd>
  • <nav id="ycqsw"></nav>
    <menu id="ycqsw"><strong id="ycqsw"></strong></menu>
    <xmp id="ycqsw"><nav id="ycqsw"></nav>
  • 嵌入式tomcatn優缺點(簡述嵌入式tomcat的原理)


    準備工作

    我們知道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);
     }
     }
     }
    }
    

    首先看一下上方的幾個注解

    1. @AutoConfigureOrder這個注解是決定配置類的加載順序的,當注解里的值越小越先加載,而Ordered.HIGHEST_PRECEDENCE的值是Integer.MIN_VALUE也就是說這個類肯定是最先加載的那一批
    2. @ConditionalOnXXX在之前的文章中已經無數次提到了,就不再闡述了
    3. @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就是這個類中屬性

    1. @Import引入了4個類,看都是什么吧
    2. 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的作用稍后再詳細介紹

    1. 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

    其他兩個相信大家都知道怎么回事了

    1. 除了這些這個類還注入了兩個類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);
     }
     }
     }
    

    版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至 舉報,一經查實,本站將立刻刪除。

    發表評論

    登錄后才能評論
    国产精品区一区二区免费