Spring Cloud 入门手册(二)

简介: Spring Cloud 入门手册(二)

Spring Cloud 入门手册(二)


application.yml

spring:
  application:
    name: order-service
server:
  port: 8201

主程序

package cn.tedu.sp04;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
 * @ClassName Sp04OrderserviceApplication
 * @Description
 * @Author keke
 * @Time 2021/7/17 16:28
 * @Version 1.0
 */
@SpringBootApplication
@EnableFeignClients
public class Sp04OrderserviceApplication {
    public static void main(String[] args) {
        SpringApplication.run(Sp04OrderserviceApplication.class, args);
    }
}

Java 源文件

OrderServiceImpl

package cn.tedu.sp04.order.service;
import cn.tedu.sp01.pojo.Order;
import cn.tedu.sp01.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
 * @ClassName OrderServiceImpl
 * @Description
 * @Author keke
 * @Time 2021/7/17 20:07
 * @Version 1.0
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Override
    public Order getOrder(String id) {
        log.info("获取订单, orderId =" + id);
        // TODO:远程调用商品获取商品列表
        // TODO:远程调用用户获取用户数据
        Order order = new Order();
        order.setId(id);
        return order;
    }
    @Override
    public void addOrder(Order order) {
        log.info("添加订单:" + order);
        // TODO:远程调用商品,减少商品库存
        // TODO:远程调用用户,增加用户积分
    }
}

OrderController

package cn.tedu.sp04.order.controller;
import cn.tedu.sp01.pojo.Item;
import cn.tedu.sp01.pojo.Order;
import cn.tedu.sp01.pojo.User;
import cn.tedu.sp01.service.OrderService;
import cn.tedu.sp01.web.util.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
/**
 * @ClassName OrderController
 * @Description
 * @Author keke
 * @Time 2021/7/17 20:08
 * @Version 1.0
 */
@RestController
@Slf4j
public class OrderController {
    @Autowired
    private OrderService orderService;
    /**
     * 获取订单
     */
    @GetMapping("/{orderId}")
    public JsonResult<Order> getOrder(@PathVariable String orderId){
        Order order = orderService.getOrder(orderId);
        return JsonResult.ok().data(order);
    }
    /**
     * 添加订单
     */
    @GetMapping("/")
    public JsonResult<?> addOrder(){
        Order order = new Order();
        order.setId("56u5645y54");
        order.setUser(new User(8, null, null));
        order.setItems(Arrays.asList(new Item[]{
                new Item(1,"aaa",2),
                new Item(2,"bbb",1),
                new Item(3,"ccc",3),
                new Item(4,"ddd",1),
                new Item(5,"eee",5)
        }));
        orderService.addOrder(order);
        return JsonResult.ok().msg("添加订单成功");
    }
}

访问测试

根据 orderId,获取订单 http://localhost:8201/123abc

保存订单,观察窗控制台日志输出 http://localhost:8201/

service 访问测试汇总

  • item-service

根据 orderId,查询商品 http://localhost:8001/35

减少商品库存 http://localhost:8001/decreaseNumber

使用 postman,POST 发送以下格式数据:

[
    {
        "id": 1,
        "name": "abc",
        "number": 23
    },
    {
        "id": 2,
        "name": "def",
        "number": 11
    }
]

  • user-service

根据 userId 查询用户信息 http://localhost:8101/7

根据 userId 为用户增加积分 http://localhost:8101/7/score?score=100

  • order-service

根据 orderId,获取订单 http://localhost:8201/123abc


保存订单,观察窗控制台日志输出 http://localhost:8201/


eureka 注册与发现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wrf0JzOj-1639477451459)(Spring%20Cloud%20%E5%85%A5%E9%97%A8%E6%89%8B%E5%86%8C.assets/image-20210821122452430.png)]


创建 eureka 项目

配置依赖 pom.xml

配置 application.yml

主程序启用 eureka 服务器

启动,访问测试

新建 maven 项目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-laqLD0TF-1639477451460)(Spring%20Cloud%20%E5%85%A5%E9%97%A8%E6%89%8B%E5%86%8C.assets/image-20210821122903650.png)]


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
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>order-parent</artifactId>
        <groupId>cn.tedu</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>sp05-eureka</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
