欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

123. 【深度解析SpringBoot源码B】

最编程 2024-08-14 21:35:11
...

SpringBoot-核心功能

  • (三)、SpringBoot核心功能
    • 1.配置文件
      • 1.1、properties
      • 1.2、yaml
        • (1).yaml 简介
        • (2).yaml 基本语法
        • (3).数据类型
        • (4).示列
      • 1.3、配置提示
    • 2.WEB 开发
      • 1.SpringMVC自动配置概览
      • 2.简单功能分析
        • (1).静态资源访问
          • (1.1).静态资源目录
          • (1.2).修改静态资源访问前缀
          • (1.3).修改静态资源默认指定目录
          • (1.4).支持webjars
        • (2).欢迎页支持
        • (3).静态资源配置原理 ⭐
          • (1.1)、配置类只有一个有参构造器
          • (1.2)、资源处理的默认规则
          • (1.3)、静态页的欢迎规则
      • 3.请求参数处理
        • (1).请求映射
          • (1.1)、rest使用与原理
          • (1.2)、修改默认的_method更改为自定义的参数
          • (1.3)、请求映射原理
        • (2).普通参数与基本注解
          • (1.1)、注解:
          • (1.2)、Servlet API
          • (1.5)、自定义对象参数
        • (3).POJO封装过程
          • (1.4)、复杂参数
        • (4).参数处理原理
          • (1.1)、HandlerAdapter
          • (1.2)、执行目标方法
          • (1.3)、参数解析器-`HandlerMethodArgumentResolver`
          • (1.4)、返回值处理器
        • (5).如何确定目标方法每一个参数的值
          • (1.1)、挨个判断所有参数解析器那个支持解析这个参数
          • (1.2)、解析这个参数的值
          • (1.3)、自定义类型参数 封装POJO
        • (6).目标方法执行完成
        • (7).处理派发结果

(三)、SpringBoot核心功能

CTRL+H 打开的是 继承树

CTRL+F12 打开的是 方法结构

在这里插入图片描述

1.配置文件

1.1、properties

同以前的properties用法

1.2、yaml

(1).yaml 简介

YAML 是 “YAML Ain’t Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。

非常适合用来做以数据为中心的配置文件

(2).yaml 基本语法
  • key: value;kv之间有空格
  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • '#'表示注释
  • 字符串无需加引号,如果要加,''与""表示字符串内容 会被 转义/不转义 (单引号会转义特殊字符、双引号不会转义特殊字符。比如 \n ,单引号输出的是\n,双引号会换行)。 这里的转义是: 会不会修改原本的功能,转义就是把原有的功能给转义掉。
(3).数据类型
  • 字面量:单个的、不可再分的值。date、boolean、string、number、null
k: v
  • 对象:键值对的集合。map、hash、set、object

行内写法的时候k1与 : 与 v1 都要有间隔,否则会默认讲k1:v1当作键

行内写法:  k: {k1 : v1,k2 : v2,k3 : v3}
#或
k: 
	k1: v1
  k2: v2
  k3: v3
  • 数组:一组按次序排列的值。array、list、queue
行内写法:  k: [v1,v2,v3]
#或者
k:
 - v1
 - v2
 - v3

假如一个文件中存在 application.yaml和application.properties那么两者都会生效的。

(4).示列

1.宠物类

package com.jsxs.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author Jsxs
 * @Date 2023/7/2 9:06
 * @PackageName:com.jsxs.bean
 * @ClassName: Pet
 * @Description: TODO
 * @Version 1.0
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Pet {
    private String name;
    private Double weight;
}

2.Person类: 匹配绑定并放入IOC容器中

package com.jsxs.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Author Jsxs
 * @Date 2023/7/2 9:05
 * @PackageName:com.jsxs.bean
 * @ClassName: Person
 * @Description: TODO
 * @Version 1.0
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component  // 声明这是IOC容器中的一个组件
@ConfigurationProperties(prefix = "person")  // 指定组件配置文件的前缀
public class Person {
    private String userName;
    private Boolean boss;
    private Date birth;
    private Integer age;
    private Pet pet;
    private String[] interests;
    private List<String> animal;
    private Map<String, Object> score;
    private Set<Double> salarys;
    private Map<String, List<Pet>> allPets;
}

3.application.yaml 配置文件

这里在行内写 k:v 的时候,一定要用空格间隔分来。 k 是橙色

person:
  userName : jsxs
  boss : true
  birth : 2023/07/02 09:27:26
  age : 18
  pet :
    name : 哈吉米
    weight : 18.5
  interests : [swiming,basck]
  animal : [cat,dog]
  score : {math : 131,english : 140}
  salarys : [3999,4999.98,5999.99]
  allPets :
     jsxs : [{name : tom,weight : 15.3}]

