Springboot学习笔记

Springboot学习笔记

一、知识体系

1. 知识架构

在这里插入图片描述

2. 近期学习内容

在这里插入图片描述

3. 软件开发演变

在这里插入图片描述

二、自动装配

1.pom.xml:有两级父项目spring-boot-starter-parent和spring-boot-dependencies。

(1) 核心依赖在spring-boot-dependencies中。
(2) 我们在写或引入一些springboot依赖的时候,不需要指定版本,就因为有这些版本 仓库。

2. 启动器

(1) 启动器的配置

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

(2) 启动器:就是Springboot的启动环境,比如spring-boot-starter-web启动器,它会自动导入web环境所有的依赖。
(3) Springboot会将所有的功能场景建立一个个启动器。
(4) 如果我们要使用某些功能只要找到对应的启动器即可。

3. 主程序

(1) 代码

package com.sxsl.helloword;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//程序的主入口,不能删和改,@SpringBootApplication表明这是一个Springboot的类
@SpringBootApplication
public class HellowordApplication {
	
	public static void main(String[] args) {
		//静态方法run启动应用,通过反射机制调用
		SpringApplication.run(HellowordApplication.class, args);
	}
}

(2) @SpringBootApplication注解标注这个类是Springboot的一个应用。
(3) 注解

@SpringBootConfiguration //Springboot的配置类,层层包含下面的类
         @Configuration  //spring配置类
                 @Component  //说明这也是spring的一个组件

@EnableAutoConfiguration //自动配置,层层包含下面的类
         @AutoConfigurationPackage  //自动配置包
         		 @Import({Registrar.class})   //导入自动包注册
         @Import({AutoConfigurationImportSelector.class}) //导入自动配置导入选择
                 List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);  //获取所有配置              

(4) 获取候选配置的方法

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> 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;
    }

(5) 调用SpringFactoriesLoader的loadFactoryNames,根据META-INF/spring.factories内容,遍历所有元素。
(6) META-INF/spring.factories. 自动配置的核心文件
在这里插入图片描述

4. 结论

Springboot所有自动配置都是在启动时扫描并加载:所有的自动配置君子META-INF/spring.factories中,但不一定生效,要判断条件是否成立;只要导入了对应的starter(启动器),就有了启动器,有了启动器我们的自动配置就会生效,然后就配置成功。
(1) SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
(2) 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
(3) 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
(4) 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;
(5) 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作。
在这里插入图片描述

三、springboot运行原理

1. SpringApplication的实例化

(1) 推断应用的类型是普通的项目还是Web项目
(2) 查找并加载所有可用初始化器 , 设置到initializers属性中
(3) 找出所有的应用程序监听器,设置到listeners属性中
(4) 推断并设置main方法的定义类,找到运行的主类

2. run方法执行流程

在这里插入图片描述

四、yaml配置注入

1. yaml概述

(1) YAML是 “YAML Ain’t a Markup Language” (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)
(2) 这种语言以数据作为中心,而不是以标记语言为重点!
(3) 语法要求严格:空格不能省略;以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的;属性和值的大小写都是十分敏感的。

2. 语法

2.1字面量:普通的值 [ 数字,布尔值,字符串 ]

(1) 字面量直接写在后面就可以 , 字符串默认不用加上双引号或者单引号。

k: V

(2) 注意:
“ ” 双引号,不会转义字符串里面的特殊字符 , 特殊字符会作为本身想表示的意思;
比如 :name: “kuang \n shen” 输出 :kuang 换行 shen
‘’ 单引号,会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出
比如 :name: ‘kuang \n shen’ 输出 :kuang \n shen

2.2对象、Map(键值对)

(1) 对象、Map格式

k: 
    v1:
    v2:

(2) 在下一行来写对象的属性和值得关系,注意缩进;比如:

student:
    name: qinjiang
    age: 3

(3) 行内写法

student: {name: qinjiang,age: 3}

2.3 数组( List、set )

(1) 用 - 值表示数组中的一个元素,比如:

