全面从0到1深入挖掘SpringBoot

1,119 阅读15分钟

SpringBoot作用

能快速创建出生产级别的spring应用

springboot优点

  • 创建独立spring应用
  • 内嵌web服务器
  • 自动starter依赖,简化构建配置
  • 自动配置Spring以及第三方功能
  • 提供生产级别的监控,健康检查即外部化配置
  • 无代码生成,无需编写xml

SpringBoot缺点

  • 人称版本帝,迭代快,需要时刻关注变化
  • 封装太深,内部原理复杂,不容易精通

SpringBoot入门

系统要求

  • java8以上
  • Maven3.3+
  • idea 2019.1.2

HelloWord

  • 创建maven工程
  • 引入依赖
  • 创建主程序
  • 编写业务
  • 测试:直接运行main方法
  • 简化配置:application.properties(yml)
  • 简化部署:把项目打成可直接执行的jar包,直接放在服务器执行即可

注意点:执行失败的话,取消掉cmd的快速编辑模式

了解自动配置原理

  • 1.1依赖管理
    • 父项目做依赖管理
    • 开发导入starter场景启动器
      • 1.见到很多 spring-boot-starter-*:*就某种场景
      • 只要引入starter,这个场景的所有常规需要的依赖我们都自动导入
      • springboot所有支持的场景:docs.spring.io/springboot/…
      • 见到 *-spring-boot-starter:第三方为我们提供的简化开发的场景启动器
      • 所有场景启动器最底层的依赖
    • 无需关注版本号,自动版本仲裁
      • 引入依赖默认都可以不用写版本号
      • 引入非版本仲裁的jar,要写版本号
    • 可以修改版本号
  • 1.2自动配置
    • 自动配置好tomcat
      • 引入Tmocat依赖(在starter-web场景中已经引入)
      • 配置Tomcat
    • 自动配置好SpringMVC
      • 引入springmvc全套组件
      • 自动装配Springmvc常用组件(功能)
    • 自动配置好Web常见功能,如:字符编码问题
      • springboot帮我们配置好了所有web开发的常见场景
    • 默认的包结构
      • 主程序所在包及其下面的子包里面的组件都会被默认扫描
      • 无需以前的包扫描位置
      • 想要改变扫描路径:@SrpingBootApplication(scanBasePackages=””)或者@ComponentScan指定扫描路径
    • 各种配置拥有默认值
      • 配置文件的值最终会绑定到某个类上,这个类在ioc容器中创建对象
    • 按需加载所有自动配置项(各种starter场景类似子类,spring-boot-starter 类似父类 starter场景子类就好比继承了spring-boot-starter这个父类,当有什么场景引入,相应的自动配置就在spring-boot-starter中的spring-boot-autoconfigure包里面按需加载)
      • 非常多的starter
      • 引入了哪些场景这个场景的自动配置才会开启
      • SpringBoot所有的自动配置功能都在spring-boot-autoconfigure包里面中

底层注解

  • @Configuration:
    • 1.告诉spring boot这时一个配置类==配置文件
    • 2.配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例,默认以方法名作为组件id,返回的类型就是组件类型。返回的值就是组件在容器中的实例
    • 配置类本身也是组件
    • 属性proxyBeanMethods(解决组件依赖,当为false时,spring boot不会检查被@Bean注解所注解的方法返回的bean在容器中有没有,跳过检查,springboot运行起来就比较快。当为true时,当外界每一次对这个方法的调用,都会检查容器中有没有该组件,有就从容器中拿,没有就new一个并放在容器中):
      • (单实例—Full模式)proxyBeanMethods=true:当组件间需要相互依赖,能保证所依赖的组件是容器中的组件
      • (多实例—Lite模式)proxyBeanMethods=false:如果我们给容器只是单单注册组件,组件之间也不依赖
  • @Import
    • @Import支持 三种方式
      • 1.带有@Configuration的配置类(4.2 版本之前只可以导入配置类,4.2版本之后 也可以导入 普通类)
      • 2.ImportSelector 的实现
      • 3.ImportBeanDefinitionRegistrar 的实现
    • 默认id为类的全类名
  • @Conditional
    • 条件装配:满足Conditional指定的条件,则进行组件注入
  • @ImportResource:导入spring配置文件
  • @ConfigurationProperties(prefix=”匹配前缀”)
    • @ConfigurationProperties注解用于自动配置绑定,可以将application.properties配置中的值注入到bean对象上。
    • 该注解使用必须将对象注入到IOC容器中才有配置绑定的功能
    • 该注解可以使用在类上、方法上;会自动进行配置导入
  • @EnableConfigurationProperties({类.class})
    • 在配置类上写可以看到上面的配置绑定需要使用@Component组件注解进行注册才能进行绑定,如果是写好的第三方包呢?那么没有办法给第三方包加入的时候可以使用使用方法标记进行配置绑定或者@EnableConfigurationProperties注解进行自动注册

