承接前文springboot情操陶冶-@SpringBootApplication注解解析,在前文讲解的基础上依次看下web方面的相关配置 环境包依赖 在 上述的三行依赖代码便完成了对web环境的配置,此时可以直接运行main()方法 默认服务是挂载在Tomcat容器中,端口为8080。所以可以通过该链接直接访问http://127.0.0.1:8080便可得到以下页面(未配置index页面的效果) 应用端口和上下文配置 本文将在上文的基础山讲解端口和上下文路径的具体配置以及解析。现附上简单的步骤操作 创建application-servlet.properties文件,专门用于配置应用服务 在application.properties文件中指定激活的profile,用于使上述文件生效 为了使界面变得稍微友好,引入index.html文件,放置于static目录下,如下 继续运行对应的main()函数,便可访问http://127.0.0.1:9001/demoWeb,得到以下结果 源码剖析 关于Tomcat等容器的配置,springboot采用了EmbeddedWebServerFactoryCustomizerAutoConfiguration和ServletWebServerFactoryAutoConfiguration两个类便完成了。笔者针对这两个类进行简单的分析 EmbeddedWebServerFactoryCustomizerAutoConfiguration 直接查看其内部源码,如下 主要是引入了ServerProperties配置类,而其是读取spring上下文环境中的以server为开头的属性,简单的看下 样例中的port/servlet.context-path便是保存在ServerProperties对象中的,具体其内部的属性本文就不展开了,读者可自行去阅读源码。由上述的简单代码得知该自动配置类主要根据classpath环境创建不同的应用容器,默认springboot集成的都是tomcat。我们此处只关注下TomcatWebServerFactoryCustomizer类,下文中会有所提及 ServletWebServerFactoryAutoConfiguration 具体的ServletWebServer容器配置是通过ServletWebServerFactoryAutoConfiguration来创建的,由于代码过长笔者分为几个部分来讲解 头上注解先瞧一发 要想本自动配置生效则必须classpath环境中存在 创建webServerFactory类 这两个bean类和上文中的TomcatWebServerFactoryCustomizer很相似,但仔细阅读源码之后便发现其实这只是tomcat配置的分工处理,小结如下 通过上述的三个bean类便基本完成了基本的tomcat配置,其都是WebServerFactoryCustomizer接口的实现类,那么是被谁来统一调用以完成上述的配置呢? 1.首先引入了WebServerFactory工厂类,此点可直接看由上述@Import引入的EmbeddedTomcat分析可得 创建了TomcatServletWebServerFactory的tomcat容器,其余的web容器读者可自行分析 2.最后通过beanPostProcessor接口来完成相应的容器初始化由@Import引入的BeanPostProcessorsRegistrar类,注册了webServerFactoryCustomizerBeanPostProcessor类来完成相应的tomcat个性化配置 具体的解析见上述的代码注释,其实也很简单并一目了然,所以如果用户想在tomcat上再作个性化的需求,可自行实现WebServerFactoryCustomizer接口并注册至bean工厂即可 小结 本文只讲述tomcat的相关配置,并举例说明了其port/contextPath的应用配置,更多的配置读者可采用springboot实现的带server前缀的配置以及自行实现WebServerFactoryCustomizer接口去实现pom.xml
文件中引入web依赖,炒鸡简单,如下<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>
package com.example.demospringbootweb;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class DemoSpringbootWebApplication { public static void main(String[] args) { SpringApplication.run(DemoSpringbootWebApplication.class, args); }}
#server application configserver.port=9001server.servlet.context-path=/demoWeb
spring.profiles.active=servlet
@Configuration@EnableConfigurationProperties(ServerProperties.class)public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {}
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)public class ServerProperties { @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); } }}
@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 {}
ServletRequest.class
等servlet环境依赖类,这一般引入开头的starter-web
版块便基本满足了 @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); }
@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(); } }
// 初始化上述的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(); }
@Configurationpublic MyWebServerFactoryCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>{ @Override public void customize(ConfigurableServletWebServerFactory factory) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); // do personal binding }}