java源码-SpringBoot概览

什么是SpringBoot?

  • 为所有Spring开发提供根本上更快且可广泛访问的入门经验。

  • 开箱即用,但随着需求开始偏离默认值,您会很快摆脱困境。

  • 提供一系列大型项目通用的非功能性功能(例如嵌入式服务器,安全性,指标,运行状况检查和外部化配置)。

  • 完全没有代码生成,也不需要XML配置。

  • 优点 :

    (1) 快速构建项目;

    (2) 对主流开发框架的无配置集成;

    (3) 项目可独立运行,无须外部依赖 Servlet容器;

    (4) 提供运行时的应用监控;

    (5) 极大地提高了开发,部署效率;

    (6) 与云计算的天然集成.

    缺点 :

    (1) 书籍文档少且不够深入;

    (2) 如果你不认同Spring框架,这也许是它的缺点,但建议你一定要使用Spring框架.

面试题相关:

https://baijiahao.baidu.com/s?id=1638998808858231030&wfr=spider&for=pc

https://blog.csdn.net/zhoushimiao1990/article/details/99713372

启动全过程

https://www.cnblogs.com/yust/p/10787753.html

https://segmentfault.com/a/1190000020359093?utm_source=tag-newest

https://blog.csdn.net/woshilijiuyi/article/details/82219585 参考

在这里插入图片描述

##构造方法

 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;//1、初始化资源加载器
        Assert.notNull(primarySources, "PrimarySources must not be null");//2、断言资源加载类不能为 null
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//3、初始化加载资源类集合并去重
        this.webApplicationType = deduceWebApplicationType();//4、 推断应用类型是Standard还是Web
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));//5、设置应用上下文初始化器
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//6、设置监听器 
        this.mainApplicationClass = deduceMainApplicationClass();//7、推断应用入口类
    }

主要看getSpringFactoriesInstances:

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));    // classLoader.getResources(FACTORIES_RESOURCE_LOCATION)获取类路径下全部的META-INF/spring.factories的URL
        result = new LinkedMultiValueMap<>();
        while (urls.hasMoreElements()) {                                        // 遍历全部的URL,逐个读取META-INF/spring.factories中的属性
            URL url = urls.nextElement();
            UrlResource resource = new UrlResource(url);
            Properties properties = PropertiesLoaderUtils.loadProperties(resource);
            for (Map.Entry<?, ?> entry : properties.entrySet()) {
                List<String> factoryClassNames = Arrays.asList(
                        StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
                result.addAll((String) entry.getKey(), factoryClassNames);        // 属性全部放入MultiValueMap<String, String> result中,注意result的类型
            }
        }
        cache.put(classLoader, result);                                            // 结果放入缓存,方便下次查找
        return result;
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load factories from location [" +
                FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}

loadSpringFactories做了以下这些事

a、 查找类路径下全部的META-INF/spring.factories的URL

b、 根据url加载全部的spring.factories中的属性

c、 将所有spring.factories中的值缓存到SpringFactoriesLoader的cache中:

private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();方便下次调用。

加载完所有的工厂名称之后,然后从中获取指定工厂类型的工厂名称列表,也就是getOrDefault(factoryClassName, Collections.emptyList())做的事。

2、createSpringFactoriesInstances,创建指定类型的工厂实例

根据上面获取的指定类型的工厂名称列表来实例化工厂bean,我们可以简单的认为通过反射来实例化,但是具体的实现也没那么简单,感兴趣的小伙伴可以自己去跟。

3、对工厂实例进行排序,然后返回排序后的实例列表

排序规则:@Order从小到大排序,没有order则按没排序之前的顺序。

public ConfigurableApplicationContext run(String... args) {
    // 秒表,用于记录启动时间;记录每个任务的时间,最后会输出每个任务的总费时
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    // spring应用上下文,也就是我们所说的spring根容器
    ConfigurableApplicationContext context = null;
    // 自定义SpringApplication启动错误的回调接口
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    // 设置jdk系统属性java.awt.headless,默认情况为true即开启
    configureHeadlessProperty();
    // 获取启动时监听器(EventPublishingRunListener实例)
    SpringApplicationRunListeners listeners = getRunListeners(args)
    // 触发ApplicationStartingEvent事件,启动监听器会被调用,一共5个监听器被调用,但只有两个监听器在此时做了事
    listeners.starting(); 
    try {
        // 参数封装,也就是在命令行下启动应用带的参数,如--server.port=9000
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);
        // 准备环境:1、加载外部化配置的资源到environment;2、触发ApplicationEnvironmentPreparedEvent事件
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                applicationArguments);
        // 配置spring.beaninfo.ignore,并添加到名叫systemProperties的PropertySource中;默认为true即开启
        configureIgnoreBeanInfo(environment);
        // 打印banner图
        Banner printedBanner = printBanner(environment);
        // 创建应用上下文,并实例化了其三个属性:reader、scanner和beanFactory
        context = createApplicationContext();
        // 获取异常报道器,即加载spring.factories中的SpringBootExceptionReporter实现类
        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
        // 准备上下文,本文重点
        prepareContext(context, environment, listeners, applicationArguments,
                printedBanner);
        refreshContext(context);
        afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                    .logStarted(getApplicationLog(), stopWatch);
        }
        listeners.started(context);
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }

    try {
        listeners.running(context);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

下面我们逐一分析:
<1> : StopWatch stopWatch = new StopWatch();
stopWatch.start();

这段代码功能很简单,创建一个StopWatch对象,开始记录run()启动过程时长;

getRunListeners

<2>: 先来看这个方法:SpringApplicationRunListeners listeners = getRunListeners(args);

private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}

