栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Springboot笔记(2):SpringBoot运行原理/狂神说

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Springboot笔记(2):SpringBoot运行原理/狂神说

目录

0、写在前面

1、微服务

2、Springboot内容

3、SpringCloud内容

4、Spring回顾

5、Springboot学习

1、项目构建

2、项目结构分析:

2.1、pom分析

2.2、编写一个http接口

2.3、将项目打成jar包,点击 maven的 package

2.4、彩蛋

2.5、热部署

3、运行原理

3.1、父依赖

3.2、启动类

spring.factories:自动配置核心文件

3.3、Run

run方法流程分析

源码分析:


0、写在前面

ProcessOn:画脑图

1、微服务

javase:OOP

mysql:持久化

html + css + js + jquery + 框架

javaweb: 独立开发MVC三层架构的网站,原始

SSM:框架,简化了开发流程,配置开始比较复杂。

之前都是打war包,放到tomcat运行。


SpringBoot:Spring再简化,打包成jar包,内嵌tomcat

微服务架构

2、Springboot内容

springboot是什么配置yml集成web开发:业务核心集成数据库:Druid分布式开发:Dubbo + zookeeperswagger + 接口文档任务调度SpringSecurity : Shiro

3、SpringCloud内容

微服务SpringCloud入门RestfulEurekaNginxRibbonFeignHystrixZuul路由网关SpringCloud Config:git

4、Spring回顾

Spring目的:Spring是为了解决企业级应用开发的复杂性而创建的,简化开发。

Spring是如何简化Java开发的

为了降低Java开发的复杂性,Spring采用了以下4种关键策略:

1、基于POJO的轻量级和最小侵入性编程,所有东西都是bean;2、通过IOC,依赖注入(DI)和面向接口实现松耦合;3、基于切面(AOP)和惯例进行声明式编程;4、通过切面和模版减少样式代码,RedisTemplate,xxxTemplate;

5、Springboot学习

Spring Boot 基于 Spring 开发,Spirng Boot 本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于 Spring 框架的应用程序。Springboot并不是用来替代 Spring 的解决方案,而是和 Spring 框架紧密结合用于提升 Spring 开发者体验的工具。Spring Boot 以约定大于配置的核心思想,默认帮我们进行了很多设置,多数 Spring Boot 应用只需要很少的 Spring 配置。同时它集成了大量常用的第三方库配置(例如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等等),Spring Boot 应用中这些第三方库几乎可以零配置的开箱即用。

Spring Boot的主要优点:

为所有Spring开发者更快的入门

开箱即用,提供各种默认配置来简化项目配置

内嵌式容器简化Web项目

没有冗余代码生成和XML配置的要求

1、项目构建

java version "1.8.0_181"

Maven-3.6.1

SpringBoot 2.x 最新版

项目创建方式一:使用Spring Initializr 的 Web页面创建项目

1、打开  https://start.spring.io/

2、填写项目信息

3、点击”Generate Project“按钮生成项目;下载此项目

4、解压项目包,并用IDEA以Maven项目导入,一路下一步即可,直到项目导入完毕。

5、如果是第一次使用,可能速度会比较慢,包比较多、需要耐心等待一切就绪。

项目创建方式二:使用 IDEA 直接创建项目

1、创建一个新项目

2、选择spring initalizr , 可以看到默认就是去官网的快速构建工具那里实现

3、填写项目信息

4、选择初始化的组件(初学勾选 Web 即可)

5、填写项目路径

6、等待项目构建成功

注意:一般将文件:.mvn、.gitignore、.HELP.md、mvnw.cmd、mvnw删掉即可。

2、项目结构分析:

通过上面步骤完成了基础项目的创建。就会自动生成以下文件。

1、程序的主启动类

2、一个 application.properties 配置文件

3、一个 测试类

4、一个 pom.xml

2.1、pom分析

都是以spring-boot-start开头

打开pom.xml,看看Spring Boot项目的依赖:



    org.springframework.boot
    spring-boot-starter-parent
    2.2.5.RELEASE
    



    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
        
        
            
                org.junit.vintage
                junit-vintage-engine
            
        
    



    
        
        
            org.springframework.boot
            spring-boot-maven-plugin
        
    

项目元数据信息:创建时输入Project metadata部分,也就是Maven项目的基本信息,包括:groupId、artifactId、version、name、description等。

parent:继承spring-boot-starter-parent 的依赖管理,控制版本与打包等内容。