</project>

application.yml

spring:
  application:
    name: eureka-server
server:
  port: 2001
eureka:
  server:
    enable-self-preservation: false
  instance:
    hostname: eureka1
  client:
    register-with-eureka: false
    fetch-registry: false

eureka 集群服务器之间,通过 eureka.instance.hostname 来区分

eureka.server,enable-self-perservation

eureka 的自我保护状态:心跳失败的比例,在15分钟内是否超过85%,如果出现了超过的情况,Eureka Server 会将当前的实例注册信息保护起来,同时提示一个警告,一旦进入保护模式,Eureka Server 将会尝试保护其服务注册表中的信息,不再删除注册表中的数据。也就是不会注销任何微服务

eureka.client.register-with-eureka=false

不向自身注册

eureka.client.fetch-registry=false

不从自身拉取

eureka.instance.lease-expiration-duration-in-seconds

最后一次心跳后,间隔多久认定微服务不可用,默认90

主程序

添加 @EnableEurekaServer

package cn.tedu.sp05;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
 * @ClassName Sp05EurekaApplication
 * @Description
 * @Author keke
 * @Time 2021/7/17 21:30
 * @Version 1.0
 */
@SpringBootApplication
// 触发eureka服务器的自动配置
@EnableEurekaServer
public class Sp05EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(Sp05EurekaApplication.class, args);
    }
}

修改 hosts 文件,添加 eureka 映射

C:\Windows\System32\drivers\etc\hosts

添加内容

127.0.0.1 eureka1
127.0.0.1 eureka2

启动,并访问测试

  • http://eureka1:2001

service provider 服务提供者

  • 修改 item-service、user-service、order-service,把微服务注册到 eureka 服务器
  1. pom.xml 添加 eureka 依赖
  2. application.yml添加 eureka 注册信息
  3. 启动服务,在 eureka 中查看注册信息

pom.xml 添加 eureka 客户端依赖

利用 EditStarts 添加

上面的操作会在 pom.xml 中添加以下依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

application.yml 添加 eureka 注册配置

# defaultZone 表示默认地点
# 如果使用云服务,服务商可以通过不同的eureka服务器
# 如果没有云服务,就只能写defaultZone
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka

eureka.instance.lease-renewal-interval-in-seconds

心跳间隔时间,默认30秒

eureka.client.service-url.defaultZone

默认位置,可以修改为具体地点,表示 eureka 服务器的部署位置,需要云服务器提供

eureka.client.registry-fetch-interval-seconds

拉取注册时间间隔时间,默认30秒

启动服务,在 eureka 中查看注册信息

  • http://eureka1:2001

eureka 和 “服务提供者” 的高可用

item-service 高可用

启动参数 --server.port 可以覆盖 yml 中的端口配置

配置启动参数

  • item-service-8001
--server.port=8001

  • item-service-8002
--server.port=8002


启动测试

  • 访问 eureka 查看 item-service 注册信息

  • 访问两个端口测试
    http://localhost:8001/35
    http://localhost:8002/35

eureka 高可用

添加两个服务器的 profile 配置文件

application-eureka1.yml

eureka:
  instance:
    hostname: eureka1
    prefer-ip-address: true
    # 界面列表中显示的格式也显示ip
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://eureka2:2002/eureka

application-eureka2.yml

1eureka:
  instance:
    hostname: eureka2
    prefer-ip-address: true
    # 界面列表中显示的格式也显示ip
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://eureka1:2001/eureka

配置启动参数 --spring.profiles.active--server.port

  • eureka1 启动参数
--spring.profiles.active=eureka1
--server.port=2001

  • eureka2 启动参数
--spring.profiles.active=eureka2
--server.port=2002




如果在命令行运行,可以在命令行中添加参数:

java -jar xxx.jar --spring.profiles.active=eureka1 --server.port=2001

访问 eureka 服务器,查看注册信息

http://eureka1:2001/


http://eureka2:2002/


eureka 客户端注册时,向两个服务器注册

修改以下微服务


sp02-itemservice

sp03-userservice

sp04-orderservice

eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