在这段代码里,我们又看见了熟悉的 getSpringFactoriesInstances(),原理还是一样,就是 getSpringFactoriesInstances()方法会从类路径下的 META-INF/spring.factories文件中找 对应SpringApplicationRunListener的全路径数组,并通过createSpringFactoriesInstances()方法实例化成对象返回;getSpringFactoriesInstances在第一次被调用时会将类路径下所有的META-INF/spring.factories的文件中的属性进行加载并缓存到SpringFactoriesLoader的缓存cache中,下次被调用的时候就直接从SpringFactoriesLoader的cache中取数据了。这次就是从SpringFactoriesLoader的cache中取SpringApplicationRunListener类型的类(全限定名),然后实例化后返回。

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
   ClassLoader classLoader = getClassLoader();
   // 使用名称并确保惟一以防止重复
   Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
   List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
   AnnotationAwareOrderComparator.sort(instances);
   return instances;

org.springframework.core.io.support.SpringFactoriesLoader.java

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

-> 实例化

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);
				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;
	}

再看 listeners.starting() 方法:

public void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}

所以这个方法就是回调之前获得的所有SpringApplicationRunListener对象的starting()方法,启动监听。我们可以继续再深入看一下这个监听对象的其他方法:

SpringApplicationRunListener 接口中共有上面几个方法,这几个方法将会贯穿run()方法的运行。

简单点来说,就是检测正在使用的日志系统、另起一个后台线程执行耗时的初始化


<3>:这个方法的作用也很简单,即使封装命令行参数。

prepareEnvironment

<4>: ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments)

https://www.cnblogs.com/youzhibing/p/9622441.html

加载外部化配置资源到environment,包括命令行参数、servletConfigInitParams、servletContextInitParams、systemProperties、sytemEnvironment、random、application.yml(.yaml/.xml/.properties)等;

初始化日志系统。

其实这是环境准备阶段,我们可以看一下它的实现过程:

// 准备环境
private ConfigurableEnvironment prepareEnvironment(
        SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    // Create and configure the environment 创建和配置环境

    // 获取或创建环境
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    // 配置环境:配置PropertySources和activeProfiles
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    // listeners环境准备(就是广播ApplicationEnvironmentPreparedEvent事件)。还记得这个listeners怎么来的吗?
    listeners.environmentPrepared(environment);
    // 将环境绑定到SpringApplication
    bindToSpringApplication(environment);
    // 如果是非web环境,将环境转换成StandardEnvironment
    if (this.webApplicationType == WebApplicationType.NONE) {
        environment = new EnvironmentConverter(getClassLoader())
                .convertToStandardEnvironmentIfNecessary(environment);
    }
    // 配置PropertySources对它自己的递归依赖
    ConfigurationPropertySources.attach(environment);
    return environment;
}