自动配置原理入门

  • 引导加载自动配置类
    • @SpringBootConfiguration
      • @Configuration :代表当前是一个配置类
    • @ComponentScan:指定扫描哪些包,spring注解
    • @EnableAutoConfiguration
      • @AutoConfigurationPackage(自动配置包)
        • @Import(AutoConfigurationPackages.Register.class):
          • 利用Registrar这个静态内部类中的registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry)方法给容器中导入一系列组件
          • 将指定一个包下的所有组件导入进来:MainApplication所在包下,metadata参数中存有当前类的注解信息,比如当前注解标注在哪个类上,又因为@SpringbootApplication是合成注解,合成@EnableAutoConfiguration,@SpringBootConfiguration,@ComponentScan。@EnableAutoConfiguration又合成了@AutoConfigurationPackage(自动配置包)和@Import(AutoConfigurationImportSelector.class),@AutoConfigurationPackage(自动配置包)又合成了@Import(AutoConfigurationPackages.Register.class)所以这个注解是标在主程序类上的。在Registrar类中的registerBeanDefinitions方法中,new PackageImports(metadata).getPackageNames().toArray(new String[0])),这句话就是拿到注解所在类的包名,把这个包名封装到一个数组里面,然后注册进去
        • @Import(AutoConfigurationImportSelector.class)
          • 由于AutoConfigurationImportSelector实现了DeferredImportSelector接口,DeferredImportSelector又继承了ImportSelector,所以导入容器中的组件是ImportSelector中的selectImports方法返回的数组中存放的类的全类名。selectImports方法中有一个关键,利用getAutoConfigurationEntry(annotationMetadata)给容器中批量导入一些组件。从这个方法我们可以找到最底层的方法SpringFactoriesLoader类中的loadSpringFactories(ClassLoader classLoader)方法。
            • 在方法中Enumeration urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION)-获取FACTORIES_RESOURCE_LOCATION下的 资源文件;其中FACTORIES_RESOURCE_LOCATION=”META-INF/spring.factories”,默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件,核心包spring-boot-autoconfigure里面也有META-INF/spring.factories,在这个文件中写死了springboot一启动就要给容器中加载的所有配置类
  • 按需开启自动配置项
    • 虽然我们127个场景的所有自动配置启动的时候默认全部加载。
    • 按照条件装配配置(@Conditional),最终会按需配置
  • 修改默认配置

总结:

  • SpringBoot先加载所有的自动配置类 XXXXAutoConfiguration
  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的默认值。
  • 生效的配置类就会给容器中装配很多组件
  • 只要容器中有这些组件,相当于组件所对应的功能也有了
  • 定制化组件
    • 用户直接自己@Bean替换底层的组件
    • 用户去看这个组件是获取的配置文件的什么值就去修改
  • XXXXAutoConfiguration — 组件 — xxxProperties里面拿值 — application.properties

最佳实战

  • 引用场景依赖:docs.spring.io/spring-boot…
  • 查看自动配置了哪些(选做)
    • 自己分析,引入场景对应的自动配置类一般都生效了
    • 配置文件中(application.properties)中debug=true开启自动配置报告。Negative(没生效的),Positive(生效)
  • 是否需要修改
    • 参照文档修改配置文件
    • 自定义加入或替换组件
  • Lombok
    • 简化Javabean的开发(@Data,@ToString,@AllArgsConstructor,@NoArgsConstructor)
    • 导入依赖
    • 搜索安装Lombok的插件
    • 简化日志开发

spring boot核心功能