当一个 eureka 服务宕机时,仍可以连接另一个 eureka 服务

order-service 调用商品库存服务和用户服务

修改 sp04-orderservice 项目,添加 feign,调用 item-service 和 user-service

  1. pom.xml
  2. 主程序
  3. ItemClient
  4. UserClient
  5. OrderServiceImpl

pom.xml

在父项目的 pom.xml 利用 EditStarts 添加

代码如下:

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

主程序

package cn.tedu.sp04;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
 * @ClassName Sp04OrderserviceApplication
 * @Description
 * @Author keke
 * @Time 2021/8/23 23:56
 * @Version 1.0
 */
@EnableFeignClients
@SpringBootApplication
public class Sp04OrderserviceApplication {
    public static void main(String[] args) {
        SpringApplication.run(Sp04OrderserviceApplication.class, args);
    }
}

ItemClient

package cn.tedu.sp04.order.feign;
import cn.tedu.sp01.pojo.Item;
import cn.tedu.sp01.web.util.JsonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
 * @ClassName ItemClient
 * @Description 三项配置:
 *              1.调用哪个服务
 *              2.调用服务的哪个路径
 *              3.向这个路径提交什么参数
 * @Author keke
 * @Time 2021/7/18 16:52
 * @Version 1.0
 */
@FeignClient(name = "item-service")
public interface ItemClient {
    /**
     * 远程调用商品,获取商品列表
     * @param orderId
     * @return
     */
    @GetMapping("/{orderId}")
    JsonResult<List<Item>> getItems(@PathVariable("orderId") String orderId);
    /**
     * 远程调用商品,减少商品库存
     * @param items
     * @return
     */
    @PostMapping("/decreaseNumber")
    JsonResult<?> decreaseNumber(@RequestBody List<Item> items);
}

UserClient

package cn.tedu.sp04.order.feign;
import cn.tedu.sp01.pojo.User;
import cn.tedu.sp01.web.util.JsonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
/**
 * @ClassName UserClient
 * @Description
 * @Author keke
 * @Time 2021/7/18 16:56
 * @Version 1.0
 */
@FeignClient(name = "user-service")
public interface UserClient {
    /**
     * 远程调用用户,获取用户
     * @param userId
     * @return
     */
    @GetMapping("/{userId}")
    JsonResult<User> getUser(@PathVariable("userId") Integer userId);
    /**
     * 远程调用用户,增加用户积分
     * @param userId
     * @param score
     * @return
     */
    @GetMapping("/{userId}/score")
    JsonResult<?> addScore(@PathVariable("userId") Integer userId,
                           @RequestParam("score") Integer score);
}

OrderServiceImpl

package cn.tedu.sp04.order.service;
import cn.tedu.sp01.pojo.Item;
import cn.tedu.sp01.pojo.Order;
import cn.tedu.sp01.pojo.User;
import cn.tedu.sp01.service.OrderService;
import cn.tedu.sp01.web.util.JsonResult;
import cn.tedu.sp04.feign.ItemClient;
import cn.tedu.sp04.feign.UserClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
 * @ClassName OrderServiceImpl
 * @Description
 * @Author keke
 * @Time 2021/7/17 20:07
 * @Version 1.0
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private ItemClient itemClient;
    @Autowired
    private UserClient userClient;
    @Override
    public Order getOrder(String id) {
        log.info("获取订单, orderId =" + id);
        // TODO:远程调用商品获取商品列表
        JsonResult<List<Item>> items = itemClient.getItems(id);
        // TODO:远程调用用户获取用户数据
        JsonResult<User> user = userClient.getUser(8);
        Order order = new Order();
        order.setId(id);
        order.setUser(user.getData());
        order.setItems(items.getData());
        return order;
    }
    @Override
    public void addOrder(Order order) {
        log.info("添加订单:" + order);
        // TODO:远程调用商品,减少商品库存
        itemClient.decreaseNumber(order.getItems());
        // TODO:远程调用用户,增加用户积分
        userClient.addScore(order.getUser().getId(), 1000);
    }
}

启动服务,访问测试

  • 根据 orderId,获取订单 http://localhost:8201/123abc
  • 保存订单 http://localhost:8201/

