SpringBoot 源码理解

-- 阅读之前先掌握这个

  • 常见的ApplicationContext: FileSystemXmlApplicationContext,ClassPathXmlApplicationContext,AnnoationConfigApplicationContext,ConfigurableApplicationContext,GenericApplicationContext(很多)
  • 常见的Scanner:ClassPathBeanDefinationScanner,AnnotationBeanDefinitionScanner
java 复制代码
// 创建容器
GenericApplicationContext applicationContext = new GenericApplicationContext();

// 确定bean类型
AbstractBeanDefinition beanDefinition =
        BeanDefinitionBuilder.genericBeanDefinition(类).setScope(域).getBeanDefinition();
// 注册bean
applicationContext.registerBeanDefinition();
//启动IOC
applicationContext.refresh();
// ....
// 实现注解的各种方式
//....
applicationContext.close();
  • AOP
java 复制代码
// 设置proxyFactory
ProxyFactory proxyFactory = new ProxyFactory();
// 设置目标对象
proxyFactory.setTarget();
// 强制使用cglib
proxyFactory.setProxyTargetClass();
// 设置jdk动态代理
proxyFactory.setInterfaces();
// 设置通知
proxyFactory.addAdvice()
// proxyFactory.addAdvisor()配合DefaultPointcutAdvisor()

资源加载

java 复制代码
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    // 加载各种个样的配置文件
    this.resourceLoader = resourceLoader;
    // 断言工具
    Assert.notNull(primarySources, "PrimarySources must not be null");
    // 加载类的(给IOC的)
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 判断web类型
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    this.bootstrapRegistryInitializers = new ArrayList<>(
          getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    // 从ApplicationContext初始化前读取的(springBoot特有的)
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 从监听器读取,横跨整个ApplicationContext生命周期(SpringBoot特有的方法)
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //主类推断(通过这个和primarySource就可以得出当前是不是主类加载)
    this.mainApplicationClass = deduceMainApplicationClass();
}

web应用判断

Java 复制代码
static WebApplicationType deduceFromClasspath() {
//  使用 classUtils 判断是不是WebFlux的类型
    if ( ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && 
        !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)  &&
        !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
        // 返回一个Reactive类型项目
       return WebApplicationType.REACTIVE;
    }
    // 判断是不是非Web类型
    for (String className : SERVLET_INDICATOR_CLASSES) {
       if (!ClassUtils.isPresent(className, null)) {
          return WebApplicationType.NONE;
       }
    }
    // 以上都不是即Servlet项目
    return WebApplicationType.SERVLET;
}

spring.factories文件(SpringBoot的SPI原理)

  • getSpringFactoriesInstances和createSpringFactoriesInstances这两个实际上就是创建和获取Spring.factories本质没有什么可讲的。
java 复制代码
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    ClassLoader classLoaderToUse = classLoader;
    if (classLoaderToUse == null) {
       classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
    }
    String factoryTypeName = factoryType.getName();
    return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}

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

    result = new HashMap<>();
    try {
       Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
       while (urls.hasMoreElements()) {
          URL url = urls.nextElement();
          UrlResource resource = new UrlResource(url);
          Properties properties = PropertiesLoaderUtils.loadProperties(resource);
          for (Map.Entry<?, ?> entry : properties.entrySet()) {
             String factoryTypeName = ((String) entry.getKey()).trim();
             String[] factoryImplementationNames =
                   StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
             for (String factoryImplementationName : factoryImplementationNames) {
                result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
                      .add(factoryImplementationName.trim());
             }
          }
       }

       // Replace all lists with unmodifiable lists containing unique elements
       result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
             .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
       cache.put(classLoader, result);
    }
    catch (IOException ex) {
       throw new IllegalArgumentException("Unable to load factories from location [" +
             FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
    return result;
}

run方法核心原理

java 复制代码
public ConfigurableApplicationContext run(String... args) {
    // 统计启动时间
    long startTime = System.nanoTime();
    //创建DefaultBootstrapContext
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    // 创建ApplicationContext编译对象
    ConfigurableApplicationContext context = null;
    //
    configureHeadlessProperty();
    // 创建SpringApplicationRunListeners监听器
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 开始监听
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    try {
      // 传入命令行参数
       ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
       // 准备环境
       ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
       configureIgnoreBeanInfo(environment);
       // 控制台打印欢迎信息
       Banner printedBanner = printBanner(environment);
       // 赋值ConfigurableApplicationContext运行对象
       context = createApplicationContext();
       context.setApplicationStartup(this.applicationStartup);
       // 准备上下文
       prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
       // 刷新上下文,启动SpringIOC
       refreshContext(context);
       // 回调操作
       afterRefresh(context, applicationArguments);
       // 计算耗时时间
       Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
       if (this.logStartupInfo) {
       //输出耗时日志
          new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
       }
       // 监听完毕
       listeners.started(context, timeTakenToStartup);
       // 查看CommandLineRunner和applicationRunner方法
       callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
    // 处理启动异常
       handleRunFailure(context, ex, listeners);
       throw new IllegalStateException(ex);
    }
    try {
    // 计算耗时时间
       Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
       // 通知监听器,应用已经准备好
       listeners.ready(context, timeTakenToReady);
    }
    catch (Throwable ex) {
    // 处理异常
       handleRunFailure(context, ex, null);
       throw new IllegalStateException(ex);
    }
    // 返回已经创建好的上下文
    return context;
}
相关推荐
RISCV_Explorer1 小时前
RISC-V处理器性能优化:从指令集到微架构的协同设计
后端·risc-v
她的男孩1 小时前
数据库改了配置,说好的 30 秒自动刷新根本没跑:那条 @Scheduled 是注释状态
java·后端·架构
右耳朵猫AI2 小时前
Rust周刊2026W38 | mold重写Rust、认证级Rust裸机、Slint 1.18发布、lint提速3133倍
后端·rust·系统编程
是枚小菜鸡儿吖2 小时前
同版式截图批量打码:用华为云码道做一个本地小工具!
人工智能·后端·ai·华为云码道
+VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue图书借阅管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
IT_陈寒2 小时前
Vite这坑我踩了,说说静态资源加载那些事儿
前端·人工智能·后端
我不会起名字3222 小时前
一天一道力扣Hot100(37):深度优先算法--括号生成
java·数据结构·c++·后端·python·算法·go