pets:
 - cat
 - dog
 - pig

(2) 行内写法

pets: [cat,dog,pig]

3. yaml注入配置文件

3.1 在springboot项目中的resources目录下新建一个文件 application.yml

(1) 我们在编写一个复杂一点的实体类:Person 类

@Component //注册bean到容器中
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
    
    //有参无参构造、get、set方法、toString()方法  
}

(2) 我们来使用yaml配置的方式进行注入,大家写的时候注意区别和优势,我们编写一个yaml配置application.yml


person:
  name: qinjiang
  age: 3
  happy: false
  birth: 2000/01/01
  maps: {k1: v1,k2: v2}
  lists:
   - code
   - girl
   - music
  dog:
    name: 旺财
    age: 1

(3) 我们刚才已经把person这个对象的所有值都写好了,我们现在来注入到我们的类中!


/*
@ConfigurationProperties作用:
将配置文件中配置的每一个属性的值,映射到这个组件中;
告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
*/
@Component //注册bean
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
}

在这里插入图片描述

3.2 yaml注入与@Value注入的对比

在这里插入图片描述

4. JSR303介绍和使用

4.1 关于 JSR-303

SR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。

4.2 JSR-303常见参数

@NotNull(message="名字不能为空")
private String userName;
@Max(value=120,message="年龄最大不能查过120")
private int age;
@Email(message="邮箱格式错误")
private String email;

空检查
@Null       验证对象是否为null
@NotNull    验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank   检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty   检查约束元素是否为NULL或者是EMPTY.
    
Booelan检查
@AssertTrue     验证 Boolean 对象是否为 true  
@AssertFalse    验证 Boolean 对象是否为 false  
    
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内  
@Length(min=, max=) string is between min and max included.

日期检查
@Past       验证 Date 和 Calendar 对象是否在当前时间之前  
@Future     验证 Date 和 Calendar 对象是否在当前时间之后  
@Pattern    验证 String 对象是否符合正则表达式的规则

5. 多环境切换

5.1 properties实现方式

(1) 主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml , 用来指定多个环境版本。

application-test.properties 代表测试环境配置

application-dev.properties 代表开发环境配置

(2) 需要通过一个配置来选择需要激活的环境

#比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;
#我们启动SpringBoot,就可以看到已经切换到dev下的配置了;
spring.profiles.active=dev

5.2 yaml实现方式

5.2.1 yaml的多文档块
server:
  port: 8081
#选择要激活那个环境块
spring:
  profiles:
    active: prod

---
server:
  port: 8083
spring:
  profiles: dev #配置环境的名称


---

server:
  port: 8084
spring:
  profiles: prod  #配置环境的名称
5.2.2 配置文件加载位置

springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:

优先级1:项目路径下的config文件夹配置文件 file:./config
优先级2:项目路径下配置文件  file:
优先级3:资源路径下的config文件夹配置文件 classpath:./config 
优先级4:资源路径下配置文件 classpath:
5.2.3 通过spring.config.location来改变默认的配置文件位置

我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;这种情况,一般是后期运维做的多,相同配置,外部指定的配置文件优先级最高

java -jar spring-boot-config.jar --spring.config.location=F:/application.properties

五、自动装配原理

1、原理

(1) springboot启动时会自动加载大量的自动配置类。
(2) 我们首先查看我们需要的功能有没有在Springboot默认写好的自动配置中。
(3) 然后我们再看这个自动配置类中到底配置了哪些组件。
(4) 给容器中自动配置类添加组件时候,会从properties类中获取某些属性,我们只需在配置文件中指定这些属性的值即可。
(5) XXXAutoConfiguration:自动配置类,给容器添加组件;XXXProperties:封装配置文件中的相关属性,我们可以在此扩展一些属性;Springboot的配置文件可以动态修改这些属性。

2. 了解@Conditional

(1) 作用:自动配置类须在一定条件下生效,即必须在@Conditional指定的条件成立时,才向容器添加组件,配置类里面所有的内容才生效。
(2) 常用@Conditional

