springboot基础

252 阅读7分钟
  • 先部署项目,看效果:

    报错1:"Dependency 'xxxx‘ not found"

    "Project 'xxxx‘ not found"

    原因:IDEA没有配置好maven,修改maven home directory、user settings file、local repository。

    报错2:Plugin 'org.springframework.boot:spring-boot-maven-plugin:' not found

    原因:pom.xml文件中中的 spring-boot-maven-plugin 没加版本号,版本号需要与项目springboot版本一致,此处为 2.3.7.RELEASE 。

    报错3:Project ‘org.springframework.boot:spring-boot-starter-parent:2.4.5‘ not found

    在使用IntelliJ IDEA 时出现这个问题,选择File—>Invalidate Caches / Restart…就可以解决这个问题,因为更新之后,缓存没有及时生效,重启之后就好了。

  • 为什么框架的出现会取代原有 JSP+Servlet 的开发模式?

是因为框架的封装和抽象程度更加完善,也使得代码复用性更高、项目的可维护性提高、开发和学习成本更低,加快开发进度并最终成为行业内的一套开发标准。从这个角度来说,越简洁的开发模式就越能减轻开发人员的负担并提升开发效率

  • springboot的特性:

    • 可快速创建Spring 项目,简化开发

      Spring Initializr 方案是创建新的Spring Boot 项目不错的选择。使用官方的初始化方案创建 Spring Boot 项目能够确保你获得经过测试和验证的依赖项,这些依赖项适用于自动配置,能够大大简化项目创建流程。

    • starters 自动依赖与版本控制

      Spring Boot 通过一些 starter 的定义减少开发人员在依赖管理上所花费的时间,在整合各项功能的时候不需要去自行搜索和查找所需依赖并且在 Maven 的 pom 文件中进行定义。

    • 习惯优于配置

    • 大量的自动配置,简化开发

    • 使用嵌入式的servlet容器

    • 对主流框架的无配置集成

      在 Web 应用中,spring-boot-starter-web 为我们提供了嵌入的 Tomcat 以及 SpringMVC 的依赖, 可以快速构建 MVC 模式的 Web 工程。

      在 SOA 及微服务中,用 Spring Boot 可以包装每个服务, Spring Cloud即是一套基于 Spring Boot 实现分布式系统的工具,适用于构建微服务。

      spring-boot-starter-websocket 可以快速实现消息推送,也可以整合流行的 RPC 框架,提供 RPC 服务接口,只要简单地加入对应的 starter 组件即可。

4、项目搭建及启动

使用spring initializer搭建的web项目中:

src/main/resources 表示配置文件目录,与普通的 Spring 项目相比有些区别:该目录下有 static 和 templates 两个目录,是 Spring Boot 项目默认的静态资源文件目录和模板文件目录。在 Spring Boot 项目中是没有 webapp 目录的,默认是使用 static 和 templates 两个文件夹。

5、特性讲解与源码分析

5.1 特性讲解

  • 约定优于配置

    convention over configuration,这个理念不是springboot独有的,其实我们一直都在遵循并使用,比如在 MVC 项目的开发中会把实体类放到 entity 目录下、数据接口层会定义在 dao 目录下、控制器会定义在 controller 目录下,这就是大家都遵循的规矩。

    如果在项目中遵守命名规范就可以显著地减少系统需要的配置,不然目录名、包名乱取名字这些都会使得配置难度增大。

  • 依赖管理

    在项目的 pom.xml 文件中,可看到配置了 属性,意味着它依赖一个父项目,其父项目为 spring-boot-starter-parent 。它也拥有 属性,其值为 spring-boot-dependencies

    spring-boot-dependencies 就是 springboot 项目依赖的版本管理中心。 它已经默认帮我们配置好了大部分依赖的版本信息,这些版本信息随着 Spring Boot 版本的更新也会随之更改。如果自行配置的话会将默认配置覆盖掉。

  • web场景启动器

    spring-boot-starter-web 中,已经定义了 SpringMVC 所需的依赖以及内置的 Tomcat 依赖。

5.2 基于主程序类的源码分析

主程序类如下:

 @SpringBootApplication
 public class Newbee810Application {
 ​
     public static void main(String[] args) {
         SpringApplication.run(Newbee810Application.class, args);
     }
 ​
 }

