SpringBoot源码分析

一给  金牌会员 | 2024-9-17 19:51:33 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 854|帖子 854|积分 2562

Springboot源码分析

1、SpringApplication初始化

从run()方法进入,可以看到Springboot起首创建了SpringApplication,然后调用SpringApplication的run()方法。
  1. public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
  2.     return (new SpringApplication(primarySources)).run(args);
  3. }
复制代码
创建SpringApplication,起首要执行它的构造方法。
  1. //SpringApplication.class
  2. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  3.     this.sources = new LinkedHashSet();
  4.     this.bannerMode = Mode.CONSOLE;
  5.     this.logStartupInfo = true;
  6.     this.addCommandLineProperties = true;
  7.     this.addConversionService = true;
  8.     this.headless = true;
  9.     this.registerShutdownHook = true;
  10.     this.additionalProfiles = new HashSet();
  11.     this.isCustomEnvironment = false;
  12.     this.lazyInitialization = false;
  13.     this.resourceLoader = resourceLoader;
  14.     Assert.notNull(primarySources, "PrimarySources must not be null");
  15.     this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
  16.     //webApplication类型一般是servlet
  17.     this.webApplicationType = WebApplicationType.deduceFromClasspath();
  18.    //设置初始化器,加载spring.factories文件中的ApplicationContextInitializer
  19.     this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
  20.     //设置监听器,加载spring.factories文件中的ApplicationListener
  21.     this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
  22.     //启动类的类型,我们的是com.example.demo.DemoApplication
  23.     this.mainApplicationClass = this.deduceMainApplicationClass();
  24. }
复制代码
1.1 & 1.2 设置初始化器和监听器

上面的setInitializers和setListeners去初始化spring.factories文件中对应的类,然后放入ArrayList中。比如这些:
  1. org.springframework.context.ApplicationContextInitializer=\
  2. org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
  3. org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
  4. # Application Listeners
  5. org.springframework.context.ApplicationListener=\
  6. org.springframework.boot.autoconfigure.BackgroundPreinitializer
复制代码
1.2.1 getSpringFactoriesInstances

在getSpringFactoriesInstances()方法中,springboot起首去所有spring.factories找到对应的类,然后通过反射创建类的实例。
  1. //SpringApplication.class
  2. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
  3.     return this.getSpringFactoriesInstances(type, new Class[0]);
  4. }
  5. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
  6.     ClassLoader classLoader = this.getClassLoader();
  7.     //获取spring.factories中对应类的类名,以ApplicationListenser为例,springboot会去文件中找到所有ApplicationListener对应的类,放入Set中。
  8.     Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  9.     //反射创建类的实例对象,放到List中返回
  10.     List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
  11.     AnnotationAwareOrderComparator.sort(instances);
  12.     return instances;
  13. }
  14. private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
  15.     List<T> instances = new ArrayList(names.size());
  16.     Iterator var7 = names.iterator();
  17.     while(var7.hasNext()) {
  18.         String name = (String)var7.next();
  19.         try {
  20.             //获取类信息
  21.             Class<?> instanceClass = ClassUtils.forName(name, classLoader);
  22.             Assert.isAssignable(type, instanceClass);
  23.             //获取构造器
  24.             Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
  25.             //创建实例
  26.             T instance = BeanUtils.instantiateClass(constructor, args);
  27.             instances.add(instance);
  28.         } catch (Throwable var12) {
  29.             throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);
  30.         }
  31.     }
  32.     return instances;
  33. }
复制代码
1.2.2 loadFactoryNames()

进入SpringFactoriesLoader.loadFactoryNames(type, classLoader)看一下,这里还是以ApplicationListener为例,这时的type是org.springframework.context.ApplicationListener,classLoader是AppClassLoader。
  1. //SpringFactoriesLoader.class
  2. public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
  3.     String factoryTypeName = factoryType.getName();
  4.     return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
  5. }
  6. private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
  7.     MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
  8.     if (result != null) {
  9.         return result;
  10.     } else {
  11.         try {
  12.             Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
  13.             MultiValueMap<String, String> result = new LinkedMultiValueMap();
  14.             while(urls.hasMoreElements()) {
  15.                 URL url = (URL)urls.nextElement();
  16.                 UrlResource resource = new UrlResource(url);
  17.                 Properties properties = PropertiesLoaderUtils.loadProperties(resource);
  18.                 Iterator var6 = properties.entrySet().iterator();
  19.                 while(var6.hasNext()) {
  20.                     Map.Entry<?, ?> entry = (Map.Entry)var6.next();
  21.                     String factoryTypeName = ((String)entry.getKey()).trim();
  22.                     String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
  23.                     int var10 = var9.length;
  24.                     for(int var11 = 0; var11 < var10; ++var11) {
  25.                         String factoryImplementationName = var9[var11];
  26.                         result.add(factoryTypeName, factoryImplementationName.trim());
  27.                     }
  28.                 }
  29.             }
  30.             cache.put(classLoader, result);
  31.             return result;
  32.         } catch (IOException var13) {
  33.             throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
  34.         }
  35.     }
  36. }
