IDEA-SpringBoot原理分析

传统的Spring框架实现一个Web服务,需要导入各种依赖JAR包,然后编写对应的XML配置文件等;相比较而言SpringBoot更加方便、快捷和高效。

SpringBoot依赖管理

两个核心依赖:
	Spring-boot-starter-parent
	Spring-boot-starter-web
Spring-boot-starter-parent:进行版本统一管理
	<!--Spring Boot 父项目依赖管理-->
	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    ...
    <!--Ctrl进入查看,其有一个父依赖spring-boot-dependencies-->
	<parent>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-dependencies</artifactId>
	    <version>2.3.4.RELEASE</version>
	</parent>
	...
	<!--继续进入查看spring-boot-dependencies底层源文件--><properties>标签内,对常用技术框架的依赖文件进行了统一版本号管理,常用的比如
tomcat、spring、activemp等,都有与Springboot相匹配的版本,所以在我们使用pom.xml
时不需要标注依赖文件版本号。
注意:	
	如果pom.xml引入的依赖文件不是spring-boot-starter-parent所管理的,比如Mybatis、
Druid技术框架,那么在引入依赖文件时,需要使用<version>标签指定依赖文件的版本号。
Spring-boot-starter-web: 该依赖启动器提供了Web开发场景所需的底层所有依赖文件,它对Web开发场景所需的依赖文件进行了统一管理
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        ...

进入spring-boot-starter-web源码:

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.3.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-json</artifactId>
      <version>2.3.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>2.3.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.9.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.9.RELEASE</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
  • 可以看出,仅仅在pom.xml文件中引入spring-boot-starter-web依赖启动器,就可以实现Web的场景开发,无须额外导入Tomcat服务器以及其他Web依赖文件等。
  • 当然,这些引入的依赖文件的版本号还是由Spring-boot-starter-parent父依赖进行统一管理。

Spring自动配置

@SpringBootApplication注解
@SpringBootApplication注解标注在Spring Boot启动入口处,查看该注解源码
	@SpringBootConfiguration
	@EnableAutoConfiguration
	@ComponentScan(
	    excludeFilters = {@Filter(
	    type = FilterType.CUSTOM,
	    classes = {TypeExcludeFilter.class}
	), @Filter(
	    type = FilterType.CUSTOM,
	    classes = {AutoConfigurationExcludeFilter.class}
	)}
	)
  • 可以看出@SpringBootApplication注解为一组合注解,包含上图三个核心注解。
  • @SpringBootConfiguration注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}
 @SpringBootConfiguration注解:表示SpringBoot配置类,标识一个可以被组件扫描器扫描的配置类。
 其内部有一个@Configuration注解,该注解是由Spring框架提供的,表示当前类为一个配置类,并可以被组件扫描器扫描。
  • @EnableAutoConfiguration注解:开启自动配置功能
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}
同样为一组合注解
@AutoConfigurationPackage:	
	查看其源码,可以发现其功能由@Import注解实现,作用是向容器导入注册的所有组件,导入的组件由Registry决定。
	该注解的主要作用是获取项目主程序启动类所在根目录,从而指定后续组件扫描器要扫描的包位置。
@Import({AutoConfigurationImportSelector.class})
	如下核心方法:筛选出当前项目环境需要启动的自动配置类XxxAutoConfiguration,从而实现当前项目运行所需的自动配置环境。
 protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            //this.getCandidateConfigurations(annotationMetadata, attributes)方法
            //从META-INF/spring-factories中获取所有候选自动配置类
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            //this.getConfigurationClassFilter().filter(configurations)方法
            //对所有候选配置类进行筛选,根据pom.xml文件筛选出当前项目环境的自动配置类
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }
  • @ComponentScan注解:是一个组件包扫描器,用于将指定包中的注解类自动装配到Spring的Bean容器中,其具体扫描的包的根路径由Spring Boot项目主程序启动类所在包位置决定,由@AutoConfigurationPackage注解解析得到主程序启动类所在包的具体位置。

Spring自动执行流程

  • SpringApplication实例的初始化
  public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class[]{primarySource}, args);
    }

    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }
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));
        //判断当前webApplicationType的应用类型
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        //设置SpringApplication应用初始化器,使用类加载器SpringFactoriesLoader从Spring.factiories文件中获取
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //设置SpringApplication的应用监听器,获取方式同上
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        //推断并设置项目main()方法启动的主程序类
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }
  • 项目的初始化启动
 public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        //1.获取初始化的SpringApplicationRunListeners 运行监听器并运行
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //2.项目和运行环境environment 预设置
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            //3.项目应用上下文ApplicationContext的预配置
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }
			//4.由项目运行监听器启动配置好的应用上下文ApplicationContext
            listeners.started(context);
            //5.调用应用上下文ApplicationContext中配置的程序执行器XxxRunner
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
        	//6.由项目运行监听器持续运行配置好的应用上下文ApplicationContext
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值