springboot浅析

目录

 

背景

试水

总结

思考


背景

   由于springcloud基于boot构建,要了解一些cloud规范的实现,就需要对boot的流程有所了解,而不同boot版本可能有所变化,故基于boot2.3.0来看看启动流程。

试水

    直接上代码,看着代码说事。

@SpringBootApplication
public class GatewaySampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewaySampleApplication.class,args);
    }

}

    通常一个boot应用主类也就是这么个写法,当然还厚builder方式,不纠结,接下来看看执行流程,debug看分2步,1、创建SpringApplication实例,2、执行run方法,看看构造。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

    大致做了1个事,6个字段赋值,资源加载器赋值没啥特殊,主类保存也很普通,webApplicationType这是个啥,话说构建个spring应用要么是web,要么是普通的应用,所以应用要有个web类型(servlet、reactive、none),AppplicationContextInitializer这个东西是个啥看一眼api和介绍,Callback interface for initializing a Spring {@link ConfigurableApplicationContext} prior to being {@linkplain ConfigurableApplicationContext#refresh() refreshed}.说是个回调接口,在ApplicationContext.refresh()之前执行。

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
	void initialize(C applicationContext);
}

    只此1个initialize方法需要个ConfigurableApplicationContext子类作为参数,到这也就能看出在refresh之前执行,能对ApplicationContext做些操作,然而没啥具体的啊,找个子类看看。

public class ServletContextApplicationContextInitializer
		implements ApplicationContextInitializer<ConfigurableWebApplicationContext>, Ordered {
	@Override
	public void initialize(ConfigurableWebApplicationContext applicationContext) {
		applicationContext.setServletContext(this.servletContext);
		if (this.addApplicationContextAttribute) {
			this.servletContext
          .setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
					applicationContext);
		}

	}

   这么一看能把ServletContext整到ApplicationContext里啊,这样看来ApplicationContext就有了对servlet相关组件的操作的能力了啊,先聊到这,接下来看看ApplicationListener,看看api介绍Interface to be implemented by application event listeners.Based on the standard {@code java.util.EventListener} interface for the Observer design pattern.说是需要被应用事件监听器实现,基于标准的java.util.EventListener,这个接口目的是观察者设计模式。

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
	void onApplicationEvent(E event);
}

    函数式接口,要对ApplicationEvent子事件进行处理,说个具体的ConfigFileApplicationListener,这个大家一定都熟悉做环境配置文件映射的入口,构造先说到这里,接下来是run。

public ConfigurableApplicationContext run(String... args) {
		//省略
		ConfigurableApplicationContext context = null;
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new 
                  DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, 
                  applicationArguments);
			context = createApplicationContext();
			prepareContext(context, environment, listeners, applicationArguments, 
                  printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		try {
			listeners.running(context);
		}
		return context;
	}

    省略部分代码后run代码如上,可以看到主要过程参数封装、环境创建、容器创建、容器准备、容器刷新、容器刷新后,第一个组件就是SpringApplicationRunListener,他就是在run执行期间做个监听,发布相应事件,比如prepareEnvironment的时候他就会发布个ApplicationEnvironmentPreparedEvent事件,让环境后置处理器运行起来。

    第二个DefaultApplicationArguments,可以看到是对参数的封装,其内部维护了SimpleCommandLinePropertySource和String数组,对参数进行封装。

    prepareEnviroment不细说,前面有文章聊到过,就是做环境的创建和配置的,也就是各个PropertiesSource的有序添加和profile的激活设置。

    createApplicationContext这个简单就是根据web应用类型来反射创建ApplicationContext,至于web类型是根据项目里有没有引入一些相关类赋的值。

    prepareContext这个大致就是应用初始化器,触发应用监听器,加载主要资源(其中我们的主类就是资源,构造SpringApplication时保存了;另外触发BootstrapApplicationListener还会将BootstrapMarkerConfiguration添加进来),其中加载资源就是让BeanDefinitionLoader按资源类型加载资源注册bean定义到容器中,这里提到的BootstrapApplicationListener是因为cloud的bootstrapcontext就是在这里构建的。

    另外还要提到一处就是AbstractApplicationContext.refresh()的时候有个回调方法onRefresh(),文档注释里说到Initialize other special beans in specific context subclasses.含义是在具体的子类容器中初始化特殊具体的beans,在web环境中会创建webServer,如ReactiveWebServerApplicationContext会创建NettyWebServer,这里也提供了自定义的扩展,因为是从容器中取ReactiveWebServerFactory,然后利用工厂获取相应WebServer,从这里去看类对应的包,可以看到embedded包下提供了多种嵌入式容器。

总结

    总的来说SpringApplication运行大致分2步,环境构建、容器构建,在容器创建准备时通过ApplicationContextInitializer做一些额外的初始化工作,然后在整个启动过程让SpringApplicationRunListener来监听,在不同阶段通过spring的事件机制让ApplicationListener做额外处理,提供了2种扩展方式ApplicationContextInitializer、ApplicationListener,而此二者都是在spring框架里就定好了的扩展接口,boot所做不过是让事件广播出去。

思考

    以后再面对一些基于boot构建的框架时,是不是要对spring.factories中的初始化器和监听器做些额外的关注,这个文件里也大都是自动配置类、初始化器、监听器,可能有些基于自动配置类想不清楚的问题,可以到监听器中找找答案,可能省会节约些时间,再结合前面的文章来看,spring的spi机制给开发者提供了类的扩展方式,而配置类又可以加载许多想加载的组件,在环境里可以配置属性资源,给组件字段赋值,还可以通过ApplicationContextInitializer、ApplicationListener,对容器和环境做修改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

&一步

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值