在这里插入图片描述

3. 启用 debug=true属性,查看自动配置类的生效情况

#开启springboot的调试类
debug=true

Positive matches:(自动配置类启用的:正匹配)
Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)
Unconditional classes: (没有条件的类)

注意:没有生效的自动配置类是没有导入相应的依赖,即对应的XXX-XXX-start。

六、web开发相关

1. 静态资源

1.1 通过webjar的方式引入静态资源

(1) 访问popular webjar网站,里面有大量的最常用的静态资源webjar,以jar包的形式导入静态资源。类如jquery、vue、bootstrap等,都可以找到各种版本的依赖。
以jquery3.5.0为例:在pom文件引入一下依赖:

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

(2) 在html页面中引入的方式为

<script src="webjars/jquery/3.5.0/jquery.js"></script>

(3) 查看一下webjar下的jquery路径:
在这里插入图片描述
(4) 访问jqyery.js
http://localhost:8080/webjars/jquery/3.5.0/jquery.js

1.2 通过springboot默认的静态资源文件夹路径导入

classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public
/ 当前项目的根路径

1.3 静态路径的源码分析

(1) 添加静态资源源码

	@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();
			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));
			}
		}

(2) 图示
在这里插入图片描述
(3) 对应的路

	private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/","classpath:/resources/", "classpath:/static/", "classpath:/public/" };

1.4 静态资源小结

(1) 在Springboot中处理静态资源方式:
webjars,通过localhost:8080/webjars来访问
public、/**、static、resources,通过localhost:8080访问
(2) 优先级:resources>static>public
(3) 一旦自定义静态资源路径后,上述默认路径下的静态资源

	if (!this.resourceProperties.isAddMappings()) {
				logger.debug("Default resource handling disabled");
				return;
			}

2. 首页和图标的定制

(1) 首页源码图示
在这里插入图片描述
(2) 在templates目录下的文件只能通过Controller来访问,相当于WEB-INF目录。

3. thymeleaf

3.1 模板引擎

在这里插入图片描述

3.2 常用标签

在这里插入图片描述

3.3 官方教程

官方教程:http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#what-is-thymeleaf

3.4 基础语法

(1) 创建HTML
由上文也可以知道需要在html中添加:

<html xmlns:th="http://www.thymeleaf.org">

(2) .获取变量值${…}

  <!--/*@thymesVar id="name" type="java.lang.String"*/-->
    <p th:text="'Hello!, ' + ${name} + '!'">3333</p>

(3) 选择变量表达式*{…}

<div th:object="${session.user}">
    <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
    <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p> 
    <p>Nationality: <span th:text={nationality}">Saturn</span>.</p>
</div> 
等价于
<div>
    <p>Name: <span th:text="${session.user.firstName}">Sebastian</span>.</p> 
    <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p> 
    <p>Nationality: <span th:text="${session.user.nationality}">Saturn</span>.</p>
</div>

(4) 链接表达式: @{…}

<!-- Will produce 'http://localhost:8080/gtvg/order/details?orderId=3' (plus rewriting) --> <a href="details.html" th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a> <!-- Will produce '/gtvg/order/details?orderId=3' (plus rewriting) -->

<a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a>

<a href="details.html" th:href="@{order/{orderId}/details(orderId=${o.id})}">Content路径,默认访问static下的order文件夹</a>

(5) 循环 通过th:each

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>hello</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
    <!-- 不存在则忽略,显示hello null!(可以通过默认值进行设置)-->
    <p th:text="'Hello ' + (${name}?:'admin')">3333</p>
    <table>
        <tr>
            <th>ID</th>
            <th>NAME</th>
            <th>AGE</th>
        </tr>
        <tr th:each="emp : ${empList}">
            <td th:text="${emp.id}">1</td>
            <td th:text="${emp.name}">海</td>
            <td th:text="${emp.age}">18</td>
        </tr>
    </table>
