This commit is contained in:
法然
2022-10-14 23:43:36 +08:00
parent efab00b2b8
commit bdf0a51b39
27 changed files with 725 additions and 7 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -1,3 +1,5 @@
> 后续需要整理一下每一部分涉及到的注解。
## 1 概述
> 参考教程
> [尚硅谷Spring5课程]()

View File

@@ -0,0 +1,98 @@
## 框架新功能
1. 基于java8兼容jdk9
> 本质上Spring容器的管理有三种主要的方式
> * xml配置方式能够通过xml声明bean并且注入bean的属性
> * 注解方式,通过@Bean@Component创建bean通过@Autowire注入bean
> * 函数方式同构register函数讲普通的java对象注册为bean通过context.getBean获取
### 日志功能
自带了通用的日志封装。可以整合第三方日志工具log4j&slf4j
![](image/2022-10-12-11-30-24.png)
1. slf4j是中间层
2. log4j是日志引擎实现了slf4j提供的接口。可以配合使用
```xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appenders>
<console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p %c{2} - %m%n%throwable" charset="UTF-8"/>
</console>
</appenders>
<loggers>
<root level="info">
<append-ref ref="Console"/>
</root>
</loggers>
</configuration>
```
### @Nullable
* 在属性上,属性值可以为空
* 在方法上,返回值可以为空
* 在参数中,方法参数可以为空
### 支持函数式风格
* GenericApplicationContext能将普通的Java对象注册为Bean对象
* context.getBean("com.ykl.entity.Account",Account.class);能够根据类型进行对象的装载获取
* Account account2 = context.getBean("user1",Account.class);能够根据id进行对象的装载获取。
```
//函数式风格创建对象,交给对象进行管理
@Test
public void testGe(){
GenericApplicationContext context = new GenericApplicationContext();
context.refresh();
context.registerBean("user1",Account.class,()->new Account());
//根据类型获取bean跟@Autowire一样都是根据类型手动装载
Account account = context.getBean("com.ykl.entity.Account",Account.class);
System.out.println(account);
//根据名称获取bean(跟@Qualified一样根据对象的id进行装配)
Account account2 = context.getBean("user1",Account.class);
System.out.println(account);
}
```
## 支持JUnit5
### 支持JUnit4
1. 引入Spring中针对测试的相关依赖。Spring-test
2. 编写测试代码添加Test支持加载context
```
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:bean01.xml")
public class JTest4 {
@Autowired
private AccountService accountService;
@Test
public void test01(){
accountService.pay();
}
}
```
### 支持Junit5的Jar包
1. 引入junit5的jar包
2. 使用新的测试注解进行测试@Extended(SpringExtended.class)
3. 使用复合注解替代两个注解@SpringJunitContext()

View File