dependencies:项目具体依赖,包含spring-boot-starter-web用于实现HTTP接口,该依赖包含了SpringMVC,使用SpringMVC构建 WEB (包含restful) 应用程序的入门者,使用Tomcat作为默认 嵌入式容器。spring-boot-starter-test 用于编写单元测试的依赖包。

build:构建配置部分,默认使用 spring-boot-maven-plugin,配合sprint-boot-starter-parent 就可以把Spring Boot应用打包成jar 直接运行。

2.2、编写一个http接口

1、在主程序的同级目录下,新建一个controller包,一定要在同级目录下,否则识别不到

2、在包中新建一个HelloController类

3、编写完毕后,从主程序启动项目,浏览器发起请求,看页面返回;控制台输出了 Tomcat 访问的端口号!

简单几步,就完成了一个web接口的开发。

2.3、将项目打成jar包,点击 maven的 package

如果遇到以上错误,可以配置打包时 跳过项目运行测试用例


    org.apache.maven.plugins
    maven-surefire-plugin
    
        
        true
    

2.4、彩蛋

如何更改启动时显示的字符拼成的字母,SpringBoot呢?也就是 banner 图案;

只需一步:到项目下的 resources 目录下新建一个banner.txt 即可。

图案可以到:https://www.bootschool.net/ascii 这个网站生成,然后拷贝到文件中即可!

SpringBoot这么简单的东西背后一定有故事,我们之后去进行一波源码分析!

2.5、热部署

添加依赖:dev-tools

3、运行原理

        我们之前写的HelloSpringBoot,到底是怎么运行的呢,Maven项目,我们一般从pom.xml文件探究起;Pom.xml

3.1、父依赖

其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件!


    org.springframework.boot
    spring-boot-starter-parent
    2.2.5.RELEASE
     

点进去,发现还有一个父依赖


    org.springframework.boot
    spring-boot-dependencies
    2.2.5.RELEASE
    ../../spring-boot-dependencies

        这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;

以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本了;

启动器 spring-boot-starter


    org.springframework.boot
    spring-boot-starter-web

springboot-boot-starter-xxx:就是spring-boot的场景启动器spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件;

SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter;

3.2、启动类

默认的主启动类:反射

//@SpringBootApplication 来标注一个主程序类
//说明这是一个Spring Boot应用
@SpringBootApplication
public class SpringbootApplication {

   public static void main(String[] args) {
     //以为是启动了一个方法,没想到启动了一个服务
      SpringApplication.run(SpringbootApplication.class, args);
   }

}

但是一个简单的启动类并不简单!我们来分析一下这些注解都干了什么

@SpringBootApplication

作用:标注在某个类上说明这个类是SpringBoot的主配置类 , SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;

进入这个注解:可以看到上面还有很多其他注解!

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    // ......
}

@ComponentScan

这个注解在Spring中很重要 ,它对应XML配置中的元素。

作用:自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中

@SpringBootConfiguration

作用:SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类;

我们继续进去这个注解查看

// 点进去得到下面的 @Component
@Configuration
public @interface SpringBootConfiguration {}

@Component
public @interface Configuration {}

这里的 @Configuration,说明这是一个配置类 ,配置类就是对应Spring的xml 配置文件;

里面的 @Component 这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用!

我们回到 SpringBootApplication 注解中继续看。

@EnableAutoConfiguration:开启自动配置功能

以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置 ;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效;

点进注解接续查看:

@AutoConfigurationPackage :自动配置包

@import({Registrar.class})
public @interface AutoConfigurationPackage {
}

@import :Spring底层注解@import , 给容器中导入一个组件

Registrar.class 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器 

这个分析完了,退到上一步,继续看

@import({AutoConfigurationimportSelector.class}) :给容器导入组件 ;

AutoConfigurationimportSelector :自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:

1、这个类中有一个这样的方法

// 获得候选的配置
protected List getCandidateConfigurations(Annotationmetadata metadata, AnnotationAttributes attributes) {
    //这里的getSpringFactoriesLoaderFactoryClass()方法
    //返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration
    List configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in meta-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
    return configurations;
}

2、这个方法又调用了  SpringFactoriesLoader 类的静态方法!我们进入SpringFactoriesLoader类loadFactoryNames() 方法​​​​​​

public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    //这里它又调用了 loadSpringFactories 方法
    return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