4.测试

package com.jsxs.controller;

import com.jsxs.bean.Person;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;

/**
 * @Author Jsxs
 * @Date 2023/7/2 9:37
 * @PackageName:com.jsxs.controller
 * @ClassName: IndexController
 * @Description: TODO
 * @Version 1.0
 */
@Controller
@ResponseBody
public class IndexController {

    @Resource
    Person person;

    @GetMapping("/person")
    public Person index(){
        return person;
    }
}

在这里插入图片描述

1.3、配置提示

自定义的类和配置文件绑定一般没有提示。

加入下面的依赖和配置之后,我们配置自定义的类时会有提示。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

 <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-configuration-processor</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

2.WEB 开发

DispathServletSpringMvc

1. 先获得 url 请求的路径 ()
2. 获得 url 的那种解析器(5)
3. 获得方法体参数的类型和个数
4. 遍历获得的参数 获得方法体参数的具体解析器 (27)
5. 通过解析器开始解析方法体参数。
6. 再判断参数体中是否由注解,后面会给我们创建一个实列对象
7. 最后给我们创建的空实列对象进行赋值

在这里插入图片描述
SpringBoot官方 web开发文档

1.SpringMVC自动配置概览

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.(大多场景我们都无需自定义配置)
The auto-configuration adds the following features on top of Spring’s defaults:

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
    • 内容协商视图解析器和BeanName视图解析器
  • Support for serving static resources, including support for WebJars (covered later in this document)).
    • 静态资源(包括webjars)
  • Automatic registration of Converter, GenericConverter, and Formatter beans.
    • 自动注册 ConverterGenericConverterFormatter
  • Support for HttpMessageConverters (covered later in this document).
    • 支持 HttpMessageConverters (后来我们配合内容协商理解原理)
  • Automatic registration of MessageCodesResolver (covered later in this document).
    • 自动注册 MessageCodesResolver国际化用)
  • Static index.html support.
    • 静态index.html 页支持
  • Custom Favicon support (covered later in this document).
    • 自定义 Favicon
  • Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).
    • 自动使用 ==ConfigurableWebBindingInitializer ==,(DataBinder负责将请求数据绑定到JavaBean上)

If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.
不用@EnableWebMvc注解。使用 @Configuration + WebMvcConfigurer 自定义规则

If you want to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, and still keep the Spring Boot MVC customizations, you can declare a bean of type WebMvcRegistrations and use it to provide custom instances of those components.
声明 WebMvcRegistrations 改变默认底层组件

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc, or alternatively add your own @Configuration-annotated DelegatingWebMvcConfiguration as described in the Javadoc of @EnableWebMvc.
使用 @EnableWebMvc+@Configuration+DelegatingWebMvcConfiguration 全面接管SpringMVC

2.简单功能分析

(1).静态资源访问
(1.1).静态资源目录

1.静态页面路径和静态资源不冲突

