zoukankan      html  css  js  c++  java
  • 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接口去实现

  • 相关阅读:
    浙大数据结构课后习题 练习二 7-2 Reversing Linked List (25 分)
    浙大数据结构课后习题 练习二 7-2 一元多项式的乘法与加法运算 (20 分)
    浙大数据结构课后习题 练习一 7-1 Maximum Subsequence Sum (25 分)
    浙大数据结构课后习题 练习一 7-1 最大子列和问题 (20 分)
    PAT Basic 1019 数字黑洞 (20 分)
    PAT Basic 1017 A除以B (20 分)
    PAT Basic 1013 数素数 (20 分)
    PAT Basic 1007 素数对猜想 (20 分)
    PAT Basic 1003 我要通过! (20 分)
    自动化运维——HelloWorld(一)
  • 原文地址:https://www.cnblogs.com/question-sky/p/9580060.html
Copyright © 2011-2022 走看看