SpringBoot 之 SpringApplication

341 阅读3分钟

springboot版本 2.1.1

SpringApplication 实例化做了什么?

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	    // 加载器,一般是null
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		//一般是springboot启动类
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		//判断web环境是servlet还是reactive还是none 
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		//获取所有springboot项目下面下的META-INF/spring.factories的ApplicationContextInitializer
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection)
		//获取所有springboot项目下面下的META-INF/spring.factories 的ApplicationListener
		getSpringFactoriesInstances(ApplicationListener.class));
		//这个做法有点意思,springboot创建一个异常,通过异常的堆栈拿到执行main方法的类
		this.mainApplicationClass = deduceMainApplicationClass();
	}

上面大概讲了springboot实例化做的事情,接下来细化下

怎么判断当前web环境是servlet还是reactive还是none

现在的web项目一般都是基于servlet,这是spring5的新特性之一:reactive是不依赖servlet,大概看了下reactive相关的包结构基本于springmvc差不多,但是没细看怎么做到不依赖servlet

WebApplicationType.deduceFromClasspath
static WebApplicationType deduceFromClasspath() {
        //如果项目中有orgspringframework.web.reactive.DispatcherHandler的类
        //而且没有org.glassfish.jersey.servlet.ServletContainer 和
        //org.springframework.web.servlet.DispatcherServlet 那就当作当前web环境是reactive环境
		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		// "javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext只要有一个类不存在就当作none,不是web项目
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		//web环境是servlet
		return WebApplicationType.SERVLET;
	}

总结就是判断reactive和servlet相关的类有没有在项目中依赖

获取所有springboot项目下面下的META-INF/spring.factories的ApplicationContextInitializer
        //springboot初始化的代码
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
			//获取类加载器
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		//这个重要,去加载spring.factories
		Set<String> names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
				//通过spring.factories获取到的全类名实例化对象
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
				//排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
怎么加载spring.factories

	private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
         //MultiValueMap 就是一个map,先从缓存中获取    
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}
		try {
		//加载META-INF/spring.factories 中的数据,可能存在多个Spring.factories
		//在扩展spring的时候也可以自己在META-INF 下面添加spring.factories
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
					//这个是一个spring自定义的map但是没有具体的时候,因为其实里面是用一个Map<string,List>(这个list是LinkedList)来接
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryClassName = ((String) entry.getKey()).trim();
					//用逗号分隔成多个(好像还有换行符)
					for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryClassName, factoryName.trim());
					}
				}
			}
			//放到缓存中
			cache.put(classLoader, result);
			return result;
		}
	}

所以就是通过加载spring.factories得到key接口,value是实现类,同时放到缓存中,可以用来做spring扩展

    //实例化  ApplicationContextInitializer 之后放到这个list
	private List<ApplicationContextInitializer<?>> initializers;
    //实例化  ApplicationListener 之后放到这个list
	private List<ApplicationListener<?>> listeners;

上面就是springboot大概的实例化

run方法做了什么?

public ConfigurableApplicationContext run(String... args) {
        .....
        //获取监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
		//执行监听器
		listeners.starting();
        .......
}

getRunListeners(args) 这个方法做了什么

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		//从spring.factories 取出 SpringApplicationRunListener
		目前只有 EventPublishingRunListener (其实并不是真实的监听器,往下看)
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}
listeners.starting() 其实是调用了EventPublishingRunListener#starting
	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		//EventPublishingRunListener实例化的时候,会创建一个广播器,然并且往广播//器放真实的监听,这些监听都是SpringApplicaition实例化的时候从spring.fac//tories拿出来的,后面需要通知监听器的时候就是使用广播器通知
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}
	
		public void starting() {
		//直接调用广播器
		this.initialMulticaster.multicastEvent(
				new ApplicationStartingEvent(this.application, this.args));
	}

接下来看下 SimpleApplicationEventMulticaster#multicastEvent

	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		//通过 getApplicationListeners 获取符合条件的监听器
		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
			//执行监听器的 onApplicationEvent 方法
				invokeListener(listener, event);
			}
		}
	}

getApplicationListeners 获取符合条件的监听器其实就是调用GenericApplicationListener#supportsEventType 来判断的,所以一般写spring监听器,就是实现 GenericApplicationListener#supportsEventType方法,来判断自己的监听对什么事件感兴趣

未完待续..........