springboot情操陶冶-web配置(一)


承接前文springboot情操陶冶-@SpringBootApplication注解解析,在前文講解的基礎上依次看下web方面的相關配置

環境包依賴

pom.xml文件中引入web依賴,炒雞簡單,如下

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

上述的三行依賴代碼便完成了對web環境的配置,此時可以直接運行main()方法

package com.example.demospringbootweb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoSpringbootWebApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoSpringbootWebApplication.class, args);
    }
}

默認服務是掛載在Tomcat容器中,端口為8080。所以可以通過該鏈接直接訪問http://127.0.0.1:8080便可得到以下頁面(未配置index頁面的效果)404_page

應用端口和上下文配置

本文將在上文的基礎山講解端口和上下文路徑的具體配置以及解析。現附上簡單的步驟操作


創建application-servlet.properties文件,專門用於配置應用服務

#server application config
server.port=9001
server.servlet.context-path=/demoWeb

application.properties文件中指定激活的profile,用於使上述文件生效

spring.profiles.active=servlet

為了使界面變得稍微友好,引入index.html文件,放置於static目錄下,如下static_resource


繼續運行對應的main()函數,便可訪問http://127.0.0.1:9001/demoWeb,得到以下結果index_page

源碼剖析

關於Tomcat等容器的配置,springboot采用了EmbeddedWebServerFactoryCustomizerAutoConfigurationServletWebServerFactoryAutoConfiguration兩個類便完成了。筆者針對這兩個類進行簡單的分析

EmbeddedWebServerFactoryCustomizerAutoConfiguration

直接查看其內部源碼,如下

@Configuration
@EnableConfigurationProperties(ServerProperties.class)
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
	@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
	public static class TomcatWebServerFactoryCustomizerConfiguration {

		@Bean
		public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(
				Environment environment, ServerProperties serverProperties) {
			return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
		}

	}

	/**
	 * Nested configuration if Jetty is being used.
	 */
	@Configuration
	@ConditionalOnClass({ Server.class, Loader.class, WebAppContext.class })
	public static class JettyWebServerFactoryCustomizerConfiguration {

		@Bean
		public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(
				Environment environment, ServerProperties serverProperties) {
			return new JettyWebServerFactoryCustomizer(environment, serverProperties);
		}

	}

	/**
	 * Nested configuration if Undertow is being used.
	 */
	@Configuration
	@ConditionalOnClass({ Undertow.class, SslClientAuthMode.class })
	public static class UndertowWebServerFactoryCustomizerConfiguration {

		@Bean
		public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(
				Environment environment, ServerProperties serverProperties) {
			return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
		}

	}
}

主要是引入了ServerProperties配置類,樣例中的server.port/server.servlet.context-path便是保存在ServerProperties對象中的,其是讀取spring上下文環境中的以server為開頭的屬性,具體的屬性用戶可自行查看源碼。

由上述的簡單代碼得知該自動配置類主要根據classpath環境創建不同的應用容器,默認springboot集成的都是tomcat。我們此處只關注下TomcatWebServerFactoryCustomizer類,下文中會有所提及

ServletWebServerFactoryAutoConfiguration

具體的ServletWebServer容器配置是通過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 {
}

要想本自動配置生效則必須classpath環境中存在ServletRequest.class等servlet環境依賴類,這一般引入開頭的starter-web版塊便基本滿足了


創建webServerFactory個性化配置類

	@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);
	}

這兩個bean類和上文中的TomcatWebServerFactoryCustomizer很相似,但仔細閱讀源碼之后便發現其實這只是tomcat配置的分工處理,小結如下

  • TomcatWebServerFactoryCustomizer 配置tomcat的主要信息,包含remoteIpValue、connector(最大/最小可接收線程、最大可接收頭部大小等等)、uriEncoding、connectionTimeout、maxConnection等屬性
  • TomcatServletWebServerFactoryCustomizer 配置tomcat的額外信息,redirectContextRoot(是否在請求根上下文時轉發,true則轉發路徑為/demoWeb/)和useRelativeRedirects(是否使用相對路徑)等路徑跳轉問題處理
  • ServletWebServerFactoryCustomizer 主要配置tomcat的servlet的信息,包含端口、上下文路徑、應用名、Session配置、Servlet攜帶的初始變量等等

通過上述的三個bean類便基本完成了基本的tomcat配置,其都是WebServerFactoryCustomizer接口的實現類,那么是被誰來統一調用以完成上述的配置呢?


1.首先引入了WebServerFactory工廠類,此點可直接看由上述@Import引入的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();
		}

	}

創建了TomcatServletWebServerFactory的tomcat容器,其余的web容器讀者可自行分析


2.最后通過beanPostProcessor接口來完成相應的容器初始化
@Import引入的BeanPostProcessorsRegistrar類,注冊了webServerFactoryCustomizerBeanPostProcessor類來完成相應的tomcat個性化配置

    // 初始化上述的WebServerFactory對象前操作
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof WebServerFactory) {
            this.postProcessBeforeInitialization((WebServerFactory)bean);
        }

        return bean;
    }

	// 調用所有實現了WebServerFactoryCustomizer接口的對象
    private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
        ((Callbacks)LambdaSafe.callbacks(WebServerFactoryCustomizer.class, this.getCustomizers(), webServerFactory, new Object[0]).withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)).invoke((customizer) -> {
            customizer.customize(webServerFactory);
        });
    }
	
	// 查找當前bean工廠中所有類型為WebServerFactoryCustomizer接口對象集合
    private Collection<WebServerFactoryCustomizer<?>> getCustomizers() {
        if (this.customizers == null) {
            this.customizers = new ArrayList(this.getWebServerFactoryCustomizerBeans());
            this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
            this.customizers = Collections.unmodifiableList(this.customizers);
        }

        return this.customizers;
    }

    private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() {
        return this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();
    }

具體的解析見上述的代碼注釋,其實也很簡單並一目了然,所以如果用戶想在tomcat上再作個性化的需求,可自行實現WebServerFactoryCustomizer接口並注冊至bean工廠即可

@Configuration
public MyWebServerFactoryCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>{
	@Override
	public void customize(ConfigurableServletWebServerFactory factory) {
		PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
		// do personal binding
	}
}

小結

本文只講述tomcat的相關配置,並舉例說明了其port/contextPath的應用配置,更多的配置讀者可采用springboot實現的帶server前綴的配置以及自行實現WebServerFactoryCustomizer接口去實現


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM