〇、SpringCloud
0.区别于单体项目和soa架构,微服务架构每个服务独立,灵活。
1. spring cloud是一个完整的微服务框架,springCloud包括三个体系:
spring cloud Netflix
spring cloud Alibaba
spring 其他
2.spring cloud 版本命名
早期以伦敦地铁名命名,后来采用年份命名。
3.spring cloud 涵盖有非常多的子框架,每个框架有属于自己的版本。学习阶段需要先了解每一个子框架的用法。每个spring cloud框架 对应的spring boot版本也不一样
这里采用H版本
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.12.RELEASE</version></parent><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Hoxton.SR12</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>
一、Eureka
1.Eureka 分为 Eureka service服务器 和 Eureka client客户端
所有客户端都在 服务器中注册自己:
将自己的客户端主机名和ip端口号储存在服务器中,这个存储过程也可以使用redis完成。如果给客户端搭建集群,主机名一样。
当客户端需要远程调用其他客户端时,通过告知服务器客户端主机名获取多个ip及端口号
这时客户端拿到了一系列的ip及端口号。可以使用Ribbon计算出这次远程调用哪一个客户端。
2.搭建Eureka service服务器 配置文件
<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency></dependencies>
server:port: 8761 eureka:client:# 因为当前项目为服务,不需要向服务注册自己,默认为trueregister-with-eureka: false# 因为当前为非集群版eureka,所以不需要同步其他节点数据fetch-registry: false
3.搭建Eureka client服务器 配置文件
<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>
server:port: 9999 # 配置服务注册的名称 spring:application:name: application-client #配置EureKaServer的地址 默认为 http://localhost:8761/eureka/ #eureka: # client: # service-url: # defaultZone: http://localhost:8761/eureka/
4.访问Eureka
①开启service项目;
② 客户端编写三个启动类,每次启动时更改端口号;主机名application-client
③访问Eureka服务器
二、Ribbon
Ribbon是负责负载均衡的springCloud Netflix 子框架。
在访问Eureka 拿到访问地址后,本客户端调用Ribbon通过算法计算出一个访问地址。
核心接口为 LoadBalancerClient
1.这里启动两个 主机名为application-service 的客户端。
2.用一个application-client的客户端通过Eureka拿到application-service主机地址
3.多次访问localhost:9999/demo
可以看到默认的负载均衡策略为轮循。
三、远程调用 RestTemplate类
0)RestTemplate是spring用于发送http请求的模板类。这里配置该对象:
@LoadBalanced 注解用于开启Robbin负载均衡策略。
RandomRule对象是负载均衡的算法,随机选择调用地址。
1)创建springboot的父项目 、公共项目
新建子项目commen
commen依赖:
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version> <!-- 请使用最新的版本号 --><scope>provided</scope>
</dependency>
2)服务器
服务器正常写增删改查的项目,这里测试就直接返回对应数据方便观察接口调用
@RestController
public class MyController {
// @Value("${server.port}")private int port = 8080;/*** 返回类型为集合,泛型为自定类型。*/@RequestMapping("/returnUsers")public List<User> returnUsers(int nums){List<User> result = new ArrayList<>();for(int i = 0; i < nums; i++){result.add(new User(100 + i, "姓名-" + i, 20+i));}return result;}/*** 任意请求方式, 返回值类型是集合。相对复杂的Java类型。* @return*/@RequestMapping("/returnList")public List<String> returnList(int nums){List<String> result = new ArrayList<>();for(int i = 0; i < nums; i++){result.add("返回结果 - " + i);}return result;}/*** 任意请求,传递路径地址参数* @param name* @param age* @return*/@RequestMapping("/restfulParams/{name}/{age}")public String restfulParams(@PathVariable("name") String name,@PathVariable int age){System.out.println("端口号: " + port + ", 任意请求方式,restful参数, name = " +name + " ; age = " + age);return "restful参数, name = " + name + " ; age = " + age;}/*** post请求,请求体传递参数。参数使用@RequestBody处理。*/@PostMapping("/postBodyParams")public String postBodyParams(@RequestBody Map<String, String> params){System.out.println("端口号: " + port + " , post请求,有请求体参数, params = " +params);return "post请求,请求体参数, params = " + params;}/*** post请求,有参数*/@PostMapping("/postWithParams")public String postWithParams(String name, int age){System.out.println("端口号: " + port + " , post请求,有参数, name = " +name + " ; age = " + age);return "post请求有参数 : name = " +name + " ; age = " + age;}/*** post请求,没有参数*/@PostMapping("/postNoParams")public String postNoParams(){System.out.println("端口号: " + port + " , post请求,没有参数");return "post请求,没有参数";}/*** get请求,包含参数*/@GetMapping("/getWithParams")public String getWithParams(String name, int age){System.out.println("端口号: " + port + " 。 get请求,有参数, name = "+ name + " ; age = " + age);return "get请求,包含参数 : name = " + name + " ; age = " + age;}/*** get请求,没有参数* @return*/@GetMapping("/getNoParams")public String getNoParams(){System.out.println("端口号:" + port + "。 get请求,无参数。");return "get请求,无参数。";}
}
服务器依赖:
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.example</groupId><artifactId>commen</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>
3)客户端配置RestTemplate对象
客户端依赖:
<dependencies><dependency><artifactId>spring-boot-starter-web</artifactId><groupId>org.springframework.boot</groupId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.example</groupId><artifactId>commen</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>
4)使用RestTemplate对象在客户端测试服务器方法的调用
①请求行携带键值对的几种形式
②post请求自定义请求头 请求体为键值对
③post请求 传输请求体为json格式
④post请求 自定义传输请求体为json格式
⑤ exchange()通用公式
@SpringBootTest
public class RestTemplateTest {@Autowiredprivate RestTemplate restTemplate;@Testpublic void test(){String forObject = restTemplate.getForObject("http://localhost:8080/getNoParams", String.class);System.out.println("forObject = " + forObject);}@Testpublic void test1(){String forObject1 = restTemplate.getForObject("http://localhost:8080/getWithParams?name=张三&age=20", String.class);String forObject2 = restTemplate.getForObject("http://localhost:8080/getWithParams?name={a}&age={b}", String.class,"战法",29);Map<String,Object> map= new HashMap();map.put("x","阿森纳");map.put("y",20);String forObject3 = restTemplate.getForObject("http://localhost:8080/getWithParams?name={x}&age={y}", String.class,map);System.out.println("forObject1 = " + forObject1);System.out.println("forObject2 = " + forObject2);System.out.println("forObject3 = " + forObject3);}@Testpublic void testPost(){restTemplate.postForObject("http://localhost:8080/postNoParams",null,String.class);}@Testpublic void testPost1(){HttpHeaders httpHeaders = new HttpHeaders();httpHeaders.add("content-type","application/x-www-form-urlencoded");MultiValueMap<String,Object> map = new LinkedMultiValueMap<>();map.add("name","埃德加");map.add("age","20");HttpEntity<MultiValueMap<String,Object>> entity = new HttpEntity<>(map,httpHeaders);String s = restTemplate.postForObject("http://localhost:8080/postWithParams", entity, String.class);String s1 = restTemplate.postForObject("http://localhost:8080/postWithParams?name=咋很难&age=29", entity, String.class);System.out.println("s = " + s);System.out.println("s1 = " + s1);}@Testpublic void testPost2(){Map<String,Object> map = new HashMap<>();map.put("name","绽放");map.put("age",29);restTemplate.postForObject("http://localhost:8080/postBodyParams",map,String.class);}@Testpublic void testPost3() throws JsonProcessingException {HttpHeaders httpHeaders = new HttpHeaders();httpHeaders.add("content-type","application/json");// MultiValueMap<String,Object> map = new LinkedMultiValueMap<>();Map<String,Object> map = new HashMap<>();map.put("name","埃德加");map.put("age","20");ObjectMapper objectMapper = new ObjectMapper();String s1 = objectMapper.writeValueAsString(map);HttpEntity<String> entity = new HttpEntity<>(s1,httpHeaders);String s = restTemplate.postForObject("http://localhost:8080/postBodyParams", entity, String.class);System.out.println("s = " + s);}@Testpublic void testEvery(){ResponseEntity<List<User>> exchange = restTemplate.exchange("http://localhost:8080/returnUsers?nums=9",HttpMethod.GET,null,new ParameterizedTypeReference<List<User>>() {});System.out.println("exchange = " + exchange);}
}
四、openfeign
1)编写Feign接口:
1.将要调用服务主机的Controller中所有单元方法全部复制
2.创建Feign接口,并粘贴所有方法,改写为抽象方法
@FeignClient("application-service")
public interface Feign {@RequestMapping("/returnUsers")public List<User> returnUsers(int nums);/*** 任意请求方式, 返回值类型是集合。相对复杂的Java类型。* @return*/@RequestMapping("/returnList")public List<String> returnList(@RequestParam("nums") int nums);/*** 任意请求,传递路径地址参数* @param name* @param age* @return*/@RequestMapping("/restfulParams/{name}/{age}")public String restfulParams(@PathVariable("name") String name,@PathVariable("age") int age);/*** post请求,请求体传递参数。参数使用@RequestBody处理。*/@PostMapping("/postBodyParams")public String postBodyParams(@RequestBody Map<String, String> params);/*** post请求,有参数*/@PostMapping("/postWithParams")public String postWithParams(@RequestParam("name") String name,@RequestParam("age") int age);/*** post请求,没有参数*/@PostMapping("/postNoParams")public String postNoParams();/*** get请求,包含参数*/@GetMapping("/getWithParams")public String getWithParams(@RequestParam("name")String name,@RequestParam("age")int age);/*** get请求,没有参数* @return*/@GetMapping("/getNoParams")public String getNoParams();
}
3.添加注解