</body>
</html>
@GetMapping(value = "/hello")
    public String hello(Model model) {
        List<Emp> empList = new ArrayList<>();
        empList.add(new Emp(1, "校长", 24));
        empList.add(new Emp(2, "书记", 28));
        empList.add(new Emp(3, "小海", 25));
        model.addAttribute("empList", empList);
        return "hello";
    }

HelloController

(6) 条件运算

If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))

webjars
http://localhost:8080/webjars/jquery/3.6.0/jquery.js

package com.sxsl.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.Locale;

//如果想diy一些定制化的功能,只要写这个组件,然后交给Springboot,Springboot就会帮我们自动装载
//扩展springmvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    // public interface ViewResolver 实现视图解析器接口的类,我们就把它看成视图解析器
    @Bean
    public ViewResolver myViewResolver(){
        return new MyViewResolver();
    }

    public static class MyViewResolver implements ViewResolver {
        @Nullable
        @Override
        //自定义了一个自己的视图解析器
        public View resolveViewName(String s, Locale locale) throws Exception {
            return null;
        }
    }
}

4、SpringMVC自动配置

4.1 自动配置原理

4.1.1 Spring Boot对Spring MVC的默认配置
org.springframework.boot.autoconfigurae.web.servlet.WebMvcAutoConfiguration
4.1.2 自动配置在Spring的默认值之上添加了以下功能

(1) 包含ContentNegotiatingViewResolver和BeanNameViewResolver。 ---->视图解析器
(2) 支持服务静态资源,包括对WebJars的支持。 —>静态资源文件夹路径
(3) 自动注册Converter、GenericConverter和FormatterBeans。 —>转换器,格式化器
(4) 支持HttpMessageConverters。 —>SpringMVC用来转换Http请求和响应的;User —Json;
(5) 自动注册MessageCodesResolver。 —>定义错误代码生成规则
(6) 静态index.html支持。 —>静态首页访问
(7) 定制favicon支持。 —>网站图标
(8) 自动使用ConfigurableWebBingdingInitializerbean

4.1.3 扩展Spring Boot MVC

(1) 如果您想保留Spring Boot MVC的功能,并且需要添加其他MVC配置(拦截器,格式化程序和视图控制器等),可以添加自己的WebConfigurer类型的Configuration类,但不能带@EnableWebMvc注解
(2) 如果您想自定义RequestMappingHandlerMapping、RequestMappingHandlerAdapter或者ExceptionHandlerExceptionResolver实例,可以声明一个WebMvcRegistrationsAdapter实例来提供这些组件。

4.1.4 完全掌控Spring MVC

如果您想完全掌控Spring MVC,可以添加自定义注解@EnableWebMvc的@Configuration配置类。

4.1.5 官方文档地址:

https://docs.spring.io/spring-boot/docs/2.2.1.RELEASE/reference/html/spring-boot-features.html#boot-features-spring-mvc-static-content

4.2 视图解析器

(1) 根据方法的返回值得到视图对象(View),视图对象决定如何渲染(转发or重定向),自动配置了ViewResolver
(2) ContentNegotiatingViewResolver:组合所有的视图解析器的;
在这里插入图片描述
(3) 视图解析器来源
在这里插入图片描述
(4) 自己给容器中添加一个视图解析器;自动的将其组合进来

@Component
public class MyViewResolver implements ViewResolver {

    @Override
    public View resolveViewName(String s, Locale locale) throws Exception {
        return null;
    }
}

(5) 设置断点,debug时查看
在这里插入图片描述

4.3 转换器、格式化器

(1) Converter:转换器;public String hello(User user):类型转换使用Converter(表单数据转为user)
(2) Formatter 格式化器; 2020.12.12===Date;自己添加的格式化器转换器,我们只需要放在容器中即可

@Bean
//在配置文件中配置日期格式化的规则
@ConditionalOnProperty(prefix = "spring.mvc", name = "date-format")
public Formatter<Date> dateFormatter() {
    return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化组件
}

4.4 HttpMessageConverters