@@ -0,0 +1,501 @@
# WebFlux
> 这一块了解就行,不用掌握。
## 1 WebFlux简介
> 第一轮:就是看视频教程学会所有技术的原理和基本使用方法
> 第二轮阅读官方的文档尤其是Spring、Java、Maven等掌握编程的细节。
### 简介
Spring5添加的新模块。用于web开发的功能与SpringMVC类似。Webflux使用与当前比较流行的响应式编程出现的框架。
传统的Web框架比如SpringMVC基于Servlet容器Webflux是一种异步非阻塞的框架。异步非阻塞的框架在Servlet3.1后才支持)
其和虚拟式基于Reactor的相关API实现的。
### 异步非阻塞
* **异步和同步是针对调用者**,调用者发送请求,如果等着对方回应之后采取做其他事情就是同步,如果发送后不等着对方回应就去做其他事情就是异步。
* **阻塞和非阻塞针对被调用者**,被调用者收到一个请求之后,做完嘞请求任务之后,次啊给出返回,就阻塞,收到请求之后马上给出反馈然后再去做事情就是非阻塞。
### 与SpringMVC对比
![](image/2022-10-12-19-28-38.png)
* 异步非阻塞,在有限的资源下,能够处理更多的请求,提高系统地吞吐量。
* 函数式编程。Java最基本的编程模式。能够使用Java函数式编程的特点。
* 两个框架都可以使用注解方式运行都可以运行在Tomcat等Servlet容器中。但SpringMVC采用命令式编程WebFlux使用响应式编程。
### 使用场景:网关
* 需要处理大量的请求。所有客户调用网关,网关负责调用其他的组件。可以使用异步的方式。
## 2 网络技术栈
> [参考文档](http://c.biancheng.net/servlet2/container.html)
![](image/2022-10-12-19-01-07.png)
### web服务器
部署动态网站一般需要 Web 服务器的支持,例如:
* 运行 PHP 网站一般选择 Apache 或者 Nginx
* 运行 ASP/ASP.NET 网站一般选择 IIS
* 运行 Python 网站一般选择内置的 WSGI 服务器模块——wsgiref。
Web 服务器是一种对外提供 Web 服务的软件,它可以接收浏览器的 HTTP 请求,并将处理结果返回给浏览器。
在部署 Servlet 网站时,同样需要一种类似的软件,例如 Tomcat、Jboss、Jetty、WebLogic 等但是它们通常被称为“容器”而不是“服务器”这究竟是为什么呢Servlet 容器和传统意义上的服务器有什么不同呢?
我们通常所说的 Web 服务器,比如 Apache、Nginx、IIS 等,它们的功能往往都比较单一,只能提供 http(s) 服务让用户访问静态资源HTML 文档、图片、CSS 文件、JavaScript 文件等),它们不能执行任何编程语言,也不能访问数据库,更不能让用户注册和登录。
也就是说,如果只有 Web 服务器那您只能部署静态网站不能部署动态网站。要想部署动态网站必须要有编程语言运行环境运行时Runtime的和数据库管理系统的支持。
部署动态网站一般至少需要三个组件,分别是 Web 服务器、脚本语言运行时和数据库,例如,部署 PHP 网站一般选择「Apache + PHP 运行时 + MySQL」的组合。
![](image/2022-10-12-19-07-25.png)
### Web容器
> 简单来说Web容器就是让java能够像脚本语言一样响应用户请求的工具。
Servlet 是基于 Java 语言的,运行 Servlet 必然少不了 JRE 的支持,它负责解析和执行字节码文件(.class文件。然而 JRE 只包含了 Java 虚拟机JVM、Java 核心类库和一些辅助性性文件,它并不支持 Servlet 规范。要想运行 Servlet 代码,还需要一种额外的部件,该部件必须支持 Servlet 规范,实现了 Servlet 接口和一些基础类,这种部件就是 Servlet 容器。
Servlet 容器就是 Servlet 代码的运行环境(运行时),它除了实现 Servlet 规范定义的各种接口和类,为 Servlet 的运行提供底层支持,还需要管理由用户编写的 Servlet 类,比如实例化类(创建对象)、调用方法、销毁类等。
Servlet 中的容器和生活中的容器是类似的概念生活中容器用来装水、装粮食Servlet 中的容器用来装类,装对象。
读者可能会提出疑问,我们自己编写的 Servlet 类为什么需要 Servlet 容器来管理呢?这是因为我们编写的 Servlet 类没有 main() 函数,不能独立运行,只能作为一个模块被载入到 Servlet 容器,然后由 Servlet 容器来实例化,并调用其中的方法。
一个动态页面对应一个 Servlet 类,开发一个动态页面就是编写一个 Servlet 类当用户请求到达时Servlet 容器会根据配置文件web.xml来决定调用哪个类。
![](image/2022-10-12-19-11-25.png)
1. 您看Web 服务器是整个动态网站的“大门”,用户的 HTTP 请求首先到达 Web 服务器Web 服务器判断该请求是静态资源还是动态资源:如果是静态资源就直接返回,此时相当于用户下载了一个服务器上的文件;如果是动态资源将无法处理,必须将该请求转发给 Servlet 容器。
2. Servlet 容器接收到请求以后会根据配置文件web.xml找到对应的 Servlet 类将它加载并实例化然后调用其中的方法来处理用户请求处理结束后Servlet 容器将处理结果再转交给 Web 服务器,由 Web 服务器将处理结果进行封装,以 HTTP 响应的形式发送给最终的用户。
常用的 Web 容器有 Tomcat、Jboss、Jetty、WebLogic 等,其中 Tomcat 由 Java 官方提供,是初学者最常使用的。
为了简化部署流程Web 容器往往也会自带 Web 服务器模块,提供基本的 HTTP 服务,所以您可以不用再安装 Apache、IIS、Nginx 等传统意义上的服务器,只需要安装一款 Web 容器,就能部署 Servlet 网站了。正是由于这个原因,有的教材将 Tomcat 称为 Web 容器,有的教材又将 Tomcat 称为 Web 服务器,两者的概念已经非常模糊了。
将 Web 容器当做服务器使用后,上面的流程图就变成了下面的样子:
![](image/2022-10-12-19-13-49.png)
> 注意Servlet 容器自带的 Web 服务器模块虽然没有传统的 Web 服务器强大,但是也足以应付大部分开发场景,对初学者来说是足够的。当然,您也可以将传统的 Web 服务器和 Servlet 容器组合起来,两者分工协作,各司其职,共同完成 HTTP 请求。
总结,Servlet 容器就是 Servlet 程序的运行环境,它主要包含以下几个功能:
* 实现 Servlet 规范定义的各种接口和类,为 Servlet 的运行提供底层支持;
* 管理用户编写的 Servlet 类,以及实例化以后的对象;
* 提供 HTTP 服务,相当于一个简化的服务器。
容器提供什么
* 通讯支持利用容器提供的方法可以轻松的让servlet与web服务器对话无需自己建立ServerSocket、监听端口、创建流等。容器知道自己与Web服务器之间的协议。
* 生命周期的管理控制着Servlet的生与死。
* 多线程支持容器会自动的为其接收的每个Servlet请求创建一个新的Java线程。
* 声明方式实现安全利用容器可以使用XML部署描述文件来配置和修改安全性而不必将其硬编码写入到Servlet(或其他)类代码中。
* JSP支持将JSP翻译成Java。
## 3 响应式编程
### 响应式编程定义
响应式编程是一种面向数据流和变化产波的编程范式。
意味着可以在编程语言很方便地表达静态或者动态的数据流,
![](image/2022-10-12-19-35-03.png)
一个响应式编程的典型例子。D1=B1+C1。当B1的值修改后D1的值也会修改。B1的数据变化流向了D1。
### Java8响应式编程
是要使用观察者模式实现了响应式编程。使用响应式编程Observer,Observable实现。
```java
/**
* Alipay.com Inc.
* Copyright (c) 2004-2022 All Rights Reserved.
*/
package com.ykl.shangguigu08.reactor;
import java.util.Observable;
/**
* @author yinkanglong
* @version : ObserverDemo, v 0.1 2022-10-12 19:47 yinkanglong Exp $
*/
public class ObserverDemo extends Observable {
/**
* 通过Java8中的类实现响应式编程。
* 简单来说,就是观察值模式。
* @param args
*/
public static void main(String[] args) {
ObserverDemo observerDemo = new ObserverDemo();
observerDemo.addObserver((o,arg)->{
System.out.println("发生变化");
});
observerDemo.addObserver((o,arg)->{
System.out.println("准备改变");
});
observerDemo.setChanged();
observerDemo.notifyObservers();
}
}
```
### java9响应式编程
主要通过Flow类的sub和sub订阅消息实现响应式编程。
> 感觉这个响应式编程和awt控件的点击相应式操作很相似。但是不是启动新的线程。
```
```
### 响应式编程Reator实现
* 响应式编程操作Reactor是满足Reactive规范框架
* Reactor有两个核心类Mono和Flux这两个类实现接口Publisher提供丰富操作符号Flux对象实现发布返回N个元素。Mono实现发布者返回0或者1个元素。
* Flux和Mono都是数据流的发布者。能够发出三种信号
* 元素值
* 完成信号。一种终止信号。订阅者数据流已经结束了。
* 错误信号。一种终止信号。终止数据流并把错误信息传递给订阅者。
![](image/2022-10-13-10-22-26.png)
三种信号的特点
* 错误信号和完成信号都是终止信号不能共存。
* 如果没有发送任何元素值,而是直接发送错误或者完成信号,表示空数据流
* 如果没有错误信号,没有完成信号,表示无限数据流。
### 实例Flux&Mono
引入相关的依赖
```
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.1.5.RELEASE</version>
</dependency>
```
进行发布者发布内容
```java
package com.ykl.shangguigu08.reactor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* @author yinkanglong
* @version : TestReactor, v 0.1 2022-10-13 10:25 yinkanglong Exp $
*/
public class TestReactor {
public static void main(String[] args) {
//reactor中的核心语法
Flux.just(1,2,3,4);
Mono.just(1);
//其他方法
Integer[] array = {1,2,3,4};
Flux.fromArray(array);
List<Integer> list = Arrays.asList(array);
Flux.fromIterable(list);
Stream<Integer> stream = list.stream();
Flux.fromStream(stream);
}
}
```
* just等发布方法只是声明了数据流。只有声明了订阅者才会触发数据流不订阅就不会触发。
```
Flux.just(1,2,3,4).subscribe(System.out::print);
Mono.just(1).subscribe(System.out::print);
```
### 操作符
对数据流进行一道道操作,成为操作符,比如工厂流水线。
* 操作符map。将元素映射为新的元素。
* 操作符flatmap。元素映射为流。
![](image/2022-10-13-10-38-26.png)
![](image/2022-10-13-10-41-45.png)
## 4 WebFlux执行流程和核心API
### Netty的基本原理
SpringWebflux基于Reactor默认使用容器NettyNetty是高性能的NIO框架异步非阻塞框架。
1. BIO阻塞
![](image/2022-10-13-11-44-28.png)
2. NIO非阻塞
![](image/2022-10-13-11-44-49.png)
### SpringWebFlux
* SpringWebflux核心控制器DispatchHandler实现接口WebHandler
![](image/2022-10-13-11-48-44.png)
### 关键类
DispatcherHandler负责请求处理。有三个核心类。
![](image/2022-10-13-11-51-20.png)
* HandlerMappingreactor反应器请求查询到处理方法。
* HandlerAdapter真正负责请求处理processor部分
* HandlerResultHandler对结果进行处理
### 函数式编程实现
两个核心接口。
* RouterFunction 路由处理
* HandlerFunction处理函数
## 5 WebFlux基于注解的编程的实现
### 创建WebFlux项目
1. 创建Springboot项目引入webflux的依赖
```xml
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>shangguigu09</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>shangguigu09</name>
<description>shangguigu09</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
```
2. 在配置文件中设置启动端口号8081
```yaml
server.port =8081
```
3. 从上到下设计代码:创建接口和实现类
```java
@Service
public class UserServiceImpl implements UserService {
private final Map<Integer,User> users = new HashMap<>();
public UserServiceImpl() {
this.users.put(1,new User("lucy","nan",10));
this.users.put(2,new User("mary","nv",38));
this.users.put(3,new User("jack","nv",32));
}
@Override
public Mono<User> getUserById(int id) {
return Mono.justOrEmpty(this.users.get(id));
}
@Override
public Flux<User> getAllUser() {
return Flux.fromIterable(this.users.values());
}
@Override
public Mono<Void> savaUserInfo(Mono<User> userMono) {
return userMono.doOnNext(person->{
int id = users.size() + 1;
users.put(id,person);
}).thenEmpty(Mono.empty());
}
}
```
4. 从下到上实现代码:实现业务逻辑
```java
@RestController
public class UserController {
@Autowired
private UserService userService;
//id
@GetMapping("/user/{id}")
public Mono<User> getUserById(@PathVariable int id){
return userService.getUserById(id);
}
//all
@GetMapping("/user")
public Flux<User> getAllUser(){
return userService.getAllUser();
}
//tianjian
@GetMapping("/saveuser")
public Mono<Void> saveUser(@RequestBody User user){
Mono<User> userMono = Mono.just(user);
return userService.savaUserInfo(userMono);
}
}
```
### 实现说明
* SpringMVC范式同步阻塞方式基于SpringMVC+Servlet+Tomcat
* SpringWebflux方式异步非阻塞方式基于SpringMVCWebflux+Reactor+Netty
## 6 WebFlux基于函数的编程的实现
### 简要说明
> bio,nio,aio
在使用函数式编程,需要自己初始化服务器
基于函数式编程模型的时候,有两个核心接口。
* RouterFunction 实现路由功能请求转发给对应的handler
* HandlerFunction 处理请求生成响应函数。
核心任务定义两个函数式接口的实现,并启动需要的服务器。
SpringWebFlux的请求和响应是
* ServerRequest
* ServerResponse
### 实现流程
1. 从上到下实现业务bean
2. 创建handler实现Mono方法
```java
public class UserHandler {
private final UserService userService;
public UserHandler(UserService userService){
this.userService = userService;
}
//根据id
public Mono<ServerResponse> getUserById(ServerRequest request){
//获取id值
int userid = Integer.valueOf( request.pathVariable("id"));
Mono<ServerResponse> notFound = ServerResponse.notFound().build();
//调用service方法取得数据
Mono<User> userMono = this.userService.getUserById(userid);
//UserMono进行转换返回。Reactor操作符
return userMono.flatMap(person->ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
.body(fromObject(person)))
.switchIfEmpty(notFound);
}
//所有用户
public Mono<ServerResponse> getAllUsers(){
Flux<User> users = this.userService.getAllUser();
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(users,User.class);
}
//添加
public Mono<ServerResponse> saveUser(ServerRequest request){
Mono<User> userMono = request.bodyToMono(User.class);
return ServerResponse.ok().build(this.userService.savaUserInfo(userMono));
}
}
```
3. 创建并初始化服务器设置路由和handler
```java
public class Server {
//创建路由
public RouterFunction<ServerResponse> route(){
UserService userService = new UserServiceImpl();
UserHandler handler = new UserHandler(userService);
return RouterFunctions.route(GET("/users/{id}").and(accept(MediaType.APPLICATION_JSON)),handler::getUserById);
// .andRoute(GET("users").and(accept(MediaType.APPLICATION_JSON)),handler::getAllUsers)
// .andRoute(GET("saveuser").and(accept(MediaType.APPLICATION_JSON)),handler::saveUser);
}
public void createReactorServer(){
RouterFunction<ServerResponse> route = route();
HttpHandler httpHandler = toHttpHandler(route);
ReactorHttpHandlerAdapter reactorHttpHandlerAdapter = new ReactorHttpHandlerAdapter(httpHandler);
HttpServer httpServer = HttpServer.create();
httpServer.handle(reactorHttpHandlerAdapter).bindNow();
}
public static void main(String[] args) throws Exception{
Server server = new Server();
server.createReactorServer();
System.out.println("enter to exit");
System.in.read();
}
}
```
### WebClient调用
```java
public class Client {
public static void main(String[] args) {
WebClient webClient = WebClient.create("http://127.0.0.1:62418");
User userMono = webClient.get().uri("/users/{id}", "1").accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class).block();
System.out.println(userMono.getName());
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 KiB

39
Spring/Spring5/总结.md Normal file
View File

@@ -0,0 +1,39 @@
```plantuml
@startmindmap
* Spring
** Srping框架概述
** IOC容器
*** IOC底层原理
*** IOC接口
*** IOC操作Bean基于XML
**** bean
**** properties
*** IOC操作Bean基于注解
**** @Server
** AOP
*** AOP底层代理JDK动态代理CGLib动态代理
*** 切入点、增强、切面
*** AspectJ实现AOp
** JDBCTemplate
*** 实现对数据库的CURD
*** 实现对数据库的批量操作
** 事务操作
*** 什么是事务
*** 重要概念
**** 传播行为
**** 隔离级别
*** 基于注解
*** 基于完全注解方式
** Spring框架新功能
*** 整合日志框架
*** @Nullable注解
*** 函数式注册对象
*** 整合JUnit5单元测试框架
*** SpringWebflux
@endmindmap
```

View File

@@ -1,4 +1,4 @@
* [shouce]http://shouce.jb51.net/docker_practice/
* [栾一峰](http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html)
* [菜鸟教程](https://www.runoob.com/docker/ubuntu-docker-install.html)
* [参考文献](http://c.biancheng.net/view/3118.html)

View File

@@ -25,6 +25,10 @@ vethc-pair技术充当桥梁。
![](image/2022-10-10-22-33-15.png)
> docker 本身提供了两种网络联通的方法。
> * 一种是NAT端口多路复用端口映射通过-p/P参数docker网络通过映射到宿主机网络的某个端口使得宿主机外部的机器能够通过宿主机ip访问到docker中的服务。
> * 另一种是Brige桥接模式将两个
### 容器网络
所有容器在不指定网络的情况下使用docker0的地址做路由。
@@ -35,6 +39,7 @@ docker中的所有网络接口都是虚拟的转发效率很高。
![](image/2022-10-11-00-06-31.png)
![](image/2022-10-12-09-49-41.png)
## 2 补充知识
### --link名称解析
@@ -90,8 +95,46 @@ docker run -d -P --name tomcat01 --net mynet tomcat
能够将容器加入到网络中
docker network connnet mynet tomcat01
```
* 查看docker网络
```
➜ notes git:(master) ✗ docker network inspect mynet
[
{
"Name": "mynet",
"Id": "343a1bc0691ca6598e028c517613aba3317ee3267f5febd68f88f9d50f5f98c2",
"Created": "2022-10-11T14:41:58.831548151Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.0.0/16",
"Gateway": "192.168.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
```
* docker network create --driver bridge实际上是创建了一个桥接网络也是创建了一个虚拟网桥。这个网桥负责连接宿主机和这容器网络。
* 容器网络:所有容器组成网络的方式
* 桥接网络:容器网络的一种格式。这个网络内的容器通过桥接模式连接到宿主机
* 虚拟网桥:桥接网络中的概念,用来连接两个网络。
* 虚拟网卡veth pair桥接网络中的概念一对虚拟网卡设备连接到虚拟网桥。
## 4 实战Redis集群

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

12
test.log Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,10 +1,21 @@
## actor
https://zhuanlan.zhihu.com/p/372277468
## 演进过程
1. 如果要让服务器服务多个客户端,那么最直接的方式就是为每一条连接创建线程。
2. 创建一个「线程池」,将连接分配给线程,然后一个线程可以处理多个连接的业务。
3. 就是将 socket 改成非阻塞,然后线程不断地轮询调用 read 操作来判断是否有数据,这种方式虽然该能够解决阻塞的问题,但是解决的方式比较粗暴,因为轮询是要消耗 CPU 的,而且随着一个 线程处理的连接越多,轮询的效率就会越低
4. I/O 多路复用。I/O 多路复用技术会用一个系统调用函数来监听我们所有关心的连接,也就说可以在一个监控线程里面监控很多的连接
3. 这样又引来一个新的问题单个线程怎样才能高效地处理多个连接的业务当一个连接对应一个线程时线程一般采用「read -> 业务处理 -> send」的处理流程如果当前连接没有数据可读那么线程会阻塞在 read 操作上( socket 默认情况是阻塞 I/O不过这种阻塞方式并不影响其他线程
4. 就是将 socket 改成非阻塞,然后线程不断地轮询调用 read 操作来判断是否有数据,这种方式虽然该能够解决阻塞的问题,但是解决的方式比较粗暴,因为轮询是要消耗 CPU 的,而且随着一个 线程处理的连接越多,轮询的效率就会越低
5. I/O 多路复用。I/O 多路复用技术会用一个系统调用函数来监听我们所有关心的连接,也就说可以在一个监控线程里面监控很多的连接。
6. 我们熟悉的 select/poll/epoll 就是内核提供给用户态的多路复用系统调用,线程可以通过一个系统调用函数从内核中获取多个事件。
7. 在获取事件时,先把我们要关心的连接传给内核,再由内核检测:
1. 如果没有事件发生,线程只需阻塞在这个系统调用,而无需像前面的线程池方案那样轮训调用 read 操作来判断是否有数据。
2. 如果有事件发生,内核会返回产生了事件的连接,线程就会从阻塞状态返回,然后在用户态中再处理这些连接对应的业务即可。
8. 当下开源软件能做到网络高性能的原因就是 I/O 多路复用吗?
1. 是的,基本是基于 I/O 多路复用,用过 I/O 多路复用接口写网络程序的同学,肯定知道是面向过程的方式写代码的,这样的开发的效率不高。
2. 于是,大佬们基于面向对象的思想,对 I/O 多路复用作了一层封装,让使用者不用考虑底层网络 API 的细节,只需要关注应用代码的编写。
3. 大佬们还为这种模式取了个让人第一时间难以理解的名字Reactor 模式。
9. 反应指的是「对事件反应」也就是来了一个事件Reactor 就有相对应的反应/响应。事实上Reactor 模式也叫 Dispatcher 模式,我觉得这个名字更贴合该模式的含义,即 I/O 多路复用监听事件收到事件后根据事件类型分配Dispatch给某个进程 / 线程。
### 原理
@@ -15,8 +26,6 @@ select/poll/epoll 是如何获取网络事件的呢?在获取事件时,先
## 1 Reactor设计模式
>
Reactor 模式也叫 Dispatcher 模式,即 I/O 多路复用监听事件收到事件后根据事件类型分配Dispatch给某个进程 / 线程。

View File

@@ -1,8 +1,12 @@
# 设计模式之美
> 我发下所有的代码层面、软件层面、系统层面、多个系统组成的微服务层面... ...这些不同粒度的实体,都遵循相同的设计模式。太美了,后续重新学习一下各个模式(看个视频数遍复习笔记)
> 参考文献
> * [https://www.cnblogs.com/gaochundong/tag/Design%20Pattern/](https://www.cnblogs.com/gaochundong/tag/Design%20Pattern/)
> 目录
> 1. 设计模式分类
> 2. 设计模式之间的关系

View File

@@ -1,9 +1,19 @@
# 观察者模式
**别名**
- Dependency
- Publish-Subscribe
> 观察者模式好牛啊,在不同的代码层次有这不同的名称但是大同小异。
> * 在java代码层就是观察着模式
> * 在socket网络编程、IO编程中netty、springWebFlux、sofarpc就是Reactor模式
> * 在操作系统中就是IO多路复用的一种策略
> * 在UI框架中就是Listener事件监听机制和响应机制
> * 在web网站开发中被称为响应式编程。
> * 在微服务中就是注册中心的发布订阅过程
> * 在消息中间件中就是发布订阅模式。
> *
**意图**
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。