复制代码
loadSpringFactories()方法会遍历所有的spring.factories文件,把所有的类的名字生存到map中,然后调用getOrDefault()方法就可以获取到所有的ApplicationListner对应的类名了。

SpringApplication初始化完了,接下来该执行run()方法了
2、SpringApplication执行run()方法
  1. //SpringApplication.class
  2. public ConfigurableApplicationContext run(String... args) {
  3.     StopWatch stopWatch = new StopWatch();
  4.     stopWatch.start();
  5.     //这里是Spring的上下文
  6.     ConfigurableApplicationContext context = null;
  7.     Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
  8.     this.configureHeadlessProperty();
  9.     //获取运行监听器,获取到的是EventPublishingRunListener,这是springboot的启动监听器
  10.     SpringApplicationRunListeners listeners = this.getRunListeners(args);
  11.     //启动监听器
  12.     listeners.starting();
  13.     Collection exceptionReporters;
  14.     try {
  15.         ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  16.         //2.1 准备环境
  17.         ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
  18.         this.configureIgnoreBeanInfo(environment);
  19.         //Banner打印类
  20.         Banner printedBanner = this.printBanner(environment);
  21.         //2.2 创建应用上下文
  22.         context = this.createApplicationContext();
  23.         exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
  24.         //2.3 准备上下文
  25.         this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  26.         //2.4 刷新上下文
  27.         this.refreshContext(context);
  28.         //刷新上下文后置处理
  29.         this.afterRefresh(context, applicationArguments);
  30.         stopWatch.stop();
  31.         if (this.logStartupInfo) {
  32.             (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
  33.         }
  34.                 //发布上下文启动完成事件
  35.         listeners.started(context);
  36.         this.callRunners(context, applicationArguments);
  37.     } catch (Throwable var10) {
  38.         this.handleRunFailure(context, var10, exceptionReporters, listeners);
  39.         throw new IllegalStateException(var10);
  40.     }
  41.     try {
  42.         listeners.running(context);
  43.         return context;
  44.     } catch (Throwable var9) {
  45.         this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
  46.         throw new IllegalStateException(var9);
  47.     }
  48. }
复制代码
2.1 prepareEnvironment()准备环境
  1. //SpringApplication.class
  2. private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
  3.     //根据前面推断的webApplicationType创建对应的环境,servlet对应的是StandardServletEnvironment()
  4.     ConfigurableEnvironment environment = this.getOrCreateEnvironment();
  5.     //根据参数配置环境,包括命令行参数,启动类传入的参数
  6.     this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
  7.     ConfigurationPropertySources.attach((Environment)environment);
  8.     //执行完这个,配置文件中的配置进行就被加载到环境中了
  9.     listeners.environmentPrepared((ConfigurableEnvironment)environment);
  10.     //环境和SpringApplication绑定起来
  11.     this.bindToSpringApplication((ConfigurableEnvironment)environment);
  12.     if (!this.isCustomEnvironment) {
  13.         environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
  14.     }
  15.     ConfigurationPropertySources.attach((Environment)environment);
  16.     return (ConfigurableEnvironment)environment;
  17. }
复制代码
2.1.1 根据参数配置环境configureEnvironment()
  1. //SpringApplication.class
  2. protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
  3.     if (this.addConversionService) {
  4.         ConversionService conversionService = ApplicationConversionService.getSharedInstance();
  5.         environment.setConversionService((ConfigurableConversionService)conversionService);
  6.     }
  7.         //配置命令行中的参数
  8.     this.configurePropertySources(environment, args);
  9.     //激活相应的配置文件,例如application.propertires或者application-dev.properties等
  10.     this.configureProfiles(environment, args);
  11. }
复制代码
如果我启动的dev环境,执行完上面的代码后环境中是这样的

2.1.2 listeners.environmentPrepared()

执行完这句代码后,配置文件中的信息就被加载到环境中了,如下图。具体怎么做到的还没看懂

2.2 创建应用上下文createApplicationContext()
  1. //SpringApplication.class
  2. protected ConfigurableApplicationContext createApplicationContext() {
  3.     Class<?> contextClass = this.applicationContextClass;
  4.     if (contextClass == null) {
  5.         try {
  6.             switch (this.webApplicationType) {
  7.                 case SERVLET:
  8.                     contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
  9.                     break;
  10.                 case REACTIVE:
  11.                     contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
  12.                     break;
  13.                 default:
  14.                     contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
  15.             }
  16.         } catch (ClassNotFoundException var3) {
  17.             throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
  18.         }
  19.     }
  20.     return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
  21. }
