diff --git a/dev-protocol-springcloud/SpringCloud项目介绍.md b/dev-protocol-springcloud/SpringCloud项目介绍.md
new file mode 100644
index 0000000..1cf5fc2
--- /dev/null
+++ b/dev-protocol-springcloud/SpringCloud项目介绍.md
@@ -0,0 +1,18 @@
+# 项目大致说明
+
+- 微服务通信 - (RestTemplate/Ribbon/Feign/OpenFeign)
+ - [dev-protocol-springcloud-communication](dev-protocol-springcloud-communication)
+- 微服务网关 - (Gateway)
+ - [dev-protocol-springcloud-gateway](dev-protocol-springcloud-gateway)
+- 分布式链路、日志追踪 - (Sleuth + Zipkin)
+ - todo
+- 微服务容错 - (SpringCloud Netflix Hystrix)
+ - todo
+- 消息驱动微服务 - (SpringCloud Stream)
+ - todo
+- 分布式事务 - (SpringCloud Alibaba Seata)
+ - todo
+- 网关动态限流 - (SpringCloud Alibaba Sentinel)
+ - todo
+- 微服务工程部署与整体可用性验证
+ - todo
\ No newline at end of file
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/pom.xml b/dev-protocol-springcloud/dev-protocol-springcloud-communication/pom.xml
new file mode 100644
index 0000000..240f4af
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/pom.xml
@@ -0,0 +1,55 @@
+
+
+ 4.0.0
+
+ org.example
+ dev-protocol
+ 1.0-SNAPSHOT
+ ../../pom.xml
+
+
+ dev-protocol-springcloud-communication
+
+
+ 8
+ 8
+ UTF-8
+ 0.9.1
+
+
+
+
+ io.github.openfeign
+ feign-micrometer
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+
+
+ org.projectlombok
+ lombok
+
+
+ com.alibaba
+ fastjson
+ 1.2.51
+
+
+ io.jsonwebtoken
+ jjwt
+ ${jjwt.version}
+
+
+
+
\ No newline at end of file
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/OpenFeignDemoApplication.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/OpenFeignDemoApplication.java
new file mode 100644
index 0000000..9843e9c
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/OpenFeignDemoApplication.java
@@ -0,0 +1,17 @@
+package org.example;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+@SpringBootApplication
+@EnableDiscoveryClient // fixme 可以不使用服务发现的方式进行配置, 直接使用 http 的方式进行配置也可
+@EnableFeignClients // 用于扫描包中使用了 @FeignClient 注解的类
+@RefreshScope // 刷新配置
+public class OpenFeignDemoApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(OpenFeignDemoApplication.class, args);
+ }
+}
\ No newline at end of file
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/constant/CommonConstant.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/constant/CommonConstant.java
new file mode 100644
index 0000000..62943fd
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/constant/CommonConstant.java
@@ -0,0 +1,19 @@
+package org.example.common.constant;
+
+/**
+ *
通用模块常量定义
+ * */
+public final class CommonConstant {
+
+ /** RSA 公钥 */
+ public static final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnV+iGlE1e8Z825G+ChIwRJ2H2jOMCBu" +
+ "HV7BPrUE8dAGjqAlRtCaxMyJw7NV9NIUl/rY7RWBUQwelkGmGuQomnUAFIgN9f8UxSC6G935lo1ZoBVJWYmfs5ToXLz+fQugmqHZvF+Vc5l" +
+ "UEo1YapeiaymkOxDORMGjzQBoxoBt316IAwNEPIvcV+F6T+WNFJX/p5Xj48Z1rtmbOQ8ffF+pEWKZGsYg/9b+pKiqFJtuyHqwj/9oxFBE98" +
+ "MCu5RfK6M7Ff9/1dyNen1HKjI7Awj8ZnSceVUldcXEdnP89YagevbhtSl/+CvCsKwHq5+ZLkcuONSxE4dIFWTjxA92wJjYf9wIDAQAB";
+
+ /** JWT 中存储用户信息的 key */
+ public static final String JWT_USER_INFO_KEY = "e-commerce-user";
+
+ /** 授权中心的 service-id */
+ public static final String AUTHORITY_CENTER_SERVICE_ID = "e-commerce-authority-center";
+}
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/package-info.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/package-info.java
new file mode 100644
index 0000000..e306ecb
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/package-info.java
@@ -0,0 +1 @@
+package org.example.common;
\ No newline at end of file
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/util/TokenParseUtil.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/util/TokenParseUtil.java
new file mode 100644
index 0000000..b78ae88
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/util/TokenParseUtil.java
@@ -0,0 +1,63 @@
+package org.example.common.util;
+
+import com.alibaba.fastjson.JSON;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jws;
+import io.jsonwebtoken.Jwts;
+import org.example.common.constant.CommonConstant;
+import org.example.common.vo.LoginUserInfo;
+import sun.misc.BASE64Decoder;
+
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Calendar;
+
+/**
+ * JWT Token 解析工具类
+ * */
+public class TokenParseUtil {
+
+ /**
+ * 从 JWT Token 中解析 LoginUserInfo 对象
+ * */
+ public static LoginUserInfo parseUserInfoFromToken(String token) throws Exception {
+
+ if (null == token) {
+ return null;
+ }
+
+ Jws claimsJws = parseToken(token, getPublicKey());
+ Claims body = claimsJws.getBody();
+
+ // 如果 Token 已经过期了, 返回 null
+ if (body.getExpiration().before(Calendar.getInstance().getTime())) {
+ return null;
+ }
+
+ // 返回 Token 中保存的用户信息
+ return JSON.parseObject(
+ body.get(CommonConstant.JWT_USER_INFO_KEY).toString(),
+ LoginUserInfo.class
+ );
+ }
+
+ /**
+ * 通过公钥去解析 JWT Token
+ * */
+ private static Jws parseToken(String token, PublicKey publicKey) {
+
+ return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
+ }
+
+ /**
+ * 根据本地存储的公钥获取到 PublicKey 对象
+ * */
+ private static PublicKey getPublicKey() throws Exception {
+
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(
+ new BASE64Decoder().decodeBuffer(CommonConstant.PUBLIC_KEY)
+ );
+ return KeyFactory.getInstance("RSA").generatePublic(keySpec);
+ }
+}
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/vo/CommonResponse.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/vo/CommonResponse.java
new file mode 100644
index 0000000..220b0a8
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/vo/CommonResponse.java
@@ -0,0 +1,36 @@
+package org.example.common.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 通用响应对象定义
+ * {
+ * "code": 0,
+ * "message": "",
+ * "data": {}
+ * }
+ * */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CommonResponse implements Serializable {
+
+ /** 错误码 */
+ private Integer code;
+
+ /** 错误消息 */
+ private String message;
+
+ /** 泛型响应数据 */
+ private T Data;
+
+ public CommonResponse(Integer code, String message) {
+
+ this.code = code;
+ this.message = message;
+ }
+}
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/vo/JwtToken.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/vo/JwtToken.java
new file mode 100644
index 0000000..c2515fc
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/vo/JwtToken.java
@@ -0,0 +1,17 @@
+package org.example.common.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 授权中心鉴权之后给客户端的 Token
+ * */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class JwtToken {
+
+ /** JWT */
+ private String token;
+}
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/vo/LoginUserInfo.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/vo/LoginUserInfo.java
new file mode 100644
index 0000000..a6a4d81
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/vo/LoginUserInfo.java
@@ -0,0 +1,20 @@
+package org.example.common.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 登录用户信息
+ * */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class LoginUserInfo {
+
+ /** 用户 id */
+ private Long id;
+
+ /** 用户名 */
+ private String username;
+}
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/vo/UsernameAndPassword.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/vo/UsernameAndPassword.java
new file mode 100644
index 0000000..f057b2d
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/common/vo/UsernameAndPassword.java
@@ -0,0 +1,20 @@
+package org.example.common.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 用户名和密码
+ * */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class UsernameAndPassword {
+
+ /** 用户名 */
+ private String username;
+
+ /** 密码 */
+ private String password;
+}
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/controller/CommunicationController.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/controller/CommunicationController.java
new file mode 100644
index 0000000..91bf95b
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/controller/CommunicationController.java
@@ -0,0 +1,67 @@
+package org.example.controller;
+
+import org.example.common.vo.JwtToken;
+import org.example.common.vo.UsernameAndPassword;
+import org.example.service.UseRestTemplateService;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 微服务通信 Controller
+ * */
+@RestController
+@RequestMapping("/communication")
+public class CommunicationController {
+
+ private final UseRestTemplateService restTemplateService;
+// private final UseRibbonService ribbonService;
+// private final AuthorityFeignClient feignClient;
+// private final UseFeignApi useFeignApi;
+
+ public CommunicationController(UseRestTemplateService restTemplateService
+// UseRibbonService ribbonService,
+// AuthorityFeignClient feignClient,
+// UseFeignApi useFeignApi
+ ) {
+ this.restTemplateService = restTemplateService;
+// this.ribbonService = ribbonService;
+// this.feignClient = feignClient;
+// this.useFeignApi = useFeignApi;
+ }
+
+ @PostMapping("/rest-template")
+ public JwtToken getTokenFromAuthorityService(
+ @RequestBody UsernameAndPassword usernameAndPassword) {
+ return restTemplateService.getTokenFromAuthorityService(usernameAndPassword);
+ }
+
+ @PostMapping("/rest-template-load-balancer")
+ public JwtToken getTokenFromAuthorityServiceWithLoadBalancer(
+ @RequestBody UsernameAndPassword usernameAndPassword) {
+ return restTemplateService.getTokenFromAuthorityServiceWithLoadBalancer(
+ usernameAndPassword);
+ }
+
+ /* @PostMapping("/ribbon")
+ public JwtToken getTokenFromAuthorityServiceByRibbon(
+ @RequestBody UsernameAndPassword usernameAndPassword) {
+ return ribbonService.getTokenFromAuthorityServiceByRibbon(usernameAndPassword);
+ }
+
+ @PostMapping("/thinking-in-ribbon")
+ public JwtToken thinkingInRibbon(@RequestBody UsernameAndPassword usernameAndPassword) {
+ return ribbonService.thinkingInRibbon(usernameAndPassword);
+ }
+
+ @PostMapping("/token-by-feign")
+ public JwtToken getTokenByFeign(@RequestBody UsernameAndPassword usernameAndPassword) {
+ return feignClient.getTokenByFeign(usernameAndPassword);
+ }
+
+ @PostMapping("/thinking-in-feign")
+ public JwtToken thinkingInFeign(@RequestBody UsernameAndPassword usernameAndPassword) {
+ return useFeignApi.thinkingInFeign(usernameAndPassword);
+ }*/
+}
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/feign/EchoService.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/feign/EchoService.java
new file mode 100644
index 0000000..48169c8
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/feign/EchoService.java
@@ -0,0 +1,17 @@
+package org.example.feign;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+
+/**
+ * 基于注解的方式进行实现
+ */
+@Component
+@FeignClient(name = "nacos-provider", configuration = MyFeignConfiguration.class) // name 对应的是服务注册中心的服务名称
+public interface EchoService {
+
+ @GetMapping(value = "/echo/{string}")
+ String echo(@PathVariable String string);
+}
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/feign/EchoServiceManually.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/feign/EchoServiceManually.java
new file mode 100644
index 0000000..c1aaf76
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/feign/EchoServiceManually.java
@@ -0,0 +1,13 @@
+package org.example.feign;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+
+/**
+ * 不基于注解的方式进行装配需要的接口类
+ */
+public interface EchoServiceManually {
+
+ @GetMapping(value = "/echo/{string}")
+ public String echo(@PathVariable String string);
+}
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/feign/FeignClientsConfig.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/feign/FeignClientsConfig.java
new file mode 100644
index 0000000..de000b6
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/feign/FeignClientsConfig.java
@@ -0,0 +1,38 @@
+package org.example.feign;
+
+
+import feign.Client;
+import feign.Contract;
+import feign.Feign;
+import feign.codec.Decoder;
+import feign.codec.Encoder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.openfeign.FeignClientsConfiguration;
+import org.springframework.context.annotation.Import;
+
+@Import(FeignClientsConfiguration.class)
+public class FeignClientsConfig {
+
+ @Autowired
+ private Client client;
+ @Autowired
+ private Encoder encoder;
+ @Autowired
+ private Decoder decoder;
+ @Autowired
+ private Contract contract;
+
+ public EchoServiceManually buidService(){
+ EchoServiceManually serviceManually = Feign.builder()
+ .client(client)
+ .encoder(encoder)
+ .decoder(decoder)
+ .contract(contract)
+ // url : ip+port 不可以, 使用服务名称
+// .target(EchoServiceManually.class, "http://192.168.10.227:8081");
+ .target(EchoServiceManually.class, "http://nacos-provider");
+ return serviceManually;
+ }
+
+
+}
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/feign/MyFeignConfiguration.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/feign/MyFeignConfiguration.java
new file mode 100644
index 0000000..7884ee3
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/feign/MyFeignConfiguration.java
@@ -0,0 +1,4 @@
+package org.example.feign;
+
+public class MyFeignConfiguration {
+}
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/service/UseRestTemplateService.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/service/UseRestTemplateService.java
new file mode 100644
index 0000000..6a4b9b7
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/java/org/example/service/UseRestTemplateService.java
@@ -0,0 +1,80 @@
+package org.example.service;
+
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.example.common.constant.CommonConstant;
+import org.example.common.vo.JwtToken;
+import org.example.common.vo.UsernameAndPassword;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * 使用 RestTemplate 实现微服务通信
+ * */
+@Slf4j
+@Service
+public class UseRestTemplateService {
+
+ private final LoadBalancerClient loadBalancerClient;
+
+ public UseRestTemplateService(LoadBalancerClient loadBalancerClient) {
+ this.loadBalancerClient = loadBalancerClient;
+ }
+
+ /**
+ * 从授权服务中获取 JwtToken
+ * */
+ public JwtToken getTokenFromAuthorityService(UsernameAndPassword usernameAndPassword) {
+
+ // 第一种方式: 写死 url
+ String requestUrl = "http://127.0.0.1:7000/ecommerce-authority-center" +
+ "/authority/token";
+ log.info("RestTemplate request url and body: [{}], [{}]",
+ requestUrl, JSON.toJSONString(usernameAndPassword));
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_JSON);
+ return new RestTemplate().postForObject(
+ requestUrl,
+ new HttpEntity<>(JSON.toJSONString(usernameAndPassword), headers),
+ JwtToken.class
+ );
+ }
+
+ /**
+ * 从授权服务中获取 JwtToken, 且带有负载均衡
+ * */
+ public JwtToken getTokenFromAuthorityServiceWithLoadBalancer(
+ UsernameAndPassword usernameAndPassword
+ ) {
+
+ // 第二种方式: 通过注册中心拿到服务的信息(是所有的实例), 再去发起调用
+ ServiceInstance serviceInstance = loadBalancerClient.choose(
+ CommonConstant.AUTHORITY_CENTER_SERVICE_ID
+ );
+ log.info("Nacos Client Info: [{}], [{}], [{}]",
+ serviceInstance.getServiceId(), serviceInstance.getInstanceId(),
+ JSON.toJSONString(serviceInstance.getMetadata()));
+
+ String requestUrl = String.format(
+ "http://%s:%s/ecommerce-authority-center/authority/token",
+ serviceInstance.getHost(),
+ serviceInstance.getPort()
+ );
+ log.info("login request url and body: [{}], [{}]", requestUrl,
+ JSON.toJSONString(usernameAndPassword));
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_JSON);
+ return new RestTemplate().postForObject(
+ requestUrl,
+ new HttpEntity<>(JSON.toJSONString(usernameAndPassword), headers),
+ JwtToken.class
+ );
+ }
+}
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/resources/http/communication.http b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/resources/http/communication.http
new file mode 100644
index 0000000..3501e51
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/main/resources/http/communication.http
@@ -0,0 +1,37 @@
+### 获取 Token
+POST http://127.0.0.1:8000/ecommerce-nacos-client/communication/rest-template
+Content-Type: application/json
+
+{
+ "username": "123@126.com",
+ "password": "25d55ad283aa400af464c76d713c07ad"
+}
+
+
+### 获取 Token, 带有负载均衡
+POST http://127.0.0.1:8000/ecommerce-nacos-client/communication/rest-template-load-balancer
+Content-Type: application/json
+
+{
+ "username": "123@126.com",
+ "password": "25d55ad283aa400af464c76d713c07ad"
+}
+
+### 通过 OpenFeign 获取 Token
+POST http://127.0.0.1:8000/ecommerce-nacos-client/communication/token-by-feign
+Content-Type: application/json
+
+{
+ "username": "123@126.com",
+ "password": "25d55ad283aa400af464c76d713c07ad"
+}
+
+
+### 通过原生 Feign Api 获取 Token
+POST http://127.0.0.1:8000/ecommerce-nacos-client/communication/thinking-in-feign
+Content-Type: application/json
+
+{
+ "username": "123@126.com",
+ "password": "25d55ad283aa400af464c76d713c07ad"
+}
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/test/java/org/example/EchoServiceManuallyTest.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/test/java/org/example/EchoServiceManuallyTest.java
new file mode 100644
index 0000000..6c96572
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/test/java/org/example/EchoServiceManuallyTest.java
@@ -0,0 +1,21 @@
+package org.example;
+
+import lombok.extern.slf4j.Slf4j;
+import org.example.feign.EchoService;
+import org.junit.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import javax.annotation.Resource;
+
+@Slf4j
+@SpringBootTest
+class EchoServiceManuallyTest {
+
+ @Resource
+ private EchoService echoService;
+
+ @Test
+ public void testOpenFeignInit(){
+ log.info("echoService = {}", echoService);
+ }
+}
\ No newline at end of file
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/test/java/org/example/FeignClientsConfigTest.java b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/test/java/org/example/FeignClientsConfigTest.java
new file mode 100644
index 0000000..39df804
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/src/test/java/org/example/FeignClientsConfigTest.java
@@ -0,0 +1,50 @@
+package org.example;
+
+import lombok.extern.slf4j.Slf4j;
+import org.example.feign.EchoServiceManually;
+import org.example.feign.FeignClientsConfig;
+import org.junit.Test;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+@Slf4j
+@SpringBootTest
+class FeignClientsConfigTest implements ApplicationContextAware, InitializingBean {
+ private EchoServiceManually echoServiceManually;
+ private ApplicationContext applicationContext;
+
+
+ /**
+ * 1
+ * @param applicationContext the ApplicationContext object to be used by this object
+ */
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ this.applicationContext = applicationContext;
+ }
+
+ /**
+ * 2
+ */
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+ context.setParent(applicationContext);
+ // 注册类
+ context.register(FeignClientsConfig.class);
+ context.refresh();
+ // 获取 EchoServiceManually
+ FeignClientsConfig bean = context.getBean(FeignClientsConfig.class);
+ this.echoServiceManually = bean.buidService();
+ }
+
+ @Test
+ public void testEchoService(){
+ String echo = this.echoServiceManually.echo("TestAppManually");
+ log.info("result = {}", echo);
+ }
+}
\ No newline at end of file
diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-communication/微服务通信方案.md b/dev-protocol-springcloud/dev-protocol-springcloud-communication/微服务通信方案.md
new file mode 100644
index 0000000..6b89acb
--- /dev/null
+++ b/dev-protocol-springcloud/dev-protocol-springcloud-communication/微服务通信方案.md
@@ -0,0 +1,82 @@
+# 微服务通信方案
+
+## 1. 微服务通信方案解读
+
+- 早期-第一种方案: 微服务通信方案: RPC
+- RPC 实现微服务通信的核心思想
+ - 全局注册表: 将 RPC 支持的所有方法都注册进去
+ - 通过将 java 对象进行编码(IDL, json, xml 等) + 方法名传递(TCP/IP 协议)到目标服务器实现微服务通信
+---
+- RPC 的优缺点
+ - 目前市面上最流行的 RPC 框架有:gRPC、Thrift、Dubbo, 有较多的选择性
+ - 速度快、并发性能高 - (使用TCP作为传输协议)
+ - 实现复杂(相对 Rest 而言), 需要做的工作与维护上更多(例如:Server 的地址一般存储于 Zookeeper 上, 就需要引入和维护 ZK)
+ - Tip: 优缺点是相对的, 不需要拘泥于理论
+---
+- 第二种方案: 微服务通信方案: HTTP(Rest)
+ - 标准化的 HTTP 协议(GET、POST、PUT、DELETE 等), 前主流的微服务框架通信实现都是 HTTP
+ - 简单、标准,需要做的工作和维护工作少;几乎不需要做额外的工作即可与其他的微服务集成
+---
+- 第三种方案: 微服务通信方案: Message
+ - 通过 Kafka、RocketMQ 等消息队列实现消息的发布与订阅(消费)
+ - 可以实现"削峰填谷",缓冲机制实现数据、任务处理
+ - 最大的缺点是只能够做到最终一致性,而不能做到实时一致性;当然,这也是看业务需求
+---
+- 微服务通信该做何选择
+ - 结合微服务框架与业务的需要做出选择
+ - SpringCloud 建议的通信方案是 OpenFeign(Rest)
+ - 需要最终一致性且不要求快速响应的业务场景可以选择使用 Message(异步处理对系统性能有很大的提升)
+ - 问题来了: SpringCloud 可不可以使用 RPC 呢?(但是,要有足够强的理由说明你为什么要使用 RPC)
+---
+
+## 2. 使用 RestTemplate 实现微服务通信
+
+- 使用 RestTemplate 的两种方式(思想)
+ - 在代码(或配置文件中)写死IP 和 端口号(需要知道,这并不是不可行!)
+ - 通过注册中心(推荐Nacos)获取服务地址,可以实现负载均衡的效果
+---
+
+
+
+
+
+
+
+
+
+
+
+## OpenFeign 核心源码解析
+
+
+
+## OpenFeign 应用技巧
+
+- 认识 FeignClientsConfiguration
+ - 修改 Feign 的默认配置
+ - 自定义 @FeignClient configuration
+
+
+## OpenFeign 二次改造
+
+- 认识 MicrometerCapability
+ - 基于 Capability 的扩展机制
+
+## OpenFeign 造轮子
+
+- 手动创建 FeignClient
+
+## OpenFeign 面试题深度解析
+
+- Feign 和 OpenFeign 的区别
+
+- OpenFeign 的运行原理
+
+- FeignClient 配置方式
+
+
+
+
+
+
+
diff --git a/middleware/dubbo/dubbo.md b/middleware/dubbo/dubbo.md
new file mode 100644
index 0000000..e69de29
diff --git a/pom.xml b/pom.xml
index 2c54495..79ddae3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,6 +50,7 @@
best-practice/css-webflux/reative-spring-css
spring/spring-security/spring-security-demo
dev-protocol-springcloud/dev-protocol-springcloud-gateway
+ dev-protocol-springcloud/dev-protocol-springcloud-communication