(1) HttpMessageConverter:SpringMVC用来转换Http请求和响应的;User —Json;
(2) HttpMessageConverters:是从容器中确定;获取所有的HttpMessageConverter;
(3) 自己给容器中添加HttpMessageConverter,只需要将自己的组件注册容器中(@Bean,@Component)

4.5 扩展SpringMVC

4.5.1 扩展步骤

(1) 以前的配置文件中的配置

<mvc:view-controller path="/hello" view-name="success"/>

(2) 现在,编写一个配置类(@Configuration),是WebMvcConfigurer类型;不能标注@EnableWebMvc

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/hi").setViewName("success");
    }
}

(3) 访问:http://localhost:8080/hi

4.5.2 原理

(1) 我们知道WebMVCAutoConfiguration是SpringMVC的自动配置类,下面这个类是WebMVCAutoConfiguration中的一个内部类
在这里插入图片描述
(2) 看一下@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})中的这个类,这个类依旧是WebMvcAutoConfiguration中的一个内部类
在这里插入图片描述
(3) 重点看一下这个类继承的父类DelegatingWebMvcConfiguration

public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

    public DelegatingWebMvcConfiguration() {
    }

    //自动注入,从容器中获取所有的WebMvcConfigurer
    @Autowired(
        required = false
    )
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }

    }

    ......

    /**
     * 查看其中一个方法
      * this.configurers:也是WebMvcConfigurer接口的一个实现类
      * 看一下调用的configureViewResolvers方法 ↓
      */
    protected void configureViewResolvers(ViewResolverRegistry registry) {
        this.configurers.configureViewResolvers(registry);
    }
public void configureViewResolvers(ViewResolverRegistry registry) {
    Iterator var2 = this.delegates.iterator();

    while(var2.hasNext()) {
        WebMvcConfigurer delegate = (WebMvcConfigurer)var2.next();
        //将所有的WebMvcConfigurer相关配置都来一起调用;  
        delegate.configureViewResolvers(registry);
    }

}

(4) 容器中所有的WebMvcConfigurer都会一起起作用;我们的配置类也会被调用;
效果:SpringMVC的自动配置和我们的扩展配置都会起作用;
在这里插入图片描述

4.6 全面接管SpringMVC

4.6.1 步骤

(1) SpringBoot对SpringMVC的自动配置不需要了,所有都是由我们自己来配置;所有的SpringMVC的自动配置都失效了。
(2) 我们只需要在配置类中添加@EnableWebMvc即可

@Configuration
@EnableWebMvc
public class MyMvcConfig implements WebMvcConfigurer

在这里插入图片描述

4.6.2 原理

(1) 为什么@EnableWebMvc自动配置就失效了;我们看一下EnableWebMvc注解类

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}

(2) 重点在于@Import({DelegatingWebMvcConfiguration.class})
DelegatingWebMvcConfiguration是WebMvcConfigurationSupport的子类,我们再来看一下SpringMVC的自动配置类WebMvcAutoConfiguration


@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})

//重点是这个注解,只有当容器中没有这个类型组件的时候该配置类才会生效
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})

@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration 

(3) @EnableWebMvc将WebMvcConfigurationSupport组件导入进来;导入的WebMvcConfigurationSupport只是SpirngMVC最基本的功能。

4.7 如何修改Spring Boot的默认配置

SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来。

七、分布式

1、什么是分布式系统

(1) 在《分布式系统原理与范型》一书中有如下定义:“分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”;
(2) 分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据。
(3) 分布式系统(distributed system)是建立在网络之上的软件系统。
(4) 首先需要明确的是,只有当单个节点的处理能力无法满足日益增长的计算、存储任务的时候,且硬件的提升(加内存、加磁盘、使用更好的CPU)高昂到得不偿失的时候,应用程序也不能进一步优化的时候,我们才需要考虑分布式系统。因为,分布式系统要解决的问题本身就是和单机系统一样的,而由于分布式系统多节点、通过网络通信的拓扑结构,会引入很多单机系统没有的问题,为了解决这些问题又会引入更多的机制、协议,带来更多的问题。。。

