SpringBoot之SpringApplication(1)

本文深入探讨SpringBoot的启动过程,从SpringApplication的构造到run方法,详细解析了如何推断Web应用类型、加载ApplicationContextInitializer以及SpringApplicationRunListener。通过SpringFactoriesLoader加载配置,创建事件监听器,并利用SimpleApplicationEventMulticaster广播事件。
摘要由CSDN通过智能技术生成

总算是怀着热切的心情打开了spring boot的源码,不知道能看到怎么样的结果,不过算是能压抑期末考紧张的心情。

启动类,都是调用SpringApplication的run()方法,传入的是加入@Configuration注解的类,跟参数。

	public static ConfigurableApplicationContext run(Class<?> primarySource,
			String... args) {
		return run(new Class<?>[] { primarySource }, args);
	}
	public static ConfigurableApplicationContext run(Class<?>[] primarySources,
			String[] args) {
		return new SpringApplication(primarySources).run(args);
	}

先初始化了SpringApplication的实例然后调用run方法。先看其构造吧

	public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
	}
	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 = deduceWebApplicationType();
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

在其双参构造方法中可以看到,先是保存传入的resourceLoader,对资源非null断言,将资源primarySources按照有序LinkedSet形式存储,调用deduceWebApplication()方法推断出webApplication的类型,然后设置initializers、listeners、用deduceMainApplicationClass()方法得出并设置mainApplicationClass。

先看deduceWebApplication()方法

	private WebApplicationType deduceWebApplicationType() {
		if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
				&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		for (String className : WEB_ENVIRONMENT_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		return WebApplicationType.SERVLET;
	}
可以看到这里通过ClassUtils类的isPresent()方法检查classpath中是否有相应的类来判断类型。
        private static final String[] WEB_ENVIRONMENT_CLASSES = 
                        { "javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" };	
        public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
			+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

	private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
			+ "web.reactive.DispatcherHandler";

	private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
			+ "web.servlet.DispatcherServlet";

	private static final String JERSEY_WEB_ENVIRONMENT_CLASS = "org.glassfish.jersey.server.ResourceConfig";
如果有dispatcherHandler,且没有DispatcherServlet、jersy的就是Reactive类型,如果没有WEB_ENVIRONMENT_CLASSES

指定的类,那么则None类型,否则Servlet类型。

在设置Initializers时首先调用getSpringFactoriesInstances()方法加载ApplicationContextInitializer,然后直接赋值给initializers。

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

可以看到这里通过spring容器来实现IoC。先得到contextClassLoader,然后调用SpringFactoriesLoader的loadFactoryNames传入factoryClass得到该Class下配置的类名的集合,这里使用set来存,保证类名不重复。然后调用createSpringFactoriesInstances()方法,得到对应的实例的集合,再排序返回。

我们先来看下loadFactoryNames()方法的逻辑。

    public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }
先得到factoryClass的名字,这里即org.springframework.context.ApplicationContextInitializer,然后调用loadSpringFactories()传入ClassLoader,得到map,然后用factoryClass的名字作为key去get。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值