zuul API 网关

zuul API 网关,为微服务应用提供同一段对外访问接口。

zuul 还提供过滤器,对所有微服务提供统一的请求校验

新建 sp06-zuul 项目

pom.xml

  • 需要添加 sp01-commons 依赖
<?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
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>order-parent</artifactId>
        <groupId>cn.tedu</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>sp06-zuul</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.tedu</groupId>
            <artifactId>sp01-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
    </dependencies>
</project>
目录
相关文章
|
2月前
|
XML Java 测试技术
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
这篇文章介绍了Spring5框架的三个新特性:支持@Nullable注解以明确方法返回、参数和属性值可以为空;引入函数式风格的GenericApplicationContext进行对象注册和管理;以及如何整合JUnit5进行单元测试,同时讨论了JUnit4与JUnit5的整合方法,并提出了关于配置文件加载的疑问。
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
|
2月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
2月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
2月前
|
Java 数据库连接 Spring
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
文章是关于Spring、SpringMVC、Mybatis三个后端框架的超详细入门教程,包括基础知识讲解、代码案例及SSM框架整合的实战应用,旨在帮助读者全面理解并掌握这些框架的使用。
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
|
2月前
|
NoSQL Java Redis
Redis6入门到实战------ 八、Redis与Spring Boot整合
这篇文章详细介绍了如何在Spring Boot项目中整合Redis,包括在`pom.xml`中添加依赖、配置`application.properties`文件、创建配置类以及编写测试类来验证Redis的连接和基本操作。
Redis6入门到实战------ 八、Redis与Spring Boot整合
|
2月前
|
XML Java 数据格式
Spring5入门到实战------5、IOC容器-Bean管理(三)
这篇文章深入探讨了Spring5框架中IOC容器的高级Bean管理,包括FactoryBean的使用、Bean作用域的设置、Bean生命周期的详细解释以及Bean后置处理器的实现和应用。
Spring5入门到实战------5、IOC容器-Bean管理(三)
|
2月前
|
XML Java 数据格式
Spring5入门到实战------4、IOC容器-Bean管理XML方式、集合的注入(二)
这篇文章是Spring5框架的实战教程,主题是IOC容器中Bean的集合属性注入,通过XML配置方式。文章详细讲解了如何在Spring中注入数组、List、Map和Set类型的集合属性,并提供了相应的XML配置示例和Java类定义。此外,还介绍了如何在集合中注入对象类型值,以及如何使用Spring的util命名空间来实现集合的复用。最后,通过测试代码和结果展示了注入效果。
Spring5入门到实战------4、IOC容器-Bean管理XML方式、集合的注入(二)
|
2月前
|
SQL 数据库
Spring5入门到实战------13、使用JdbcTemplate操作数据库(批量增删改)。具体代码+讲解 【下篇】
这篇文章是Spring5框架的实战教程,深入讲解了如何使用JdbcTemplate进行数据库的批量操作,包括批量添加、批量修改和批量删除的具体代码实现和测试过程,并通过完整的项目案例展示了如何在实际开发中应用这些技术。
Spring5入门到实战------13、使用JdbcTemplate操作数据库(批量增删改)。具体代码+讲解 【下篇】
|
2月前
|
XML Java 数据格式
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
这篇文章是Spring5框架的AOP切面编程教程,通过XML配置方式,详细讲解了如何创建被增强类和增强类,如何在Spring配置文件中定义切入点和切面,以及如何将增强逻辑应用到具体方法上。文章通过具体的代码示例和测试结果,展示了使用XML配置实现AOP的过程,并强调了虽然注解开发更为便捷,但掌握XML配置也是非常重要的。
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
|
2月前
|
XML Java 数据格式
Spring5入门到实战------6、IOC容器-Bean管理XML方式(自动装配)
这篇文章是Spring5框架的入门教程,详细讲解了IOC容器中Bean的自动装配机制,包括手动装配、`byName`和`byType`两种自动装配方式,并通过XML配置文件和Java代码示例展示了如何在Spring中实现自动装配。
Spring5入门到实战------6、IOC容器-Bean管理XML方式(自动装配)
下一篇
无影云桌面