Springboot源码分析
1、SpringApplication初始化
从run()方法进入,可以看到Springboot起首创建了SpringApplication,然后调用SpringApplication的run()方法。- public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
- return (new SpringApplication(primarySources)).run(args);
- }
复制代码 创建SpringApplication,起首要执行它的构造方法。- //SpringApplication.class
- public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
- this.sources = new LinkedHashSet();
- this.bannerMode = Mode.CONSOLE;
- this.logStartupInfo = true;
- this.addCommandLineProperties = true;
- this.addConversionService = true;
- this.headless = true;
- this.registerShutdownHook = true;
- this.additionalProfiles = new HashSet();
- this.isCustomEnvironment = false;
- this.lazyInitialization = false;
- this.resourceLoader = resourceLoader;
- Assert.notNull(primarySources, "PrimarySources must not be null");
- this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
- //webApplication类型一般是servlet
- this.webApplicationType = WebApplicationType.deduceFromClasspath();
- //设置初始化器,加载spring.factories文件中的ApplicationContextInitializer
- this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
- //设置监听器,加载spring.factories文件中的ApplicationListener
- this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
- //启动类的类型,我们的是com.example.demo.DemoApplication
- this.mainApplicationClass = this.deduceMainApplicationClass();
- }
复制代码 1.1 & 1.2 设置初始化器和监听器
上面的setInitializers和setListeners去初始化spring.factories文件中对应的类,然后放入ArrayList中。比如这些:- org.springframework.context.ApplicationContextInitializer=\
- org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
- org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
- # Application Listeners
- org.springframework.context.ApplicationListener=\
- org.springframework.boot.autoconfigure.BackgroundPreinitializer
复制代码 1.2.1 getSpringFactoriesInstances
在getSpringFactoriesInstances()方法中,springboot起首去所有spring.factories找到对应的类,然后通过反射创建类的实例。- //SpringApplication.class
- private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
- return this.getSpringFactoriesInstances(type, new Class[0]);
- }
- private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
- ClassLoader classLoader = this.getClassLoader();
- //获取spring.factories中对应类的类名,以ApplicationListenser为例,springboot会去文件中找到所有ApplicationListener对应的类,放入Set中。
- Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
- //反射创建类的实例对象,放到List中返回
- List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
- AnnotationAwareOrderComparator.sort(instances);
- return instances;
- }
- private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
- List<T> instances = new ArrayList(names.size());
- Iterator var7 = names.iterator();
- while(var7.hasNext()) {
- String name = (String)var7.next();
- try {
- //获取类信息
- Class<?> instanceClass = ClassUtils.forName(name, classLoader);
- Assert.isAssignable(type, instanceClass);
- //获取构造器
- Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
- //创建实例
- T instance = BeanUtils.instantiateClass(constructor, args);
- instances.add(instance);
- } catch (Throwable var12) {
- throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);
- }
- }
- return instances;
- }
复制代码 1.2.2 loadFactoryNames()
进入SpringFactoriesLoader.loadFactoryNames(type, classLoader)看一下,这里还是以ApplicationListener为例,这时的type是org.springframework.context.ApplicationListener,classLoader是AppClassLoader。- //SpringFactoriesLoader.class
- public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
- String factoryTypeName = factoryType.getName();
- return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
- }
- private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
- MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
- if (result != null) {
- return result;
- } else {
- try {
- Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
- MultiValueMap<String, String> result = new LinkedMultiValueMap();
- while(urls.hasMoreElements()) {
- URL url = (URL)urls.nextElement();
- UrlResource resource = new UrlResource(url);
- Properties properties = PropertiesLoaderUtils.loadProperties(resource);
- Iterator var6 = properties.entrySet().iterator();
- while(var6.hasNext()) {
- Map.Entry<?, ?> entry = (Map.Entry)var6.next();
- String factoryTypeName = ((String)entry.getKey()).trim();
- String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
- int var10 = var9.length;
- for(int var11 = 0; var11 < var10; ++var11) {
- String factoryImplementationName = var9[var11];
- result.add(factoryTypeName, factoryImplementationName.trim());
- }
- }
- }
- cache.put(classLoader, result);
- return result;
- } catch (IOException var13) {
- throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
- }
- }
- }
复制代码 loadSpringFactories()方法会遍历所有的spring.factories文件,把所有的类的名字生存到map中,然后调用getOrDefault()方法就可以获取到所有的ApplicationListner对应的类名了。

