SpringBoot配置嵌入式的Servlet

SpringBoot默认使用Tomcat作为嵌入式的Servlet

问题?

1)、如何定制和修改Servlet容器的相关配置;

server.port=8081
server.context-path=/crud

server.tomcat.uri-encoding=UTF-8

//通用的Servlet容器设置
server.xxx
//Tomcat的设置
server.tomcat.xxx

注:在2.0之前的版本当中可以使用以下方式修改 Servlet  (EmbeddedServletContainerCustomizer   为 ServerProperties  父类)

@Bean  //一定要将这个定制器加入到容器中
public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
    return new EmbeddedServletContainerCustomizer() {

        //定制嵌入式的Servlet容器相关的规则
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            container.setPort(8083);
        }
    };
}

 2)、注册Servlet三大组件【Servlet、Filter、Listener】

由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件。

注册三大组件用以下方式

ServletRegistrationBean

@Bean
public ServletRegistrationBean myServlet(){
    ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
    return registrationBean;
}

public class MyServlet extends HttpServlet {    //处理get请求    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        doPost(req,resp);    }

    @Override    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        resp.getWriter().write("Hello MyServlet");    }}

FilterRegistrationBean

@Bean
public FilterRegistrationBean myFilter(){
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    registrationBean.setFilter(new MyFilter());
    registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
    return registrationBean;
}

public class MyFilter implements Filter {    @Override    public void init(FilterConfig filterConfig) throws ServletException {    }    @Override    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {        System.out.println("MyFilter process...");        chain.doFilter(request,response);    }

    @Override    public void destroy() {    }}

ServletListenerRegistrationBean

@Bean
public ServletListenerRegistrationBean myListener(){
    ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());
    return registrationBean;
}

public class MyListener implements ServletContextListener {    @Override    public void contextInitialized(ServletContextEvent sce) {        System.out.println("contextInitialized...web应用启动");    }

    @Override    public void contextDestroyed(ServletContextEvent sce) {        System.out.println("contextDestroyed...当前web项目销毁");    }}

这种注册方式最好的例子(注册  DIspatcherServlet

SpringBoot帮我们自动SpringMVC的时候,自动的注册SpringMVC的前端控制器;DIspatcherServlet

DispatcherServletAutoConfiguration中:

 @Bean(
            name = {"dispatcherServletRegistration"}
        )
        @ConditionalOnBean(
            value = {DispatcherServlet.class},
            name = {"dispatcherServlet"}
        )
        public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
     //默认拦截: /  所有请求;包静态资源,但是不拦截jsp请求;   /*会拦截jsp    //可以通过  spring.mvc.servlet.path  (之前版本是server.servletPath)  来修改SpringMVC前端控制器默认拦截的请求路径 DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet, webMvcProperties.getServlet().getPath());
            registration.setName("dispatcherServlet");
            registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
            multipartConfig.ifAvailable(registration::setMultipartConfig);
            return registration;
        }

2)、SpringBoot能不能支持其他的Servlet容器;

Spring Boot 的 web 项目默认使用嵌入式的 Tomcat 服务器,同时它也支持程序员自己切换 内置的 Servlet 容器,如 Jetty 、Undertow

Jetty 支持长连接,对于页面与服务器类似建立长连接聊天式的性能很好,

Undertow   高性能非阻塞的,并发性能非常好,但是不支持JSP

Tomcat 与 Undertow 对比
1、Tomcat
是 Apache 基金下的一个轻量级的 Servlet 容器,支持 Servlet 和 JSP。Tomcat 具有 Web
服务器特有的功能,包括 Tomcat 管理和控制平台、安全局管理和 Tomcat 阀等。Tomcat 本身包含了 HTTP
服务器,因此也可以视作单独的 Web 服务器。
2、但是,Tomcat 和 ApacheHTTP 服务器不是同一个东西,ApacheHTTP 服务器是用 C 语言实现的 HTTP Web 服务器。Tomcat 是完全免费的,深受开发者的喜爱。
3、Undertow
是 Red Hat 公司的开源产品, 它完全采用 Java 语言开发,是一款灵活的高性能 Web 服务器,支持阻塞 IO 和非阻塞 IO。由于
Undertow 采用 Java 语言开发,可以直接嵌入到 Java 项目中使用。同时,Undertow 完全支持 Servlet 和 Web
Socket,在高并发情况下表现非常出色。