这个方法表示创建环境,并且environment 的属性都会加载进来,包括 application.properties 和外部的属性配置,具体实现有兴趣的同学可以研究一下。其中listeners.environmentPrepared(environment)方法表示环境准备完成

展开:

//返回对应的环境 这个Type 是在创建SpringApplication的时候判断出来的

// 获取或创建Environment,很显然我们这里是创建StandardServletEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() {
    // 存在则直接返回
    if (this.environment != null) {
        return this.environment;
    }
    // 根据webApplicationType创建对应的Environment
    // webApplicationType的值还记得在哪获取到的吗?不知道的请去看我的springboot源码一
    if (this.webApplicationType == WebApplicationType.SERVLET) {
        return new StandardServletEnvironment();    // 标准的Servlet环境,也就是我们说的web环境
    }
    return new StandardEnvironment();                // 标准环境,非web环境

img

//根据传进来的参数,就是  SpringApplication.run(MyAppliaction.class, args);的args封装到
//环境里面去
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
   if (this.addConversionService) {
      ConversionService conversionService = ApplicationConversionService.getSharedInstance();
      environment.setConversionService((ConfigurableConversionService) conversionService);
   }
   configurePropertySources(environment, args);
   configureProfiles(environment, args);
}

从源码看,将配置任务按顺序委托给configurePropertySources和configureProfiles,那么我们来看看这两个方法

configurePropertySources

protected void configurePropertySources(ConfigurableEnvironment environment,
        String[] args) {
    MutablePropertySources sources = environment.getPropertySources();
    // 此时defaultProperties还是null,可能后续过程会初始化,具体详情请期待后续的博文
    if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
        // 存在的话将其放到最后位置
        sources.addLast(
                new MapPropertySource("defaultProperties", this.defaultProperties));
    }
    // 存在命令行参数,则解析它并封装进SimpleCommandLinePropertySource对象,同时将此对象放到sources的第一位置(优先级最高)
    if (this.addCommandLineProperties && args.length > 0) {
        String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
        if (sources.contains(name)) {
            PropertySource<?> source = sources.get(name);
            CompositePropertySource composite = new CompositePropertySource(name);
            composite.addPropertySource(new SimpleCommandLinePropertySource(
                    "springApplicationCommandLineArgs", args));
            composite.addPropertySource(source);
            sources.replace(name, composite);
        }
        else {
            // 将其放到第一位置
            sources.addFirst(new SimpleCommandLinePropertySource(args));
        }
    }
}

注释说明是增加、移除或者重排序应用环境中的PropertySource。就目前而言,如果有命令行参数则新增封装命令行参数的PropertySource,并将它放到sources的第一位置。

configureProfiles

protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
    // 保证environment的activeProfiles属性被初始化了。从PropertySources中查找spring.profiles.active属性
    // 存在则将其值添加activeProfiles集合中。我们可以通过命令行参数指定该参数,但我们没有指定
    environment.getActiveProfiles(); // ensure they are initialized
    // But these ones should go first (last wins in a property key clash)
    // 如果存在其他的Profiles,则将这些Profiles放到第一的位置。此时没有,后面有没有后面再说
    Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
    profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
    environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}

配置应用环境中的哪些配置文件处于激活状态(或默认激活)。可以通过spring.profiles.active属性在配置文件处理期间激活其他配置文件。说的简单点就是设置哪些Profiles是激活的。

这3个方法都是protected,也就说鼓励被重写。重写configureEnvironment可以完全控制自定义环境,或者重写configurePropertySources或configureProfiles,进行更细粒度控制。

->再来看看 ApplicationConversionService (转换)是个啥:

public static ConversionService getSharedInstance() {
   ApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance;
   if (sharedInstance == null) {
      synchronized (ApplicationConversionService.class) {
         sharedInstance = ApplicationConversionService.sharedInstance;
         if (sharedInstance == null) {
            sharedInstance = new ApplicationConversionService();
            ApplicationConversionService.sharedInstance = sharedInstance;
         }
      }
   }
   return sharedInstance;
}

-> listeners.environmentPrepared(environment);

void environmentPrepared(ConfigurableEnvironment environment) {
   for (SpringApplicationRunListener listener : this.listeners) {
      listener.environmentPrepared(environment);
   }
}

org/springframework/context/event/SimpleApplicationEventMulticaster 执行监听器

这个代码有没有很熟悉?,不清楚的点这里,查看其中的listeners.starting()。上次广播的是ApplicationStartingEvent事件,而这次广播的是ApplicationEnvironmentPreparedEvent事件。这里就不和大家一起跟源代码了,大家自行去跟哦。我在这总结下:

过滤出的与ApplicationEnvironmentPreparedEvent相匹配的监听器列表如下,他们的onApplicationEvent会被调用,大致做了以下事情:

ConfigFileApplicationListener
        1、加载EnvironmentPostProcessor列表,仍然是从META-INF/spring.factories中加载(在SpringApplication实例化的时候已经加载了,这次是从缓存中读取),然后实例化;
        2、将自己也加入EnvironmentPostProcessor列表;ConfigFileApplicationListener实现了EnvironmentPostProcessor接口,可以看它的类图。
        3、对EnvironmentPostProcessor列表进行排序;排序之后,EnvironmentPostProcessor列表图如下:
        4、遍历EnvironmentPostProcessor列表,调用每个EnvironmentPostProcessor的postProcessEnvironment方法

SystemEnvironmentPropertySourceEnvironmentPostProcessor

将propertySourceList中名为systemEnvironment的SystemEnvironmentPropertySource对象替换成OriginAwareSystemEnvironmentPropertySource对象,source未变,还是SystemEnvironmentPropertySource对象的source;OriginAwareSystemEnvironmentPropertySource是SystemEnvironmentPropertySourceEnvironmentPostProcessor的静态内部类,且继承自SystemEnvironmentPropertySource。具体这么替换出于什么目的,便于原点查找?暂时还未知。

SpringApplicationJsonEnvironmentPostProcessor

spring.application.json(或SPRING_APPLICATION_JSON)是设置在系统属性或系统环境中;

如果spring.application.json(或SPRING_APPLICATION_JSON)有配置,那么给environment的propertySourceList增加JsonPropertySource,并将JsonPropertySource放到名叫systemProperties的PropertySource前;目前没有配置,那么此环境后处理器相当于什么也没做。

CloudFoundryVcapEnvironmentPostProcessor

云平台是否激活,激活了则给environment的propertySourceList增加名为vcap的PropertiesPropertySource对象,并将此对象放到命令行参数PropertySource(名叫commandLineArgs)后。很显然,我们没有激活云平台,那么此环境后处理器相当于什么也没做。

ConfigFileApplicationListener

添加名叫random的RandomValuePropertySource到名叫systemEnvironment的PropertySource后;

并初始化Profiles;初始化PropertiesPropertySourceLoader和YamlPropertySourceLoader这两个加载器从file:./config/,file:./,classpath:/config/,classpath:/路径下加载配置文件,PropertiesPropertySourceLoader加载配置文件application.xml和application.properties,YamlPropertySourceLoader加载配置文件application.yml和application.yaml。目前我们之后classpath:/路径下有个application.yml配置文件,将其属性配置封装进了一个名叫applicationConfig:[classpath:/application.yml]的OriginTrackedMapPropertySource中,并将此对象放到了propertySourceList的最后。

AnsiOutputApplicationListener

设置ansi输出,将AnsiOutput的属性enabled设置成ALWAYS,即允许ANSI-colored输出

LoggingApplicationListener

初始化日志系统
      ClasspathLoggingApplicationListener:没开启调试,所以什么也没做
      BackgroundPreinitializer:此时什么也没做
      DelegatingApplicationListener:此时什么也没做,因为环境中没有配置context.listener.classes属性
      FileEncodingApplicationListener:此时什么也没做,环境中没有spring.mandatory-file-encoding属性

