• 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接口去实现

  • 相关阅读:
    P4315 月下“毛景树”
    P1505 [国家集训队]旅游
    P3258 [JLOI2014]松鼠的新家
    P4116 Qtree3
    P2580 于是他错误的点名开始了
    P3038 [USACO11DEC]牧草种植Grass Planting
    P3128 [USACO15DEC]最大流Max Flow
    P2146 [NOI2015]软件包管理器
    P2590 [ZJOI2008]树的统计
    P3384 【模板】树链剖分
  • 原文地址:https://www.cnblogs.com/question-sky/p/9580060.html
Copyright © 2020-2023  润新知