只要静态资源放在类路径classpath下: called /static (or /public or /resources or /META-INF/resources

访问 : 当前项目根路径/ + 静态资源名

在这里插入图片描述

  1. 静态页面与静态资源冲突 (同名)

原理: 静态映射/**。 (即 localhost:8080/**)

网址请求进来,先去找Controller看能不能处理不能处理的所有请求又都交给静态资源处理器静态资源也找不到则响应404页面

控制层存在一个 /1.jpg的页面跳转,static下面存在着一张图片叫做 1.jpg

package com.jsxs.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @Author Jsxs
 * @Date 2023/7/2 10:54
 * @PackageName:com.jsxs.controller
 * @ClassName: HelloController
 * @Description: TODO
 * @Version 1.0
 */
@Controller
@ResponseBody
public class HelloController {

    @GetMapping("/1.jpg")
    public String hello(){
        return "aaa";
    }
}

在这里插入图片描述
1.静态资源默认访问的位置是 /** 即(localhost:8080/**)

spring:
  mvc:
    static-path-pattern: /**
(1.2).修改静态资源访问前缀

1.正常业务的开发中,我们需要对静态元加上前缀(主要目的是为了实现静态资源的拦截,这个前缀通常为控制层类的前缀)

spring:
  mvc:
    static-path-pattern: /res/**

http://localhost:8080/res/2.jpg

在这里插入图片描述

(1.3).修改静态资源默认指定目录

静态资源存放的默认路径有四个,实际开发中我们可能需要自定义指定我们的静态资源访问路径放哪里。

spring:
  mvc:
    static-path-pattern: /res/**
  web:
    resources:
    # 这里的路径我们可以指定一个或多个,多个用[ ]括起来。
      static-locations: classpath:/haha

查看static-locations的源码发现是一个数组
在这里插入图片描述

http://localhost:8080/res/2.jpg

在这里插入图片描述
把静态资源放在指定的目录下,才会被查找的到。
在这里插入图片描述

(1.4).支持webjars

通俗的讲就是讲 css js 等一些资源封装成了 Maven或者jar包

自动映射: webjars/**

webjars官网: https://www.webjars.org/

在这里插入图片描述

        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.5.1</version>
        </dependency>

访问地址:http://localhost:8080/webjars/jquery/3.5.1/jquery.js 后面地址要按照依赖里面的包路径

在这里插入图片描述

(2).欢迎页支持

Spring Boot supports both static and templated welcome pages. It first looks for an index.html file in the configured static content locations. If one is not found, it then looks for an index template. If either is found, it is automatically used as the welcome page of the application.

支持两种: 第一种(任意)静态资源目录目录下放index.html 第二种Controller下进行处理请求。

    1. 静态资源路径下 index.html
    • 可以配置静态资源路径
    • 但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默认访问
spring:
#  mvc:
#    static-path-pattern: /res/**
  web:
    resources:
      static-locations: classpath:/haha

在这里插入图片描述

    1. controller能处理/index
(3).静态资源配置原理 ⭐
  • SpringBoot启动默认加载 xxxAutoConfiguration 类(自动配置类)
  • SpringMVC功能的自动配置类 WebMvcAutoConfiguration,生效
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {}
  • 给容器中配了什么。
	@Configuration(proxyBeanMethods = false)
	@Import(EnableWebMvcConfiguration.class)
	@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
	@Order(0)
	public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {}
  • 配置文件的相关属性和xxx进行了绑定。
    • WebMvcProperties==spring.mvc、
    • ResourceProperties==spring.web.resources
(1.1)、配置类只有一个有参构造器
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnEnabledResourceChain
    static class ResourceChainCustomizerConfiguration {
        ResourceChainCustomizerConfiguration() {
        }

        @Bean
        WebMvcAutoConfiguration.ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer(ResourceProperties resourceProperties, WebProperties webProperties) {
            return new WebMvcAutoConfiguration.ResourceChainResourceHandlerRegistrationCustomizer((Resources)(resourceProperties.hasBeenCustomized() ? resourceProperties : webProperties.getResources()));
        }
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @EnableConfigurationProperties({WebProperties.class})
    public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
        private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
        private final Resources resourceProperties;
        private final WebMvcProperties mvcProperties;
        private final WebProperties webProperties;
        private final ListableBeanFactory beanFactory;
        private final WebMvcRegistrations mvcRegistrations;
        private final WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
        private ResourceLoader resourceLoader;
        
	//有参构造器所有参数的值都会从容器中确定 ⭐⭐⭐
//ResourceProperties resourceProperties;获取和spring.resources绑定的所有的值的对象
//WebMvcProperties mvcProperties 获取和spring.mvc绑定的所有的值的对象
//ListableBeanFactory beanFactory Spring的beanFactory ⭐ (容器)
//HttpMessageConverters 找到所有的HttpMessageConverters
//ResourceHandlerRegistrationCustomizer 找到 资源处理器的自定义器。=========
//DispatcherServletPath  
//ServletRegistrationBean   给应用注册Servlet、Filter....
        public EnableWebMvcConfiguration(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, WebProperties webProperties, ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ListableBeanFactory beanFactory) {
            this.resourceProperties = (Resources)(resourceProperties.hasBeenCustomized() ? resourceProperties : webProperties.getResources());
            this.mvcProperties = mvcProperties;
            this.webProperties = webProperties;
            this.mvcRegistrations = (WebMvcRegistrations)mvcRegistrationsProvider.getIfUnique();
            this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
            this.beanFactory = beanFactory;
        }
(1.2)、资源处理的默认规则
因为这里分析得到: 假如resourceProperties.isAddMappings()false下面的业务逻辑都不生效,也就是说默认配置的路径都不会生效。
@Override
		public void addResourceHandlers(ResourceHandlerRegistry registry) {
		// 静态资源是否全部生效if (!this.resourceProperties.isAddMappings()) {
				logger.debug("Default resource handling disabled");
				return;
			}
			Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
			CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
			//webjars的规则
            if (!registry.hasMappingForPattern("/webjars/**")) {
				customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
						.addResourceLocations("classpath:/META-INF/resources/webjars/")
						.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
			}
            
            //
			String staticPathPattern = this.mvcProperties.getStaticPathPattern();
			if (!registry.hasMappingForPattern(staticPathPattern)) {
				customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
						.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
			}
		}