3)、替换为其他嵌入式Servlet容器

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnWebApplication
@EnableConfigurationProperties({ServerProperties.class})
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
    public EmbeddedWebServerFactoryCustomizerAutoConfiguration() {

默认支持:

Tomcat(默认使用)

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>引入web模块默认就是使用嵌入式的Tomcat作为Servlet容器;

Jetty

<!-- 引入web模块 -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
   <exclusions>
      <exclusion>
         <artifactId>spring-boot-starter-tomcat</artifactId>
         <groupId>org.springframework.boot</groupId>
      </exclusion>
   </exclusions>
</dependency>

<!--引入其他的Servlet容器-->
<dependency>
   <artifactId>spring-boot-starter-jetty</artifactId>
   <groupId>org.springframework.boot</groupId>
</dependency>

Undertow

<!-- 引入web模块 -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
   <exclusions>
      <exclusion>
         <artifactId>spring-boot-starter-tomcat</artifactId>
         <groupId>org.springframework.boot</groupId>
      </exclusion>
   </exclusions>
</dependency>

<!--引入其他的Servlet容器-->
<dependency>
   <artifactId>spring-boot-starter-undertow</artifactId>
   <groupId>org.springframework.boot</groupId>
</dependency>

4)、嵌入式Servlet容器自动配置原理;

  springboot2.x前后在配置化 Servlet 容器的方式是不同的,

  创建工厂之前容器属性的配置方式

    ①2.x之前采用后置处理器的方式

    ②2.x之后直接采用启用配置的方式

2.x之后的方式

@AutoConfigureOrder(-2147483648)
@ConditionalOnClass({ServletRequest.class})
@ConditionalOnWebApplication(
    type = Type.SERVLET
)//启动自动配置
@EnableConfigurationProperties({ServerProperties.class})//根据条件给容器中导入嵌入式的容器
@Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class})
public class ServletWebServerFactoryAutoConfiguration {
    public ServletWebServerFactoryAutoConfiguration() {
    }

    @Bean
    public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
        return new ServletWebServerFactoryCustomizer(serverProperties);
    }

以导入Tomcat为例,查看Tomcat依赖组件,如果满足则导入tomcat工厂,以此获取Tomcat容器

通过Tomcat工厂获取tomcat容器的代码如下

@Override
	public WebServer getWebServer(ServletContextInitializer... initializers) {
		if (this.disableMBeanRegistry) {
			Registry.disableRegistry();
		}                //创建一个Tomcat
		Tomcat tomcat = new Tomcat();
		File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");                //配置Tomcat的基本环节
		tomcat.setBaseDir(baseDir.getAbsolutePath());
		Connector connector = new Connector(this.protocol);
		connector.setThrowOnFailure(true);
		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);               //将配置好的Tomcat传入进去,返回一个 TomcatWebServer ;并且启动Tomcat服务器
		return getTomcatWebServer(tomcat);
	}

启动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 {
		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) {
				stopSilently();
				destroySilently();
				throw new WebServerException("Unable to start embedded Tomcat", ex);
			}
		}
	}

2.0之后的启动步骤

配置文件初始化----》容器工厂的初始化

2.x之前的方式

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
//导入BeanPostProcessorsRegistrar:Spring注解版;给容器中导入一些组件
//导入了EmbeddedServletContainerCustomizerBeanPostProcessor:
//后置处理器:bean初始化前后(创建完对象,还没赋值赋值)执行初始化工作
public class EmbeddedServletContainerAutoConfiguration {

    @Configuration
	@ConditionalOnClass({ Servlet.class, Tomcat.class })//判断当前是否引入了Tomcat依赖;
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)//判断当前容器没有用户自己定义EmbeddedServletContainerFactory:嵌入式的Servlet容器工厂;作用:创建嵌入式的Servlet容器
	public static class EmbeddedTomcat {

		@Bean
		public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
			return new TomcatEmbeddedServletContainerFactory();
		}

	}

    /**
	 * Nested configuration if Jetty is being used.
	 */
	@Configuration
	@ConditionalOnClass({ Servlet.class, Server.class, Loader.class,
			WebAppContext.class })
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedJetty {

		@Bean
		public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
			return new JettyEmbeddedServletContainerFactory();
		}

	}

	/**
	 * Nested configuration if Undertow is being used.
	 */
	@Configuration
	@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedUndertow {

		@Bean
		public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() {
			return new UndertowEmbeddedServletContainerFactory();
		}

	}
//初始化之前
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
      throws BeansException {
    //如果当前初始化的是一个ConfigurableEmbeddedServletContainer类型的组件
   if (bean instanceof ConfigurableEmbeddedServletContainer) {
       //
      postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
   }
   return bean;
}

private void postProcessBeforeInitialization(
			ConfigurableEmbeddedServletContainer bean) {
    //获取所有的定制器,调用每一个定制器的customize方法来给Servlet容器进行属性赋值;
    for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
        customizer.customize(bean);
    }
}

private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
    if (this.customizers == null) {
        // Look up does not include the parent context
        this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
            this.beanFactory
            //从容器中获取所有这葛类型的组件:EmbeddedServletContainerCustomizer
            //定制Servlet容器,给容器中可以添加一个EmbeddedServletContainerCustomizer类型的组件
            .getBeansOfType(EmbeddedServletContainerCustomizer.class,
                            false, false)
            .values());
        Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
        this.customizers = Collections.unmodifiableList(this.customizers);
    }
    return this.customizers;
}

ServerProperties也是定制器

2.x之前的初始化步骤:

1)、SpringBoot根据导入的依赖情况,给容器中添加相应的EmbeddedServletContainerFactory【TomcatEmbeddedServletContainerFactory】

