Springboot 启动流程(一):Application对象的创建

Springboot 启动流程(一):
springboot启动时电泳main方法的SpringApplication.run()方法传入class和main方法的args对象
在底层调用了run方法:
public static ConfigurableApplicationContext run(Class<?> primarySource,
            String... args) {
    return run(new Class<?>[] { primarySource }, args);
}
其中run方法的具体实现:
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
            String[] args) {
    return new SpringApplication(primarySources).run(args);
}
new了一个SpringApplication的对象,传入了class对象再调用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 = WebApplicationType.deduceFromClasspath();// 给webApplicationType赋值,之后createContent时用到
    setInitializers((Collection) getSpringFactoriesInstances(
            ApplicationContextInitializer.class));// 把加载出的ApplicationContextInitializer放入initializers中(其中重要的方法:getSpringFactoriesInstances)
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 吧加载的Listener放入listeners
    this.mainApplicationClass = deduceMainApplicationClass();// 给mainApplication赋值(获取调用Application.run方法的类)
}
上面的代码主要做了初始化变量的工作,其中最重要的方法就是getSpringFactoriesInstances方法:
他调用了pringFactoriesLoader.loadFactoryNames方法,这个方法的实际作用可以看成是预加载,当我们调用这个方法时
会获取所有.factory的配置文件,然后根据传来的names创建对象,具体代码如下:
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 = getClassLoader();// 获取的是defaultClassLoader(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;
}

SpringFactoriesLoader:
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    MultiValueMap<String, String> result = cache.get(classLoader);
    if (result != null) {
        return result;
    }

    try {
        Enumeration<URL> urls = (classLoader != null ?
                classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
        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;
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load factories from location [" +
                FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}
FACTORIES_RESOURCE_LOCATION 这个变量是类中写死的:
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
获取对应的classloader的META-INF/spring.factories的配置文件的内容,我们可以看下spring.factories中写的是什么:
org.springframework.beans.BeanInfoFactory=org.springframework.beans.ExtendedBeanInfoFactory
上面是其中一个spring.factories中的内容,其实就是一个Factory的类名,loadSpringFactories方法获取了所有spring.factories中的数据
然后放在list中放回给前面的方法,再把list放入缓存中.获取完类名后在调用Application中的createSpringFactoriesInstances方法,
这个方法主要是通过反射获取所有name的对象,代码如下:
@SuppressWarnings("unchecked")
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
        Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
        Set<String> names) {
    List<T> instances = new ArrayList<>(names.size());
    for (String name : names) {
        try {
            Class<?> instanceClass = ClassUtils.forName(name, classLoader);
            Assert.isAssignable(type, instanceClass);// 判断instanceClass是否是type的子类
            Constructor<?> constructor = instanceClass
                    .getDeclaredConstructor(parameterTypes);// 获取对应构造方法
            T instance = (T) BeanUtils.instantiateClass(constructor, args);// 获取对象
            instances.add(instance);
        }
        catch (Throwable ex) {
            throw new IllegalArgumentException(
                    "Cannot instantiate " + type + " : " + name, ex);
        }
    }
    return instances;
}
一系列类流程下来,就给所有的initializers和listeners赋值了.
创建完SpringApplication对象后就要调用run方法了.我们先总结下这一块儿代码的流程:
首先调用run方法是会创建SpringApplication的对象,并获取所有的ApplicationContextInitializer对象和ApplicationListener对象,并赋值给
成员变量.最后从stackTrace中找到调用main方法的类并赋值给mainApplicationClass,随后就开始真正的初始化spring的流程了
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值