Memorykk

never too late to learn

SpringBoot

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。

SpringBoot

创建独立Spring应用

内嵌web服务器

自动starter依赖,简化构建配置

自动配置Spring以及第三方功能

提供生产级别的监控、健康检查及外部化配置

无代码生成、无需编写XML

避免大量的 Maven 导入和各种版本冲突。

@SpringBootApplication

@SpringBootApplication == @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan

主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来

@Configuration

配置类本身也是组件

  • Full模式:配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式;proxyBeanMethods = true
  • Lite模式:配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断;proxyBeanMethods = false

@Bean、@Component、@Controller、@Service、@Repository、@ComponentScan、@Import

@Import:自动以类的NoArgsConstrutor创建实例放入IoC

@Conditional

@ConditionalOnMissingBean(name = “tom”):满足指定条件则进行组件注入。

@ImportResource:引入原生的配置文件,比如beans.xml。

配置绑定

两种方式:

  • @Component @ConfigurationProperties(prefix = “mycar”)声明在要绑定的类的上方
  • @EnableConfigurationProperties(Car.class),开启对应类的配置绑定功能,把Car这个组件自动注入到容器中;

如果@ConfigurationProperties是在第三方包中,那么@component是不能注入到容器的。只有@EnableConfigurationProperties才可以注入到容器。

@ConfigurationProperties(prefix = “mycar”):配置绑定。读取到properties文件中的内容,并且把它封装到JavaBean中。

自动配置原理

@SpringBootApplication == @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan

@SpringBootConfiguration

相当于@Configuration, 两者之间的唯一区别是@SpringBootConfiguration允许自动找到配置。

@EnableAutoConfiguration

@EnableAutoConfiguration == @AutoConfigurationPackage + @Import(AutoConfigurationImportSelector.class)

@AutoConfigurationPackage

使用@import将AutoConfigurationPackages包下的Registrar类作为组件导入到容器中,然后使用Registrar中的方法批量完成组件的注册。

@Import(AutoConfigurationImportSelector.class)

1、利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件 
2、调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
3、利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
4、**从META-INF/spring.factories位置来加载一个文件。** 默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
文件里面写死了spring-boot一启动就要给容器中加载的127个配置类

虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration 按照条件装配规则(@Conditional),最终会按需配置

SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先约定大于配置

@ConditionalOnMissingBean,如果没有存在这个bean,那么springboot就会自动帮你配置

总结

SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration

  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定

  • 生效的配置类就会给容器中装配很多组件

  • 只要容器中有这些组件,相当于这些功能就有了

  • 定制化配置

    • 用户直接自己@Bean替换底层的组件

    • 用户去看这个组件是获取的配置文件什么值就去修改。

      xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 —-> application.properties

静态资源配置原理

SpringBoot启动默认加载 xxxAutoConfiguration 类(自动配置类)
SpringMVC功能的自动配置类 WebMvcAutoConfiguration,生效。

请求 -> Controller -> 静态资源处理器 -> 404

配置文件的相关属性和xxx进行了绑定。WebMvcProperties - spring.mvc、ResourceProperties - spring.resources

REST

  • 表单提交会带上_method=PUT

  • 请求过来被HiddenHttpMethodFilter拦截

    • 请求是否正常,并且是POST

      • 获取到_method的值。

      • 兼容以下请求;PUT.DELETE.PATCH

      • 原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是传入的值。

      • 过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。

请求映射原理

1、处理http,重写servlet、doGet、doPost,实际调用doService

2、所有的请求映射都在HandlerMapping中。RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射规则。

3、请求进来,挨个尝试所有的HandlerMapping看是否有请求信息。

  • 如果有就找到这个请求对应的handler
  • 如果没有就是下一个 HandlerMapping

请求参数注解

@PathVariable、@RequestHeader、@ModelAttribute、@RequestParam、@MatrixVariable、@CookieValue、@RequestBody

参数处理原理

HandlerMapping中找到能处理请求的Handler
为当前Handler 找一个适配器 HandlerAdapter
适配器执行目标方法并确定方法参数的每一个值

参数解析器-HandlerMethodArgumentResolver

SpringMVC目标方法能写多少种参数类型。取决于26个参数解析器。

●当前解析器是否支持解析这种参数
●支持就调用 resolveArgument

返回值处理器

15个遍历

handlerMapping中找到适合的handler(1/4) -> 为Handler找一个HandlerAdapter -> 参数处理(参数解析器)-> 执行目标方法 -> 返回值处理器 -> 处理派发结果(将所有的数据都放在 ModelAndViewContainer;包含要去的页面地址View。还包含Model数据)

POJO封装参数

1、判断参数是不是简单参数

2、创建空的实体类

3、绑定数据

4、类型转换器 -> javaBean

响应JSON

  • 返回值处理器判断是否支持这种类型返回值 supportsReturnType
  • 返回值处理器调用 handleReturnValue 进行处理
  • RequestResponseBodyMethodProcessor 可以处理返回值标了@ResponseBody 注解的。
    • 利用 MessageConverters 进行处理 将数据写为json
      • 1、内容协商(浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型)(Accept字段)
      • 2、服务器最终根据自己自身的能力,决定服务器能生产出什么样内容类型的数据,
      • 3、SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter ,看谁能处理?
        • 1、得到MappingJackson2HttpMessageConverter可以将对象写为json
        • 2、利用MappingJackson2HttpMessageConverter将对象转为json再写出去。

内容协商

根据客户端接收能力不同,返回不同媒体类型的数据。

  • 1、判断当前响应头中是否已经有确定的媒体类型。MediaType

  • 2、获取客户端(PostMan、浏览器)支持接收的内容类型。(获取客户端Accept请求头字段)【application/xml】