SpringApplication初始化完了,接下来该执行run()方法了
2、SpringApplication执行run()方法
- //SpringApplication.class
- public ConfigurableApplicationContext run(String... args) {
- StopWatch stopWatch = new StopWatch();
- stopWatch.start();
- //这里是Spring的上下文
- ConfigurableApplicationContext context = null;
- Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
- this.configureHeadlessProperty();
- //获取运行监听器,获取到的是EventPublishingRunListener,这是springboot的启动监听器
- SpringApplicationRunListeners listeners = this.getRunListeners(args);
- //启动监听器
- listeners.starting();
- Collection exceptionReporters;
- try {
- ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
- //2.1 准备环境
- ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
- this.configureIgnoreBeanInfo(environment);
- //Banner打印类
- Banner printedBanner = this.printBanner(environment);
- //2.2 创建应用上下文
- context = this.createApplicationContext();
- exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
- //2.3 准备上下文
- this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
- //2.4 刷新上下文
- this.refreshContext(context);
- //刷新上下文后置处理
- this.afterRefresh(context, applicationArguments);
- stopWatch.stop();
- if (this.logStartupInfo) {
- (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
- }
- //发布上下文启动完成事件
- listeners.started(context);
- this.callRunners(context, applicationArguments);
- } catch (Throwable var10) {
- this.handleRunFailure(context, var10, exceptionReporters, listeners);
- throw new IllegalStateException(var10);
- }
- try {
- listeners.running(context);
- return context;
- } catch (Throwable var9) {
- this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
- throw new IllegalStateException(var9);
- }
- }
复制代码 2.1 prepareEnvironment()准备环境
- //SpringApplication.class
- private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
- //根据前面推断的webApplicationType创建对应的环境,servlet对应的是StandardServletEnvironment()
- ConfigurableEnvironment environment = this.getOrCreateEnvironment();
- //根据参数配置环境,包括命令行参数,启动类传入的参数
- this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
- ConfigurationPropertySources.attach((Environment)environment);
- //执行完这个,配置文件中的配置进行就被加载到环境中了
- listeners.environmentPrepared((ConfigurableEnvironment)environment);
- //环境和SpringApplication绑定起来
- this.bindToSpringApplication((ConfigurableEnvironment)environment);
- if (!this.isCustomEnvironment) {
- environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
- }
- ConfigurationPropertySources.attach((Environment)environment);
- return (ConfigurableEnvironment)environment;
- }
复制代码 2.1.1 根据参数配置环境configureEnvironment()
- //SpringApplication.class
- protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
- if (this.addConversionService) {
- ConversionService conversionService = ApplicationConversionService.getSharedInstance();
- environment.setConversionService((ConfigurableConversionService)conversionService);
- }
- //配置命令行中的参数
- this.configurePropertySources(environment, args);
- //激活相应的配置文件,例如application.propertires或者application-dev.properties等
- this.configureProfiles(environment, args);
- }
复制代码 如果我启动的dev环境,执行完上面的代码后环境中是这样的
2.1.2 listeners.environmentPrepared()
执行完这句代码后,配置文件中的信息就被加载到环境中了,如下图。具体怎么做到的还没看懂
2.2 创建应用上下文createApplicationContext()
- //SpringApplication.class
- protected ConfigurableApplicationContext createApplicationContext() {
- Class<?> contextClass = this.applicationContextClass;
- if (contextClass == null) {
- try {
- switch (this.webApplicationType) {
- case SERVLET:
- contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
- break;
- case REACTIVE:
- contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
- break;
- default:
- contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
- }
- } catch (ClassNotFoundException var3) {
- throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
- }
- }
- return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
- }
复制代码 这个函数也是根据前面的webApplicationType创建应用上下文,servlet对应的是AnnotationConfigServletWebServerApplicationContext,当初始化完这个类时,其实也会创建一个IOC容器beanFactory,如下图所示。这是因为AnnotationConfigServletWebServerApplicationContext会继承GenericApplicationContext,当执行完这个类的构造函数,会创建一个DefaultListableBeanFactory()的beanFactory,这个就是IOC容器。
2.3 准备上下文prepareContext()
- //SpringApplication.class
- private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
- //设置上下文环境
- context.setEnvironment(environment);
- this.postProcessApplicationContext(context);
- //初始化所有的ApplicationContextInitializer
- this.applyInitializers(context);
- //发布上下文准备完成事件
- listeners.contextPrepared(context);
- if (this.logStartupInfo) {
- this.logStartupInfo(context.getParent() == null);
- this.logStartupProfileInfo(context);
- }
- //获取IOC容器beanFactory
- ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
- //将springApplicationArguments和springBootBanner注册成单例
- beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
- if (printedBanner != null) {
- beanFactory.registerSingleton("springBootBanner", printedBanner);
- }
- if (beanFactory instanceof DefaultListableBeanFactory) {
- ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
- }
- if (this.lazyInitialization) {
- context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
- }
- //2.3.1 获取资源,其中primarySources就是我们定义的启动类DemoApplication
- Set<Object> sources = this.getAllSources();
- Assert.notEmpty(sources, "Sources must not be empty");
- //2.3.2 加载启动类,注入IOC容器
- this.load(context, sources.toArray(new Object[0]));
- //发布完成加载事件
- listeners.contextLoaded(context);
- }
复制代码 2.3.1 & 2.3.2 获取启动类,注入IOC容器
当执行完getAllSources(),可以获取到启动类DemoApplication
重点看load()方法,进入load()。- //SpringApplication.class
- protected void load(ApplicationContext context, Object[] sources) {
- if (logger.isDebugEnabled()) {
- logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
- }
- //创建BeanDefinitionLoader
- BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
- if (this.beanNameGenerator != null) {
- loader.setBeanNameGenerator(this.beanNameGenerator);
- }
- if (this.resourceLoader != null) {
- loader.setResourceLoader(this.resourceLoader);
- }
- if (this.environment != null) {
- loader.setEnvironment(this.environment);
- }
- //加载启动类
- loader.load();
- }
复制代码 其中getBeanDefinitionRegistry(context)方法会将之前的上下文context强转成BeanDefinitionRegistry,他们之间的继承关系很复杂,可以转换成不同的类完成不同的方法。createBeanDefinitionLoader()方法创建了一个BeanDefinitionLoader(),点进去看看。- //BeanDefinitionLoader.class
- BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
- Assert.notNull(registry, "Registry must not be null");
- Assert.notEmpty(sources, "Sources must not be empty");
- this.sources = sources;
- //注解形式的Bean阅读器
- this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
- //xml形式的Bean阅读器
- this.xmlReader = new XmlBeanDefinitionReader(registry);
- if (this.isGroovyPresent()) {
- this.groovyReader = new GroovyBeanDefinitionReader(registry);
- }
- //类路径扫描器
- this.scanner = new ClassPathBeanDefinitionScanner(registry);
- this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
- }
复制代码 一直跟进load()。- //BeanDefinitionLoader.class
- private int load(Class<?> source) {
- if (this.isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
- GroovyBeanDefinitionSource loader = (GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
- this.load(loader);
- }
- //启动类会走进这里
- if (this.isEligible(source)) {
- //将启动类注册进beanDefinitionMap
- this.annotatedReader.register(new Class[]{source});
- return 1;
- } else {
- return 0;
- }
- }
复制代码 进入register()方法。
[code]//AnnotatedBeanDefinitionReader.classpublic void register(Class... componentClasses) { Class[] var2 = componentClasses; int var3 = componentClasses.length; for(int var4 = 0; var4 < var3; ++var4) { Class componentClass = var2[var4]; this.registerBean(componentClass); }}public void registerBean(Class beanClass) { this.doRegisterBean(beanClass, (String)null, (Class[])null, (Supplier)null, (BeanDefinitionCustomizer[])null);}private void doRegisterBean(Class beanClass, @Nullable String name, @Nullable Class |