EnableEncryptablePropertiesBeanFactoryPostProcessor:此时什么也没有做

environmentPrepared方法会触发所有监听了ApplicationEnvironmentPreparedEvent事件的监听器,这些监听器目前主要新增了两个PropertySource:RandomValuePropertySource和OriginTrackedMapPropertySource,这个OriginTrackedMapPropertySource一般就是我们应用的配置文件application.yml(application.properties)。

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   Executor executor = getTaskExecutor();
   for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
          
         invokeListener(listener, event);
      }
   }
}

invokeListener

调用getApplicationListeners过滤出的五个实例的onApplicationEvent方法,5个onApplicationEvent都做了啥,大体如下

LoggingApplicationListener:检测正在使用的日志系统,默认是logback,支持3种,优先级从高到低:logback > log4j > javalog。此时日志系统还没有初始化

BackgroundPreinitializer:另起一个后台线程触发那些耗时的初始化,包括验证器、消息转换器等等,具体是哪些初始化见下代码,有兴趣的朋友可去跟下

DelegatingApplicationListener:此时什么也没做

LiquibaseServiceLocatorApplicationListener:此时什么也没做

EnableEncryptablePropertiesBeanFactoryPostProcessor:此时仅仅打印了一句日志,其他什么也没做

简单点来说,就是检测正在使用的日志系统、另起一个后台线程执行耗时的初始化

命令模式:

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
   ErrorHandler errorHandler = getErrorHandler();
   if (errorHandler != null) {
      try {
         doInvokeListener(listener, event);
      }
      catch (Throwable err) {
         errorHandler.handleError(err);
      }
   }
   else {
      doInvokeListener(listener, event);
   }
}
//把环境绑定到springApplication
protected void bindToSpringApplication(ConfigurableEnvironment environment) {
   try {
      Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
   }
   catch (Exception ex) {
      throw new IllegalStateException("Cannot bind to SpringApplication", ex);
   }
}

<5>:功能为打印Banner,也可以自定义启动logo,比如在resources路径下创建一个banner.txt文件,将你想打印的图标放入其中

createApplicationContext

创建web应用上下文,对其部分属性:reader、scanner、beanFactory进行了实例化;reader中实例化了属性conditionEvaluator;scanner中添加了两个AnnotationTypeFilter:一个针对@Component,一个针对@ManagedBean;beanFactory中注册了8个注解配置处理器。

<6>:创建ApplicationContext容器,根据类型决定是创建普通WEB容器还是REACTIVE容器还是普通Annotation的ioc 容器

protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

根据SpringApplication的webApplicationType来实例化对应的上下文;如果webApplicationType的值是SERVLET,那么实例化AnnotationConfigServletWebServerApplicationContext,如果是REACTIVE则实例化AnnotationConfigReactiveWebServerApplicationContext(响应式编程,后续再看),如果既不是SERVLET、也不是REACTIVE,那么则是默认情况(也就是我们所说的非web引用),实例化AnnotationConfigApplicationContext。还记得webApplicationType的值是怎么获取的吗,请点这里。很显然我们目前的应用类型是SERVLET,那么实例化AnnotationConfigServletWebServerApplicationContext。

那么就来接着看AnnotationConfigServletWebServerApplicationContext:

public AnnotationConfigServletWebServerApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this);        // 实例化注解bean定义读取器
    this.scanner = new ClassPathBeanDefinitionScanner(this);    // 实例化类路径bean定义扫描器
}

有没有很熟悉:就是初始化一个spring的上下文

prepareContext

https://www.cnblogs.com/youzhibing/p/9697825.html

<7>:prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
这个方法的具体实现:

private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
    7.1:
		applyInitializers(context);
    7.2:
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
    //load 方法加载bean定义到容器内
		load(context, sources.toArray(new Object[0]));
		listeners.contextLoaded(context);
	}

7.1: 从initializers集合中遍历所有的ApplicationContextInitializer,并通过initializer.initialize( )方法初始化