2、RPC

(1) RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数
(2) 原理图
在这里插入图片描述

3、Dubbo

(1) Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
(2) dubbo官网 http://dubbo.apache.org/zh-cn/index.html
(3) dubbo图
在这里插入图片描述

4、dubbo基本概念

(1) 服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。
(2) 服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
(3) 注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
(4) 监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
(5) 调用关系说明
l 服务容器负责启动,加载,运行服务提供者。
l 服务提供者在启动时,向注册中心注册自己提供的服务。
l 服务消费者在启动时,向注册中心订阅自己所需的服务。
l 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
l 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
l 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

5、Dubbo环境搭建

5.1 Window下安装zookeeper

(1) 下载zookeeper ,解压zookeeper
(2) 运行/bin/zkServer.cmd ,初次运行会报错,没有zoo.cfg配置文件;
(3) 修改zoo.cfg配置文件

dataDir=./   临时数据存储的目录(可写相对路径)
clientPort=2181   zookeeper的端口号

(4) 使用zkCli.cmd测试

5.2 window下安装dubbo-admin

dubbo本身并不是一个服务软件。它其实就是一个jar包,能够帮你的java程序连接到zookeeper,并利用zookeeper消费、提供服务。
但是为了让用户更好的管理监控众多的dubbo服务,官方提供了一个可视化的监控程序dubbo-admin,不过这个监控即使不装也不影响使用。
(1) 下载dubbo-admin
地址 :https://github.com/apache/dubbo-admin/tree/master
(2) 解压进入目录
修改 dubbo-admin\src\main\resources \application.properties 指定zookeeper地址

server.port=7001
spring.velocity.cache=false
spring.velocity.charset=UTF-8
spring.velocity.layout-url=/templates/default.vm
spring.messages.fallback-to-system-locale=false
spring.messages.basename=i18n/message
spring.root.password=root
spring.guest.password=guest

dubbo.registry.address=zookeeper://127.0.0.1:2181

(3) 在项目目录下打包dubbo-admin

mvn clean package -Dmaven.test.skip=true

(4) 执行 dubbo-admin\target 下的dubbo-admin-0.0.1-SNAPSHOT.jar

java -jar dubbo-admin-0.0.1-SNAPSHOT.jar

(5) 执行完毕,我们去访问一下 http://localhost:7001/ , 这时候我们需要输入登录账户和密码,我们都是默认的root-root

5.3 SpringBoot + Dubbo + zookeeper

5.3.1 大体步骤

(1) 启动zookeeper
(2) IDEA创建一个空项目;
(3) 创建一个模块,实现服务提供者:provider-server , 选择web依赖即可
(4) 项目创建完毕,我们写一个服务,比如卖票的服务;
编写接口

package com.sxsl.service;

public interface TicketService {
   public String getTicket();
}

编写实现类

package com.sxsl.service;

public class TicketServiceImpl implements TicketService {
   @Override
   public String getTicket() {
       return "《狂神说Java》";
  }
}

(5) 创建一个模块,实现服务消费者:consumer-server , 选择web依赖即可
(6) 项目创建完毕,我们写一个服务,比如用户的服务;
编写service

package com.sxsl.service;

public class UserService {
   //我们需要去拿去注册中心的服务
}
5.3.2 服务提供者

(1) 将服务提供者注册到注册中心,我们需要整合Dubbo和zookeeper,所以需要导包
我们从dubbo官网进入github,看下方的帮助文档,找到dubbo-springboot,找到依赖包

<!-- Dubbo Spring Boot Starter -->
<dependency>
   <groupId>org.apache.dubbo</groupId>
   <artifactId>dubbo-spring-boot-starter</artifactId>
   <version>2.7.3</version>
</dependency>    
zookeeper的包我们去maven仓库下载,zkclient;

<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency>
   <groupId>com.github.sgroschupf</groupId>
   <artifactId>zkclient</artifactId>
   <version>0.1</version>
