Spring Boot源码(一) - 分析总览

    Spring Boot当前版本为2.2.0,之前一直对Spring Boot的各个模块比较模糊,很难理解自动装配等注解与容器启动的关系等。但是后面梳理完了之后发现,Spring Boot只是在Spring的基础上做了比较多的封装和扩展,个人理解。 还是先看一下,

一、Spring Boot的特性

 

1、独立运行Spring项目

    之前的时候Spring只是作为一个服务的一部分,或者说是容器。特别是之前的web项目是通过监听Servlet服务器规范的ContextLoadeoaderListener(或者ContextLoaderPlugin)等方式,监听服务器启动后启动Ioc容器。现在不论是jar还是war都可以使用java -jar xxx.jar方式启动项目。

2、嵌入式Servlet服务器(如Tomcat)

    独立运行Spring项目,特别是web项目的情况下,使用内嵌的Servlet服务器(如Tomcat提供的内嵌版本)。首先是启动Spring项目,然后在AbstractApplicationContext的refresh方法,在执行模板方法的onRefresh的扩展部分,调用createWebServer方法以创建Servlet服务器,是Spring与Tomcat角色的转变。

3、提供starter简化maven配置

    Spring Boot提供了一系列的starter的maven依赖,特别是spring-boot-starter-parent。只需要一个基础的依赖就能引入大部分的自动装配的模块(功能)。

4、自动装配

    自动装配使用 @ImportImportBeanDefinitionRegistrar回调接口的方式实现,那么发生的时机是 SpringApplication.run执行时,会执行AbstractApplicationContext的refresh方法时执行。具体自动装配的执行时机是在Spring源码-ImportSelector实现分析或参见SpringIoc源码(十)- ApplicationContext(六)- refresh(ConfigurationClassPostProcessor上)

5、准生产的应用监控

    Spring Boot在原有Spring的Environment的基础上进行扩展出Actuator模块,可以完成内存等的常规运营监控,特别适合小公司能快速搭建监控。

6、无代码生成和xml配置

    使用条件注解(@Conditional以及其扩展注解)和Java配置组合,不需要任何的xml配置就能实现所有配置。

 

    在梳理完Spring的源码后发现,其强大之处在于Ioc容器、ApplicationContext的生命周期、回调接口(BeanPostProcessor等),以及每个Bean的生命周期回调。生命周期也就意味着模板方法模式定义的回调,同样Spring Boot也定义了自己的回调组件。

SpringApplicationRunListener、(贯穿了Spring Boot的整个启动过程)

ApplicationContextInitializer(只是AbstractApplicationContext的准备阶段)

ApplicationRunner、CommandLineRunner(环境参数相关回调,只是前者参数是被封装过的,后者是main方法的原参数)

 

二、SpringApplication结构

1、主要字段

    // @SpringBootApplication注解标注的类
    private Set<Class<?>> primarySources;

    // 注册成Bean的全限定名,默认为空后续会将primarySources添加进去
    private Set<String> sources = new LinkedHashSet<>();

    // main方法类,一般与primarySources相同
    private Class<?> mainApplicationClass;

    // 启动Banner图,默认会启动SpringBootBanner
    private Banner.Mode bannerMode = Banner.Mode.CONSOLE;

    // 是否大于启动的StopWatch的信息
    private boolean logStartupInfo = true;

    // 是否大于main方法启动的args参数
    private boolean addCommandLineProperties = true;

    // 是否为ApplicationContext添加ConversionService
    private boolean addConversionService = true;

    // Banner图
    private Banner banner;

    // 类加载器,用于在ApplicationContext还没有启动时,加载类
    // ApplicationContextInitializer等类型的类
    private ResourceLoader resourceLoader;

    // Bean的名称生成器,否则走默认的名称生成方式(第一个字母小写的驼峰,多个大写连着的除外)
    private BeanNameGenerator beanNameGenerator;

    // Spring的Environment
    private ConfigurableEnvironment environment;

    // ApplicationContext的子类类型
    private Class<? extends ConfigurableApplicationContext> applicationContextClass;

    // Application类型,用于确认上面生成的applicationContextClass类型
    private WebApplicationType webApplicationType;

    // 配置headless的值
    private boolean headless = true;

    // 是否注册钩子
    private boolean registerShutdownHook = true;

    // 初始化器(后面会详细分析)
    private List<ApplicationContextInitializer<?>> initializers;

    // 监听(后面会详细分析)
    private List<ApplicationListener<?>> listeners;

    // 默认配置,会叠加@ConfigurationProperties
    private Map<String, Object> defaultProperties;

    // Spring Profiles
    private Set<String> additionalProfiles = new HashSet<>();

    // 是否允许BeanDefinition覆盖
    private boolean allowBeanDefinitionOverriding;

    // 是否自定义Environment,因为Spring的ApplicationContext在refresh时会初始化
    private boolean isCustomEnvironment = false;

    // 是否加载LazyInitializationBeanFactoryPostProcessor类型的BeanPostProcessor
    private boolean lazyInitialization = false;

2、构造器和run方法

// 1、类加载器、main方法类的Class
SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources);

// 2、main方法类的Class
SpringApplication(Class<?>... primarySources);

    首先构造器可以传入类加载器,一般都不传入,则在启动时候使用当前线程进行获取类加载器,后续主要用于加载ApplicationContextInitializer和ApplicationListener等类型的类。

    primarySources为@SpringBootApplication注解标记的类,主要用于后续需要使用该类的包(作为基准包)进行@Conponent的扫描。以及判断当前类是否为@Conponent,是的话则注册为Bean。

// main方法类的Class、main方法启动参数
run(Class<?> primarySource, String... args);

run(Class<?>[] primarySources, String[] args);

run(String... args);

    如果构造器没有传入primarySource参数,则在run方法时还可以传入。但是run方法执行时,一定需要传入args,很多地方会进行使用,并且会进行封装成ApplicationArguments。若不需要使用自动扫描基础包下的@Component的功能,则可以调用方法(不建议):

public static void main(String[] args) throws Exception {
    SpringApplication.run(new Class<?>[0], args);
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值