重点关注 @SpringBootApplication 注解 和 SpringApplication.run() 方法。

  • @SpringBootApplication

    由注解源码可以看出,@SpringBootApplication 注解是一个复合注解,其中前面四个注解是 Java 元注解,含义分别为:

    • @Target(ElementType.TYPE): 类、接口(包括注解类型)和 enum 声明
    • @Retention(RetentionPolicy.RUNTIME): 运行时注解
    • @Documented: 注解添加到 Java doc 中
    • @Inherited: 允许继承

    重要的是后面三个 Spring Boot 框架的自定义注解,含义分别为:

    • @SpringBootConfiguration: Spring Boot 配置注解

      仅仅是对 @Configuration 注解进行了包装,本质上依然是 @Configuration 注解

    • @EnableAutoConfiguration: 开启自动配置功能

      除上面四个 Java 元注解外,这个注解最重要的就是 @AutoConfigurationPackage 和 AutoConfigurationImportSelector 组件。

      • @AutoConfigurationPackage,使用 @Import 注解,自动将AutoConfigurationPackages.Registrar.class 指定的组件注册到 IOC 容器中。默认情况下是当前主程序类所在的包及其子包

      • AutoConfigurationImportSelector,是整个自动配置功能的核心实现,会将所有需要导入的组件以全类名的方式返回,这些组件就会被注册到 IOC 容器中。

         public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
         ​
             selectImports()
             getAutoConfigurationEntry()
             getImportGroup()
             isEnabled()
             getCandidateConfigurations()    //getCandidateConfigurations() 方法会调用 SpringFactoriesLoader 类的 loadFactoryNames() 获取所有的自动配置类类名
        

        注意!上面代码实现的几个接口还未学习!到Spring教程中去看! 里面定义的几个方法也没有看!!!

        由以上源码可以得出结论:Spring Boot 在启动的时候从类路径下的 META-INF/spring.factories 中获取 EnableAutoConfiguration 指定的配置项,过滤后将这些值作为自动配置类导入到容器中。有哪些自动配置类呢?可以在 spring-boot-autoconfigure-2.1.0.RELEASE.jar 依赖中查看。

        自动配置类生效之后,帮我们进行相关组件的自动配置工作,以前我们需要自己配置在 xml 文件中的内容都交给 Spring Boot 完成,免去了我们手动编写配置注入功能组件等的工作。

    • @ComponentScan: 组件自动扫描

      @Controller 、 @Service 、 @Repository 都有一个共同的注解 @Component,他们都会被@ComponentScan注解装配到 IOC 容器中。

  • SpringApplication.run()

     public ConfigurableApplicationContext run(String... args) {
         
         StopWatch stopWatch = new StopWatch();
         // 1:代码执行时间监控开启,Spring Boot 应用启动成功后会打印启动时间
         stopWatch.start();
         DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
         ConfigurableApplicationContext context = null;
         
         // 2:配置 headless 属性。  java.awt.headless是 J2SE 的一种模式,用于在缺失显示屏、鼠标或者键盘时的系统配置,默认为 true。
         this.configureHeadlessProperty();
         
         // 3:获取 SpringApplicationRunListeners。  getRunListeners()方法 会从类路径下的 META-INF/spring.factories 中获取 SpringApplicationRunListener 指定的类,此处为EventPublishingRunListener 。
         SpringApplicationRunListeners listeners = this.getRunListeners(args);
         
         // 4:回调所有 SpringApplicationRunListener 对象的 starting() 方法。
         listeners.starting(bootstrapContext, this.mainApplicationClass);
     ​
         try {
             ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
             
             // 5:preparedEnvironment 主要完成对 ConfigurableEnvironment 的初始化工作
             ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
             this.configureIgnoreBeanInfo(environment);
             
             // 6:获取打印的 Spring Boot 启动 banner 对象。默认实现为 org.springframework.boot.SpringBootBanner
             Banner printedBanner = this.printBanner(environment);
             
             // 7:创建 ApplicationContext 并配置 ApplicationContext 实例
             context = this.createApplicationContext();
             context.setApplicationStartup(this.applicationStartup);
             this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
             
             // 8:refreshContext() 刷新 ApplicationContext 对象。实现方法就是 Spring 的 refresh() 方法————Spring 所有的初始化都在这个方法中完成,。它会将之前通过 @EnableAutoConfiguration 获取的所有配置以及其他形式的 IOC 容器配置加载到已经准备完毕的ApplicationContext 对象中。
             this.refreshContext(context);
             this.afterRefresh(context, applicationArguments);
             stopWatch.stop();
             if (this.logStartupInfo) {
                 (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
             }
     ​
             listeners.started(context);
             // 9:在 ApplicationContext 完成启动后,会对 ApplicationRunner 和 CommandLineRunner 进行回调处理,查找当前ApplicationContext中是否注册有 CommandLineRunner,如果有,则遍历执行它们。
             this.callRunners(context, applicationArguments);
         } catch (Throwable var10) {
             // 10:在 SpringApplication 启动过程中,如果出现问题会由异常处理器接管,对异常进行统一处理。
             this.handleRunFailure(context, var10, listeners);
             throw new IllegalStateException(var10);
         }
     ​
         try {
             listeners.running(context);
             return context;
         } catch (Throwable var9) {
             this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
             throw new IllegalStateException(var9);
         }
     }
    

Spring Boot 框架的核心依然是 Spring ,它只是在 Spring 框架的基础之上,针对 Spring 应用启动流程进行了规范和封装。Spring 的核心启动方法是 refresh() ,Spring Boot 在启动时依然会调用该核心方法,只是调用该方法之前已经设置了大部分组件,在平时的 Spring 项目开发中,这些组件通常是通过 xml 配置文件进行定义和装载,而 Spring Boot 将该过程简化并通过自动配置的方式去实现该过程,它只是基于 Spring 框架的一个增强版的应用启动器。