复制代码
这个函数也是根据前面的webApplicationType创建应用上下文,servlet对应的是AnnotationConfigServletWebServerApplicationContext,当初始化完这个类时,其实也会创建一个IOC容器beanFactory,如下图所示。这是因为AnnotationConfigServletWebServerApplicationContext会继承GenericApplicationContext,当执行完这个类的构造函数,会创建一个DefaultListableBeanFactory()的beanFactory,这个就是IOC容器。

2.3 准备上下文prepareContext()
  1. //SpringApplication.class
  2. private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
  3.     //设置上下文环境
  4.     context.setEnvironment(environment);
  5.     this.postProcessApplicationContext(context);
  6.     //初始化所有的ApplicationContextInitializer
  7.     this.applyInitializers(context);
  8.     //发布上下文准备完成事件
  9.     listeners.contextPrepared(context);
  10.     if (this.logStartupInfo) {
  11.         this.logStartupInfo(context.getParent() == null);
  12.         this.logStartupProfileInfo(context);
  13.     }
  14.     //获取IOC容器beanFactory
  15.     ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
  16.     //将springApplicationArguments和springBootBanner注册成单例
  17.     beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
  18.     if (printedBanner != null) {
  19.         beanFactory.registerSingleton("springBootBanner", printedBanner);
  20.     }
  21.     if (beanFactory instanceof DefaultListableBeanFactory) {
  22.         ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
  23.     }
  24.     if (this.lazyInitialization) {
  25.         context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
  26.     }
  27.         //2.3.1 获取资源,其中primarySources就是我们定义的启动类DemoApplication
  28.     Set<Object> sources = this.getAllSources();
  29.     Assert.notEmpty(sources, "Sources must not be empty");
  30.     //2.3.2 加载启动类,注入IOC容器
  31.     this.load(context, sources.toArray(new Object[0]));
  32.     //发布完成加载事件
  33.     listeners.contextLoaded(context);
  34. }
复制代码
2.3.1 & 2.3.2 获取启动类,注入IOC容器

当执行完getAllSources(),可以获取到启动类DemoApplication

重点看load()方法,进入load()。
  1. //SpringApplication.class
  2. protected void load(ApplicationContext context, Object[] sources) {
  3.     if (logger.isDebugEnabled()) {
  4.         logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
  5.     }
  6.         //创建BeanDefinitionLoader
  7.     BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
  8.     if (this.beanNameGenerator != null) {
  9.         loader.setBeanNameGenerator(this.beanNameGenerator);
  10.     }
  11.     if (this.resourceLoader != null) {
  12.         loader.setResourceLoader(this.resourceLoader);
  13.     }
  14.     if (this.environment != null) {
  15.         loader.setEnvironment(this.environment);
  16.     }
  17.         //加载启动类
  18.     loader.load();
  19. }
复制代码
其中getBeanDefinitionRegistry(context)方法会将之前的上下文context强转成BeanDefinitionRegistry,他们之间的继承关系很复杂,可以转换成不同的类完成不同的方法。createBeanDefinitionLoader()方法创建了一个BeanDefinitionLoader(),点进去看看。
  1. //BeanDefinitionLoader.class
  2. BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
  3.     Assert.notNull(registry, "Registry must not be null");
  4.     Assert.notEmpty(sources, "Sources must not be empty");
  5.     this.sources = sources;
  6.     //注解形式的Bean阅读器
  7.     this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
  8.     //xml形式的Bean阅读器
  9.     this.xmlReader = new XmlBeanDefinitionReader(registry);
  10.     if (this.isGroovyPresent()) {
  11.         this.groovyReader = new GroovyBeanDefinitionReader(registry);
  12.     }
  13.         //类路径扫描器
  14.     this.scanner = new ClassPathBeanDefinitionScanner(registry);
  15.     this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
  16. }
复制代码
一直跟进load()。
  1. //BeanDefinitionLoader.class
  2. private int load(Class<?> source) {
  3.     if (this.isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
  4.         GroovyBeanDefinitionSource loader = (GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
  5.         this.load(loader);
  6.     }
  7.         //启动类会走进这里
  8.     if (this.isEligible(source)) {
  9.         //将启动类注册进beanDefinitionMap
  10.         this.annotatedReader.register(new Class[]{source});
  11.         return 1;
  12.     } else {
  13.         return 0;
  14.     }
  15. }
复制代码
进入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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

一给

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表