7,2:回调SpringApplicationRunListener对象的contextPrepared()方法,表示容器已准备

<8>:refreshContext(context)
刷新容器,初始化ioc容器,向容器中加入配置类、组件,并且可以出发自动配置功能,具体原理可以参考SpringBoot的自动配置原理和Spring注解版容器的加载

以下为SpringBoot bean定义的扫描并注册

@Override
	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		super.postProcessBeanFactory(beanFactory);
		if (this.basePackages != null && this.basePackages.length > 0) {
			this.scanner.scan(this.basePackages);
		}
		if (!this.annotatedClasses.isEmpty()) {
			this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
		}
	}
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}
public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}

			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the bean factory post-processors apply to them!
			// Separate between BeanDefinitionRegistryPostProcessors that implement
			// PriorityOrdered, Ordered, and the rest.
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
				currentRegistryProcessors.clear();
			}

			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

<9>: afterRefresh(context, applicationArguments);
执行Spring容器初始化的后置处理,默认为空

protected void afterRefresh(ConfigurableApplicationContext context,
			ApplicationArguments args) {
	}

<10>: listeners.started(context);
回调所有的SpringApplicationRunListener对象的started()方法

<11>: callRunners(context, applicationArguments)

private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}

调用ApplicationRunner或者CommandLineRunner 的运行方法,其中ApplicationRunner的优先级要比CommandLineRunner要高。
在我们日常的项目里,经常需要初始化一些资源,比如线程池或者数据库数据等,我们就可以实现这两个接口,在实现方法里写具体的处理逻辑,也可以在实现类上加上@Order(value) 注解来指定优先级(ps:该实现类要加上@Component)

<12>:listeners.running(context);
回调所有SpringApplicationRunListener对象的running()方法

<13>:return context
返回容器

springboot中SPI机制

https://blog.csdn.net/qq_28802119/article/details/83536305

自动配置

https://blog.csdn.net/u014745069/article/details/83820511

https://afoo.me/posts/2015-07-09-how-spring-boot-works.html#springboot-intro

自定义starter

1.新建Maven项目,在项目的POM文件中定义使用的依赖;
2.新建配置类,写好配置项和默认的配置值,指明配置项前缀;
3.新建自动装配类,使用@Configuration和@Bean来进行自动装配;
4.新建spring.factories文件,指定Starter的自动装配类;

AutoConfigurationImportSelector

参考

 public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
        ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    //......
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 如果AutoConfiguration没开,返回{}
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        // 将spring-autoconfigure-metadata.properties的键值对配置载入到PropertiesAutoConfigurationMetadata对象中并返回
        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                .loadMetadata(this.beanClassLoader);
        // 基于各种配置计算需要import的configuration和exclusion
        AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
                annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
             
    // 判断AudoConfiguration是否开启
    protected boolean isEnabled(AnnotationMetadata metadata) {
        if (getClass() == AutoConfigurationImportSelector.class) {
            // 如果配置文件中有"spring.boot.enableautoconfiguration",返回该字段的值;否则返回true
            return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
        }
        return true;
    }
             
    protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
            AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        }
        // 获取注解的属性值
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
        // 从META-INF/spring.factories文件中获取EnableAutoConfiguration所对应的configurations
        List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
        // 去重,List转Set再转List
        configurations = removeDuplicates(configurations);
        // 从注解的exclude/excludeName属性中获取排除项
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        // 对于不属于AutoConfiguration的exclude报错
        checkExcludedClasses(configurations, exclusions);
        // 从configurations去除exclusions
        configurations.removeAll(exclusions);
        // 由所有AutoConfigurationImportFilter类的实例再进行一次筛选,去
        configurations = filter(configurations, autoConfigurationMetadata);
        // 把AutoConfigurationImportEvent绑定在所有AutoConfigurationImportListener子类实例上
        fireAutoConfigurationImportEvents(configurations, exclusions);
        // 返回(configurations, exclusions)组
        return new AutoConfigurationEntry(configurations, exclusions);
    }
    // ......
}

factories 调用时序图

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值