2)、容器中某个组件要创建对象就会惊动后置处理器;EmbeddedServletContainerCustomizerBeanPostProcessor;

只要是嵌入式的Servlet容器工厂,后置处理器就工作;

3)、后置处理器,从容器中获取所有的EmbeddedServletContainerCustomizer,调用定制器的定制方法

原文地址:https://www.cnblogs.com/tombky/p/12579524.html

时间: 03-26

SpringBoot配置嵌入式的Servlet的相关文章

SpringBoot配置详解

SpringBoot配置详解 SpringBoot自动化配置 在上一节中我们使用Spring Boot实现了一个简单的RESTful API应用,在实现过程中,除了Maven的pom文件的一些配置,我们没有做任何其他的配置,这就是Spring Boot的自动化配置带来的好处,但是,我们还需要了解如何在Spring Boot中修改这些自动化配置的内容,以应对一些特殊的场景需求. 配置文件—Spring Boot支持YAML配置文件和properties配置文件 Spring Boot的默认配置文件

springboot 配置Ehcache

Ehcache的基本配置说明我就不说了.小编记录一下在springboot中使用Ehcache的使用方法. 第一步:在classpath下引入配置文件ehcache.xml 代码如下: <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd"> <cache name="demo&qu

SpringBoot 配置富文本编辑器 xheditor

一年前写过一篇:struts2 配置 xheditor 的文章.那时候还在用ssh,现在开始用spring boot.本来想配置CSDN的markdown编辑器的,可惜在github上找不到.所以,还是用回轻巧的xheditor吧. 环境要求:Spring Boot v1.5.1.RELEASE.jdk1.7.myeclipse2015 .xheditor1.1.14 xheditoe的官网好像下不了,我把xheditor1.1.14的压缩包上传到资源那里了,点击进入xheditor1.1.14

Spring-boot 配置Aop获取controller里的request中的参数以及其返回值

首先在你的Maven的pom文件里加入aop的依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> 1 2 3 4 在spring boot里面一切配置都是很简单的,下面为我所有被请求到的controller加上Aop的功能吧,看码: pack

tomcat上servlet程序的配置与处理servlet请求过程

手动配置: tomcat服务器下web项目的基本目录结构 |-tomcat根目录 |-webapps |-WebRoot : web应用的根目录 |-静态资源(html+css+js+image+vedio) |-WEB-INF : 固定写法. |-classes: (可选)固定写法.存放class字节码文件 |-lib: (可选)固定写法.存放jar包文件. |-web.xml 什么事servlet?用java语言来编写动态资源的开发技术,一个继承至HttpServlet类的普通类. 手写一个

JavaWeb核心编程之(三)Servlet配置

Servlet配置 1.配置Serlvet加载时机 2.配置多映射 配置加载时机 新建项目config->创建包com.xiaoan.config->创建类FirstServlet implements Servlet(实现Servlet接口) ->创建类SoundServlet(也实现Servlet接口) 配置web.xml 先配置两个Servlet实现类的Servlet 1 <?xml version="1.0" encoding="UTF-8&q

web.xml配置 去除servlet访问后缀

说明下修改需求:以前项目访问路径配置了后缀名.do---------项目为springmvc架构 如访问主页就是localhost/portal/index.do或是localhost/portal/user/login.do这样看起来很让我不爽所以来动手改成localhost/portal/user/login就好了 直接来看配置吧 1,通常情况下,servlet的访问有后缀时,只需匹配*.do即可 <servlet> <servlet-name>SpringDispatcher

springboot 学习笔记(二)--- properties 配置

springboot可以提供了多种方式配置properties. 一.Java System.setProperty(k, v) System.setProperty("myname", "Java_System_name"); 二.在classpath目录下创建配置文件 application.properties 文件内容格式是 KV格式 myname=classpath_name 三.支持嵌套注解 application.properties db=db jd

Java Servlet(二):servlet配置及生命周期相关(jdk7+tomcat7+eclipse)

该篇文章记录了Servlet配置相关用法及Servlet在Servlet容器中生命周期方法. Tomcat是一个Servlet容器: 1.Servlet容器管理了Servlet的整个生命周期,并调用servlet的生命周期的方法. 2.Servlet容器不只是Servlet的生命周期,而且还是Jsp,Filter,Listener,Tag等生命周期管理容器. Servlet的注册与运行 1.Servlet程序必须通过Servlet容器来启动运行,并且存储目录有特殊要求,通常servlet编译好的

springboot-shiro chapter02&mdash;&mdash;springboot webmvc jsp

简介:这一节主要涉及spring boot 支持jsp, 由于对spring boot不太熟悉,走了一些弯路. 环境:IDEA15+JDK1.8+Maven3+ 一.pom.xml资源依赖 相对于chapter01,这里依赖的资源相对多些.没有像chapter01中直接的引用spring-webmvc.spring-boot-starter和spring-boot-tomcat,而是通过引用spring-boot-starter-web资源. 可以看出spring-boot-starter-we