文件类型

  • properties:同以前的properties用法
  • yaml:
    • 简介:YAML是”YAML Ain’t Markup Language”(yaml不是一种标记语言)的递归缩写。在开发的时候这种语言意思其实是:”Yet Another Markup Language”(仍是一种标记语言)–非常适合用来做以数据为中心的配置文件
    • 基本语法:
      • key: value;kv之间有空格
      • 大小写敏感
      • 使用缩进标识层级关系
      • 缩进不允许使用tab,只允许空格(代码规范)
      • 缩进的空格数不重要,只要相同层级的元素左对齐即可
      • #标识注释
      • ”与””表示字符串内容 会被转义/不转义
    • 数据类型
      • 字面量:单个的、不可再分的值。date、boolean、string、number、null
      • 对象:键值对的集合,map,hash,set,object
      • 数组:一次按次序排列的值。

配置提示功能

Web开发

静态资源规则

  • 静态资源访问
    • 静态资源目录
      • 类路径下:/static or /public or /resources or /META-INF/resources
      • 访问:当前项目根路径/+静态资源名
      • 原理:静态资源映射/**
      • 当一个请求进来,先去Controller看能不能处理,因为是/**代表处理所有请求,所以当Controller不能处理的时候,请求都又交给静态资源处理器,静态资源处理器默认就会去类路径下定义好的目录下去找资源。静态资源找不到就会报404
    • 静态资源访问前缀
      • 默认无前缀
      • 定义静态资源访问前缀:
        • 当前项目 + static-paath-pattern + 静态资源名 = 静态资源文件夹下找
    • 欢迎页支持
      • 静态资源路径下放置index.html
        • 可以配置静态资源路径
        • 但是不可以配置静态资源的访问前缀。否则导致index.html不能被默认访问
    • 自定义Favicon
      • 开启静态资源前缀也会导致图片加载不出来
    • 静态资源配置原理
      • SpringBoot启动默认加载 xxxAutoConfiguration类(自动配置类)
      • SpringMVC功能的自动配置类 WebMvcAutoConfiguration
      • 给容器中配了哪些组件
        • 兼容restful风格的
        • 表单内容的过滤器
        • webMvcAutoConfigurationAdapter
            • 配置文件的相关属性和xxx(前缀)进行了绑定 WebMvcProperties—-spring.mvc ResourceProperties—-spring.resources
            • 当配置类只有一个有参构造器时:
              • 有参构造器的所有参数的值都会从容器中确定
              • WebProperties webProperties:获取和spring.web绑定的所有的值的对象
              • WebMvcProperties mvcProperties:获取和spring.mvc绑定的所有的值的对象
              • ListableBeanFactory beanFactory:spring的beanFactory
              • ObjectProvider  messageConvertersProvider:找到所有的HttpMessageConverters
              • ObjectProvider resourceHandlerRegistrationCustomizerProvider: 找到资源处理器的自定义器
              • ObjectProvider  dispatcherServletPath
              • ObjectProvider<ServletRegistrationBean<?>>  servletRegistrations:给应用注册Servlet、Filter…..
      • 资源处理的默认规则
      • 禁用所有静态资源规则
      • 欢迎页的默认配置

请求参数处理

  • 请求映射
    • @XXXMapping;
    • Rest风格(使用HTTP请求方式动词来表示对资源的操作)
      • 以前:/getUser-获取用户 /deleteUser-删除用户 /updateUser-修改用户 /saveUser-保存用户
      • 现在:/user-(GET-获取用户,DELETE-删除用户,PUT-修改用户,POST-保存用户)
      • 核心Filter:HiddenHttpMethodFilter
        • 用法:表单method=post,隐藏域中 name默认为_method,value为put或者delete
        • 默认Rest功能是没有开启的
    • Rest原理
      • 在WebMvcAutoConfiguration这个自动配置类中,已经默认装配好了一个OrderedHiddenHttpMethodFilter,这个类继承了HiddenHttpMethodFilter
      • 在HiddenHttpMethodFilter中有一个doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)方法
          • 当表单提交时会带上_method=put或者delete的参数
          • 当请求过来时会被HiddenHttpMethodFilter过滤器中的doFilterInternal方法拦截
            • 1.首先把请求参数先放在requestToUse临时变量中
            • 2.校验提交的表单是不是POST请求
            • 3.取出this.methodParam这个变量作为key的value, this.methodParam就是”_method”
            • 4.判断这个参数的值是否为空,并统一转为大写,再判断是否包含在被允许的方法中-ALLOWED_METHODS(PUT,DELETE,PATCH),如果包含,那么会通过包装模式requestWrapper重写了getMethod方法,返回的时传入的值, 过滤器链放行的时候用wrapper,以后的方法调用getMethod是调用的包装类的

请求映射原理

  • 继承树图:
  • 找到HttpServlet中的doGet方法发现并没有实现什么,其子类HttpServletBean也没有重写这个方法,再找到子类FrameworkServlet,这个类重写了父类HttpServlet的doGet方法在方法中有一行关键代码processRequest(request, response);在这方法中又有doService(request, response)方法,可以发现在FrameworkServlet中的doService方法并没有实现什么,由此可找到其子类DispatcherServlet,发现这个子类重写了doService
    • 在doService中又有doDispatch这个方法(真正有功能的方法),每个请求最后都会调用这个方法。
  • 在doDispache中会调用getHandler方法找到当前请求使用哪个Handler(Controller方法)处理
  • getHandler方法中的handlerMappings(处理器映射的集合),遍历handlerMappings,其中第一个就是RequestMappingHandlerMapping:保存了所有@RequestMapping和handler的映射规则(RequestMappingHandlerMapping下的mappingRegistry下的registry中可以查看到),
  • 所有的请求映射都在HandlerMapping中。
    • SpringBoot自动配置了欢迎页的WelcomePageHandlerMapping。访问/能访问到index.html
    • SpringBoot自动配置了默认的RequestMappingHandlerMapping
    • 请求进来,挨个尝试所有的HandlerMapping看是否有和这个请求相同的请求信息
      • 如果有就找到这个请求对应的handler
      • 如果没有就看下一个handlerMapping
    • 我们需要一些自定义的映射处理,我们也可以自己给容器中放HandlerMapping。自定义HandlerMapping

视图解析与模板引擎

视图解析:SpringBoot默认不支持JSP,需要引入第三方模板引擎技术实现页面渲染

1.视图解析

2.模板引擎-Thymeleaf

  • 基本语法
  • 3.thymeleaf使用
    • 1.引入starter
    • 2.springboot自动配置好了thymeleaf
      • 自动配好的策略
        • 所有的thymeleaf的配置值都在ThymeleafProperties
        • 配置好了 SpringTemplateEngine
        • 配置好了ThymeleafViewResolver
        • 我们只需直接开发页面(在html标签内加thymeleaf的名称空间)

拦截器

  • 编写一个拦截器实现HandlerInterceptor
  • 拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors方法)
  • 指定拦截规则(如果拦截所有,静态资源也会被拦截)

异常处理

  • 默认规则
    • 默认情况下,springboot提供/error处理所有错误的映射
    • 对于机器客户端(postman)它将响应JSON数据,其中包含错误,HTTP状态和异常消息的详细信息,对于浏览器客户端,响应一个“whitelabel”错误视图,以html格式呈现相同的数据
    • 要对其进行自定义,添加View解析为error
    • 要完全替换默认行为,可以实现ErrorController并注册该类型的bean定义,或添加ErrorAttributes类型的组件以使用现有机制,但替换其内容
  • 定制错误处理逻辑
    • 自定义错误页
      • error/404.html
      • error/5xx.html
    • @ControllerAdvice + @ExceptionHandler处理异常
    • 实现HandlerExceptionResolver处理异常

Web原生组件注入(Servlet,Filter,Listener)

  • 使用Servlet API
    • @ServletComponentScan(basePackages=”包名”)
    • @WebServlet(urlPatterns=””):效果:直接响应,没有经过spring的拦截器
    • @WebFilter(urlPatterns={“”,””})
    • @WebListener
  • 使用RegistrationBean
    • 1.ServletRegistrationBean
    • 2.FilterRegistrationBean
      • 当调用setUrlPatterns时传入的参数是集合类型(可以用Arrays.asList()方法将数组转为集合)
    • 3.ServletListenerRegistrationBean
  • 扩展:DispatcherServlet是如何注册进来的
    • 容器中自动配置了DispatcherServlet属性,绑定到了WebMvcProperties,对应的配置项前缀是 spring.mvc
    • 通过ServletRegistrationBean把DispatcherServlet配置进去
    • 默认的映射规则是/路径
    • Tomcat-Servlet中:当多个Servlet都能处理到同一层路径时,tomcat具有精准优选原则,当请求路径时,即使DispatcherServlet能处理全部请求,但当容器中有其它处理请求路径的Servlet时,此路径会对比DispatcherServlet和其它Servlet,tomcat会选择谁能精确处理这次请求,所以就可能造成,当我们自定义另外的Servlet时,当请求我们自定义的Servlet的路径时,会直接我们这个Servlet,并不会走Spring的DispathcerServlet,更不会被拦截器拦截

定制化原理

  • 1.定制化的常见方式
    • 修改配置文件
    • xxxxCustomizer
    • 编写自己的配置类,xxxConfiguration + @Bean替换,增加容器中默认组件,视图解析器
    • Web应用 编写一个配置类实现WebMvcConfigurer即可定制化web功能 + @Bean给容器中扩展一些组件
    • @EnableWebMvc + 配置类 +实现WebMvcConfigurer + @Bean 可以全面接管SpringMVC,所有的规则自己重新配置;实现定制和扩展功能
      • 原理:
      • 1.WebMvcAutoConfiguration:默认的SpringMVC的自动配置功能类。静态资源,欢迎页….
      • 2.WebMvcAutoConfiguration配置类要能生效必须@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
      • 3.一旦使用了@EnableWebMvc,在这个注解中会@Import(DelegatingWebMvcConfiguration.class)
      • 4.DelegatingWebMvcConfiguration的作用,只保证了SpringMvc最基本的使用
        • DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport
        • 把系统中所有的WebMvcConfigurer拿过来。所有的功能的定制都是这些WebMvcConfigurer合起来一起生效
        • 自动配置了一些非常底层的组件。RequestMappingHandlerMapping,这些组件依赖的组件都是从容器中获取
      • 5.@EnableWebMvc导致了WebMvcAutoConfiguration没有生效
  • 2.原理分析套路
    • 场景starter – XXXXAutoConfiguration -导入组件 – 绑定xxxProperties – 绑定配置文件项

数据访问

  • 1.数据源的自动配置
    • 1.导入jdbc场景
      • 数据库驱动? 为什么导入jdbc场景,官方不导入驱动? 官方不知道我们接下来要操作什么数据库。导入数据库驱动时,注意数据库版本和驱动版本对应
    • 2.分析自动配置
      • 自动配置的类
        • DataSourceAutoConfiguration:数据源的自动配置
          • 修改数据源的相关配置:spring.datasource
          • 数据库连接池的配置,是自己容器中没有Datasource才自动配
          • 底层配置好的连接池是:HikariDataSource
        • DataSourceTransactionManagerAutoConfiguration:事务管理器的自动配置
        • JdbcTemplateAutoConfiguration:jdbctemplate的自动配置,可以来对数据库进行crud
    • 3.修改配置项
  • 2.使用Druid数据源
    • 1.druid官方gitHub地址 github.com/alibaba/dru…
      • 整合第三方技术的两种方式:
        • 自定义
        • 找starter
      • 2.找starter
        • 1.引入druid-starter
        • 2.分析自动配置
          • 扩展配置项 spring.datasource.druid
          • @Import({DruidSpringAopConfiguration.class, DruidStatViewServletConfiguration.class, DruidWebStatFilterConfiguration.class, DruidFilterConfiguration.class})
          • DruidSpringAopConfiguration.class:监控springbean的,配置项:spring.datasource.druid.aop-patterns
          • DruidStatViewServletConfiguration.class:监控页的配置:spring.datasource.druid.stat.view.servlet;默认开启的
          • DruidWebStatFilterConfiguration.class:web监控配置:spring.datasource.druid.web-stat-filter;默认开启的
          • DruidFilterConfiguration.class :所有Druid自己的Filter的配置
        • 3.详细配置信息
        • springboot配置示例:github.com/alibaba/dru…
        • 配置项列表: github.com/alibaba/dru…
  • 3.整合MyBatis操作
    • 官方地址:github.com/mybatis
    • 1.引入starter
    • 2.配置文件模式
      • 导入mybatis官方starter
      • 编写mapper接口。并标注@mapper注解
      • 编写sql映射文件并绑定mapper接口
      • 在application.yaml中指定Mapper配置文件的位置,以及指定全局配置文件的信息(全局可指定可不指定)