3、我们继续点击查看 loadSpringFactories 方法

private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
    //获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身
    MultiValueMap result = (MultiValueMap)cache.get(classLoader);
    if (result != null) {
        return result;
    } else {
        try {
            //去获取一个资源 "meta-INF/spring.factories"
            Enumeration urls = classLoader != null ? classLoader.getResources("meta-INF/spring.factories") : ClassLoader.getSystemResources("meta-INF/spring.factories");
            linkedMultiValueMap result = new linkedMultiValueMap();

            //将读取到的资源遍历,封装成为一个Properties
            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                UrlResource resource = new UrlResource(url);
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                Iterator var6 = properties.entrySet().iterator();

                while(var6.hasNext()) {
                    Entry entry = (Entry)var6.next();
                    String factoryClassName = ((String)entry.getKey()).trim();
                    String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                    int var10 = var9.length;

                    for(int var11 = 0; var11 < var10; ++var11) {
                        String factoryName = var9[var11];
                        result.add(factoryClassName, factoryName.trim());
                    }
                }
            }

            cache.put(classLoader, result);
            return result;
        } catch (IOException var13) {
            throw new IllegalArgumentException("Unable to load factories from location [meta-INF/spring.factories]", var13);
        }
    }
}

4、发现一个多次出现的文件:spring.factories,全局搜索它

spring.factories:自动配置核心文件

我们根据源头打开spring.factories , 看到了很多自动配置类;这就是自动配置根源所在!

WebMvcAutoConfiguration

我们在上面的自动配置类随便找一个打开看看,比如 :WebMvcAutoConfiguration

可以看到这些一个个的都是JavaConfig配置类,而且都注入了一些Bean,可以找一些自己认识的类,看着熟悉一下!

        所以,自动配置真正实现是从classpath中搜寻所有的meta-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容器中。

结论:

    SpringBoot在启动的时候从类路径下的meta-INF/spring.factories中获取EnableAutoConfiguration指定的值;

    将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;

    整个J2EE的整体解决方案和自动配置都在 springboot-autoconfigure-2.2.0.RELEASE.jar 的jar包中;

    它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;

    他会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器中;

    容器中也会存在非常多的 xxxAutoConfiguration 的文件(@Bean),就是这些类给容器中导入了这个场景需要的所有组件,并自动配置。@Configuration、JavaConfig;

    有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作。

        Springboot所有的自动配置都是在启动的时候扫描并加载:spring.facotries 所有的自动配置类都在这里面,但是不一定生效,要判断条件是否成立,只要导入了对应的start,就有对应的启动器了,有了启动器,我们自动装配就会成功,然后就配置成功!

现在大家应该大概的了解了下,SpringBoot的运行原理,后面我们还会深化一次!

SpringApplication

3.3、Run

我最初以为就是运行了一个main方法,没想到却开启了一个服务;

@SpringBootApplication
public class SpringbootApplication {
    public static void main(String[] args) {
//该方法返回一个ConfigurableApplicationContext对象
//参数1:应用入口的类,参数2:命令行参数
        SpringApplication.run(SpringbootApplication.class, args);
    }
}

SpringApplication.run分析

分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;

SpringApplication

这个类主要做了以下四件事情:

1、推断应用的类型是普通的项目还是Web项目;

2、查找并加载所有可用初始化器 , 设置到initializers属性中;

3、找出所有的应用程序监听器,设置到listeners属性中;

4、推断并设置main方法的定义类,找到运行的主类。

查看构造器:​​​​​​​​​​​​​​

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
    // ......
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    this.setInitializers(this.getSpringFactoriesInstances();
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

run方法流程分析

JavaConfig@Configuration@Bean

源码分析:

配置文件:spring.factories

配置类:WebMvcConfiguration等

问题:

1、在spring.factories中的所有配置类,为什么有的没有生效,需要导入对应的start才能起作用?

主要是核心注解:@ConditionOnXXX:如果这里面的条件都满足,才会生效。

例如:在pom中导入了依赖. spring-boot-starter-web,则WebMvcAutoConfiguration上的类Servlet、DispatcherServlet、WebMvcConfigurer就会有。则WebMvcAutoConfiguration就会生效

@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
public class WebMvcAutoConfiguration {

}

笔记:

狂神说 SpringBoot笔记_敲代码的乔帮主-CSDN博客_springboot狂神说笔记

狂神说SpringBoot01:Hello,World!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/731320.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号