contentNegotiationManager 内容协商管理器 默认使用基于请求头的策略

  • 3、遍历循环所有当前系统的 MessageConverter,看谁支持操作这个对象(Person)

  • 4、找到支持操作Person的converter,把converter支持的媒体类型统计出来。

  • 5、客户端需要【application/xml】。服务端能力【10种、json、xml】

  • 6、进行内容协商的最佳匹配媒体类型

  • 7、用 支持 将对象转为 最佳匹配媒体类型 的converter。调用它进行转化 。

视图解析

1、目标方法处理的过程中,所有数据都会被放在 ModelAndViewContainer 里面。包括数据和视图地址
2、方法的参数是一个自定义类型对象(从请求参数中确定的),把他重新放在 ModelAndViewContainer
3、任何目标方法执行完成以后都会返回 ModelAndView(数据和视图地址)。
4、processDispatchResult 处理派发结果(页面改如何响应)

  • 1、render(mv, request, response); 进行页面渲染逻辑
    ○1、根据方法的String返回值得到 View 对象【定义了页面的渲染逻辑】
    • 1、所有的视图解析器尝试是否能根据当前返回值得到View对象
    • 2、得到了 redirect:/main.html –> Thymeleaf new RedirectView()
    • 3、ContentNegotiationViewResolver 里面包含了下面所有的视图解析器,内部还是利用下面所有视图解析器得到视图对象。
    • 4、view.render(mv.getModelInternal(), request, response); 视图对象调用自定义的render进行页面渲染工作
    • RedirectView 如何渲染【重定向到一个页面】
    • 1、获取目标url地址
    • 2、response.sendRedirect(encodedURL);

拦截器

implements HandlerInterceptor,重写preHandle、postHandle、afterCompletion。

1、根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】
2、先来顺序执行 所有拦截器的 preHandle方法

  • 1、如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle
  • 2、如果当前拦截器返回为false。直接倒序执行所有已经执行了的拦截器的 afterCompletion;

3、如果任何一个拦截器返回false。直接跳出不执行目标方法
4、所有拦截器都返回True。执行目标方法
5、倒序执行所有拦截器的postHandle方法
6、前面的步骤有任何异常都会直接倒序触发 afterCompletion
7、页面成功渲染完成以后,也会倒序触发 afterCompletion

image.png

Spring Security 和 Shiro

由于 Spring Boot 官方提供了大量的非常方便的开箱即用的 Starter ,包括 Spring Security 的 Starter ,使得在 Spring Boot 中使用 Spring Security 变得更加容易,甚至只需要添加一个依赖就可以保护所有的接口,所以,如果是 Spring Boot 项目,一般选择 Spring Security 。当然这只是一个建议的组合,单纯从技术上来说,无论怎么组合,都是没有问题的。Shiro 和 Spring Security 相比,主要有如下一些特点:

Spring Security 是一个重量级的安全管理框架;Shiro 则是一个轻量级的安全管理框架
Spring Security 概念复杂,配置繁琐;Shiro 概念简单、配置简单
Spring Security 功能强大;Shiro 功能简单

跨域问题

跨域可以在前端通过 JSONP 来解决,但是 JSONP 只可以发送 GET 请求,无法发送其他类型的请求,在 RESTful 风格的应用中,就显得非常鸡肋,因此我们推荐在后端通过 (CORS,Cross-origin resource sharing) 来解决跨域问题。

在传统的 SSM 框架中,就可以通过 CORS 来解决跨域问题,只不过之前我们是在 XML 文件中配置 CORS ,现在可以通过实现WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。

starter

首先它提供了一个自动化配置类,一般命名为 XXXAutoConfiguration ,在这个配置类中通过条件注解来决定一个配置是否生效(条件注解就是 Spring 中原本就有的),然后它还会提供一系列的默认配置,也允许开发者根据实际情况自定义相关配置,然后通过类型安全的属性注入将这些配置属性注入进来,新注入的属性会代替掉默认属性。正因为如此,很多第三方框架,我们只需要引入依赖就可以直接使用了。当然,开发者也可以自定义 Starter

spring-boot-starter-parent

我们都知道,新创建一个 Spring Boot 项目,默认都是有 parent 的,这个 parent 就是 spring-boot-starter-parent ,spring-boot-starter-parent 主要有如下作用:

定义了 Java 编译版本为 1.8 。
使用 UTF-8 格式编码。
继承自 spring-boot-dependencies,这个里边定义了依赖的版本,也正是因为继承了这个依赖,所以我们在写依赖时才不需要写版本号。
执行打包操作的配置。
自动化的资源过滤。
自动化的插件配置。
针对 application.properties 和 application.yml 的资源过滤,包括通过 profile 定义的不同环境的配置文件,例如 application-dev.properties 和 application-dev.yml。

Spring Boot 打成的 jar 和普通的 ja

Spring Boot 项目最终打包成的 jar 是可执行 jar ,这种 jar 可以直接通过 java -jar xxx.jar 命令来运行,这种 jar 不可以作为普通的 jar 被其他项目依赖,即使依赖了也无法使用其中的类。

Spring Boot 的 jar 无法被其他项目依赖,主要还是他和普通 jar 的结构不同。普通的 jar 包,解压后直接就是包名,包里就是我们的代码,而 Spring Boot 打包成的可执行 jar 解压后,在 \BOOT-INF\classes 目录下才是我们的代码,因此无法被直接引用。如果非要引用,可以在 pom.xml 文件中增加配置,将 Spring Boot 项目打包成两个 jar ,一个可执行,一个可引用。