</dependency>
【新版的坑】zookeeper及其依赖包,解决日志冲突,还需要剔除日志依赖;

<!-- 引入zookeeper -->
<dependency>
   <groupId>org.apache.curator</groupId>
   <artifactId>curator-framework</artifactId>
   <version>2.12.0</version>
</dependency>
<dependency>
   <groupId>org.apache.curator</groupId>
   <artifactId>curator-recipes</artifactId>
   <version>2.12.0</version>
</dependency>
<dependency>
   <groupId>org.apache.zookeeper</groupId>
   <artifactId>zookeeper</artifactId>
   <version>3.4.14</version>
   <!--排除这个slf4j-log4j12-->
   <exclusions>
       <exclusion>
           <groupId>org.slf4j</groupId>
           <artifactId>slf4j-log4j12</artifactId>
       </exclusion>
   </exclusions>
</dependency>

(2) 在springboot配置文件中配置dubbo相关属性!

#当前应用名字
dubbo.application.name=provider-server
#注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
#扫描指定包下服务
dubbo.scan.base-packages=com.sxsl.service

(3) 在service的实现类中配置服务注解,发布服务!注意导包问题

package com.sxsl.service;

import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;

@Service //将服务发布出去,dubbo的service
@Component //放在容器中
public class TicketServiceImpl implements TicketService {
    @Override
    public String getTicket() {
        return "《狂神说Java》";
    }
}

逻辑理解 :应用启动起来,dubbo就会扫描指定的包下带有@component注解的服务,将它发布在指定的注册中心中!

5.3.3 服务消费者

(1) 导入依赖,和之前的依赖一样;

<!--dubbo-->
<!-- Dubbo Spring Boot Starter -->
<dependency>
   <groupId>org.apache.dubbo</groupId>
   <artifactId>dubbo-spring-boot-starter</artifactId>
   <version>2.7.3</version>
</dependency>
<!--zookeeper-->
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency>
   <groupId>com.github.sgroschupf</groupId>
   <artifactId>zkclient</artifactId>
   <version>0.1</version>
</dependency>
<!-- 引入zookeeper -->
<dependency>
   <groupId>org.apache.curator</groupId>
   <artifactId>curator-framework</artifactId>
   <version>2.12.0</version>
</dependency>
<dependency>
   <groupId>org.apache.curator</groupId>
   <artifactId>curator-recipes</artifactId>
   <version>2.12.0</version>
</dependency>
<dependency>
   <groupId>org.apache.zookeeper</groupId>
   <artifactId>zookeeper</artifactId>
   <version>3.4.14</version>
   <!--排除这个slf4j-log4j12-->
   <exclusions>
       <exclusion>
           <groupId>org.slf4j</groupId>
           <artifactId>slf4j-log4j12</artifactId>
       </exclusion>
   </exclusions>
</dependency>

(2) 配置参数

#当前应用名字
dubbo.application.name=consumer-server
#注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181

(3) 本来正常步骤是需要将服务提供者的接口打包,然后用pom文件导入,我们这里使用简单的方式,直接将服务的接口拿过来,路径必须保证正确,即和服务提供者相同;
在这里插入图片描述
(4) .完善消费者的服务类

package com.sxsl.service;

import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

@Service //spring的service
public class UserService {

    @Reference //远程引用指定的服务,他会按照全类名进行匹配,看谁给注册中心注册了这个全类名
            TicketService ticketService;

    public void bugTicket(){
        String ticket = ticketService.getTicket();
        System.out.println("在注册中心买到"+ticket);
    }

}

(5) 测试类编写;ConsumerServer5ApplicationTests.java

package com.sxsl;

import com.sxsl.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ConsumerServer5ApplicationTests {
	@Autowired
	UserService userService;

	@Test
	public void contextLoads() {

		userService.bugTicket();

	}
}

5.4 启动测试

(1) 开启zookeeper
(2) 打开dubbo-admin实现监控【可以不用做】
(3) 开启服务者
(4) 消费者消费测试,结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值