springboot抛弃tomcat容器不用提供web端口,且可以保留依赖

作者:黄小厮
来源:CSDN
原文:https://blog.csdn.net/dwade_mia/article/details/82776125
版权声明:本文为博主原创文章,转载请附上博文链接!


让spring boot抛弃tomcat容器

解决方法

网上提供了很多方法,无外乎是去掉 servlet 或者 spring-web jar包依赖,如果我们项目中不需要这些倒也无所谓,如果模块之间有依赖怎么办,这将是个很麻烦的事。在此,我提供了一种更简单有效的办法,不需要去掉额外的依赖,废话不多说,先上代码:

@SpringBootApplication
public class NoneTomcatApplication {
	public static void main(String[] args) throws InterruptedException {
		SpringApplication application = new SpringApplication( NoneTomcatApplication.class );
		
		// 如果是web环境,默认创建AnnotationConfigEmbeddedWebApplicationContext,因此要指定applicationContextClass属性
		application.setApplicationContextClass( AnnotationConfigApplicationContext.class );
		application.run( args );
		
		// 如果不想让spring容器退出,可以使用以下代码
		CountDownLatch latch = new CountDownLatch( 1 );
		latch.await();
	}
}

代码如上所示,我们为SpringApplication指定初始化的spring容器实现类AnnotationConfigApplicationContext,这样spring boot便不会为我们创建servlet容器了。spring boot在创建spring容器时,会判断当前classpath是否存在javax.servlet.Servlet、org.springframework.web.context.ConfigurableWebApplicationContext,如果同时存在,则默认会初始化可以内嵌servlet容器的AnnotationConfigEmbeddedWebApplicationContext。如果我们为spring boot指定spring容器的实现类时,spring boot便老老实实地为我们创建指定的spring容器

下面,我们分析下spring boot相关的源代码

spring boot源码分析

SpringApplication#run()关键代码如下所示,包括了SpringApplicationRunListeners事件通知、创建Environment、打印Banner文字、创建spring容器、准备上下文、刷新spring容器完成初始化,等等

public ConfigurableApplicationContext run(String... args) {
    ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    ConfigurableEnvironment environment = prepareEnvironment(listeners,
    		applicationArguments);
    Banner printedBanner = printBanner(environment);
    context = createApplicationContext();
    analyzers = new FailureAnalyzers(context);
    prepareContext(context, environment, listeners, applicationArguments,
    		printedBanner);
    refreshContext(context);
    afterRefresh(context, applicationArguments);
    listeners.finished(context, null);
}

创建spring容器的代码如下所示,其中webEnvironment属性在SpringApplication构造函数中便会进行自动检测,默认情况下是不指定applicationContextClass属性的,因此会根据webEnvironment属性来选择applicationContextClass,非web环境下,创建AnnotationConfigApplicationContext,web环境下创建AnnotationConfigEmbeddedWebApplicationContext,如果我们指定,则会按照我们指定的class创建spring容器。因此,在实际的项目中,如果我们不想使用spring boot提供的内嵌servlet容器,只需要指定applicationContextClass属性就好了,当然排除相关的jar包也是一种方法,不过比较麻烦。具体的代码,见前面的代码

protected ConfigurableApplicationContext createApplicationContext() {
	Class<?> contextClass = this.applicationContextClass;
	if (contextClass == null) {
		try {
			contextClass = Class.forName(this.webEnvironment ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
				"Unable create a default ApplicationContext, "
						+ "please specify an ApplicationContextClass", ex);
		}
	}
	return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}

下图是ApplicationContext和BeanFactory相关的类图,红色框内是上面提到的两个重要实现,spring容器在完成一系列的准备工作之后,会调用onRefresh方法用于ApplicationContext子类初始化额外的bean,这是个模板方法,不同spring容器可以实现自己的逻辑,便于扩展实现

在这里插入图片描述
由上图可知,AnnotationConfigEmbeddedWebApplicationContext 继承了 EmbeddedWebApplicationContext,其onRefresh方法的主要逻辑如下所示(省略了异常处理):

@Override
protected void onRefresh() {
	super.onRefresh();
	// 创建servlet容器
	createEmbeddedServletContainer();
}

private void createEmbeddedServletContainer() {
	EmbeddedServletContainer localContainer = this.embeddedServletContainer;
	ServletContext localServletContext = getServletContext();
	// 完成servlet容器的创建、启动
	if (localContainer == null && localServletContext == null) {
		EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
		this.embeddedServletContainer = containerFactory
				.getEmbeddedServletContainer(getSelfInitializer());
	}
	else if (localServletContext != null) {
		getSelfInitializer().onStartup(localServletContext);
	}
	initPropertySources();
}

我们再来看看 AnnotationConfigApplicationContext,在 onRefresh 时没有任何处理。两者的对比很明显了,前者会为我们启动servlet容器,后者do nothing

protected void onRefresh() throws BeansException {
	// For subclasses: do nothing by default.
}

值得一提的,spring boot 2.0 移除了 AnnotationConfigEmbeddedWebApplicationContext,使用 AnnotationConfigServletWebServerApplicationContext 替代,将原有的 org.springframework.boot.context.embedded.EmbeddedServletContainer 抽象成 org.springframework.boot.web.server.WebServer,完全脱离了servlet环境的束缚

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值