SpringCloud之Config配置中心与Redis分布式锁详解

SpringCloud之Config配置中心与Redis分布式锁详解

在分布式系统中,配置的统一管理以及分布式锁的实现都是非常重要的一部分。Spring Cloud提供了Config Server和Redis分布式锁这两个强大的功能来支持分布式系统的开发。本文将详细介绍Spring Cloud Config的使用和Redis分布式锁的实现方法。

一、Spring Cloud Config的使用

1.1 简介

Spring Cloud Config提供了一种集中式的外部配置管理方法,用于管理微服务应用、集群应用和分布式系统的各种配置文件。通过它,程序员可以用统一的方式管理各个微服务中的配置信息。该配置信息存储在Git、SVN等版本管理系统中,方便进行版本控制。Spring Cloud Config Server作为配置服务的中心,管理所有的配置信息,各个微服务则通过Config Client从Config Server中读取配置信息。

1.2 Config Server的搭建和配置

首先,在pom.xml文件中添加以下依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

然后,在启动类上添加@EnableConfigServer注解,开启配置服务功能:

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class,args);
    }
}

接着,在application.properties中配置Git或SVN的地址和用户名密码:

spring.cloud.config.server.git.uri=https://github.com/your-username/your-repo
spring.cloud.config.server.git.username=your-username
spring.cloud.config.server.git.password=your-password

最后,在启动服务后,可以通过以下URL访问配置信息:

http://localhost:8888/{application}/{profile}/{label}

其中,application代表应用名,profile代表环境,如dev、test、prod等,label代表版本。

1.3 Config Client的使用

首先,在pom.xml文件中添加以下依赖:

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

接着,在启动类上添加@EnableConfiguraitonProperties注解,将配置文件中的配置属性映射到Bean中:

@SpringBootApplication
@EnableConfigurationProperties
public class ConfigClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigClientApplication.class,args);
    }
}

在application.properties中配置Config Server的地址:

spring.cloud.config.uri=http://localhost:8888

最后,在需要读取配置信息的地方,使用@Value注解获取配置信息即可:

@Component
public class DemoComponent {
    @Value("${config.name}")
    private String name;

    public void show() {
       System.out.println("name:" + name);
    }
}

1.4 示例:配置中心的综合应用

假设有两个微服务——order和product,都需要读取数据库的配置信息。可以将数据库的配置信息统一存储在配置中心,让order和product从配置中心中读取。

  1. 配置中心的搭建和配置

按照1.2所述的方式,搭建配置中心,并将数据库的配置信息上传到Git版本管理系统中。

  1. order服务的配置

在order服务的配置文件中,添加以下配置:

spring.datasource.url=${spring.cloud.config.uri}/order/mydb
spring.datasource.username=${spring.cloud.config.username}
spring.datasource.password=${spring.cloud.config.password}
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

在启动类上添加注解@EnableDiscoveryClient和@EnableFeignClients使其具有服务注册和服务发现的能力。使用Feign Client调用product服务的接口,查询商品信息:

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class,args);
    }
} 

// Feign Client
@FeignClient(name="product-service")
public interface ProductClient {
    @GetMapping("/product/{productId}")
    public Product getProduct(@PathVariable("productId") Long productId);
}

// Controller
@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private ProductClient productClient;

    @GetMapping("/{orderId}")
    public Order getOrder(@PathVariable("orderId") Long orderId) {
       Order order = new Order();
       order.setOrderId(orderId);
       Product product = productClient.getProduct(orderId);
       order.setProduct(product);
       return order;
    }
}
  1. product服务的配置

在product服务的配置文件中,添加以下配置:

spring.datasource.url=${spring.cloud.config.uri}/product/mydb
spring.datasource.username=${spring.cloud.config.username}
spring.datasource.password=${spring.cloud.config.password}
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

在启动类上添加注解@EnableDiscoveryClient以具有服务注册和服务发现的能力。将商品信息存储在内存中,用于返回查询结果:

@SpringBootApplication
@EnableDiscoveryClient
public class ProductServiceApplication {
    public static Map<Long, Product> products = new HashMap<>();

    static {
       Product product1 = new Product(1L, "华为手机P40", 4999.99);
       Product product2 = new Product(2L, "小米电视", 2999.99);
       products.put(product1.getProductId(), product1);
       products.put(product2.getProductId(), product2);
    }

    public static void main(String[] args) {
       SpringApplication.run(ProductServiceApplication.class,args);
    }
} 

// Controller
@RestController
@RequestMapping("/product")
public class ProductController {
    @GetMapping("/{productId}")
    public Product getProduct(@PathVariable("productId") Long productId) {
       Product product = ProductServiceApplication.products.get(productId);
       if(product == null) {
           throw new RuntimeException("Product not found.");
       }
       return product;
    }
}

二、Redis分布式锁的实现方法

2.1 简介

在分布式系统中,为了保证数据的正确性和一致性,需要使用分布式锁来实现资源的互斥访问。Redis是一种高性能的NoSQL数据库,非常适合用于分布式锁的实现。Redis分布式锁的基本思路是通过Redis的SETNX命令来实现互斥访问,同时设置一个过期时间,确保在某些情况下锁被意外释放时不会对程序造成不良的影响。

2.2 实现方法

使用Spring Data Redis连接Redis,并编写加锁和释放锁的代码:

@Component
public class RedisLock {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 加锁
     * @param key 锁的名称
     * @param timeout 锁的有效期
     * @return 锁标识
     */
    public String lock(String key, long timeout) {
        String identifier = UUID.randomUUID().toString();
        long end = System.currentTimeMillis() + timeout;
        while (System.currentTimeMillis() < end) {
            if (redisTemplate.opsForValue().setIfAbsent(key, identifier)) {
                redisTemplate.expire(key, timeout, TimeUnit.MILLISECONDS);
                return identifier;
            }
            try {
                Thread.sleep(100);//等待一段时间后重试
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 释放锁
     * @param key 锁的名称
     * @param identifier 锁标识
     */
    public void unlock(String key, String identifier) {
        while (true) {
            redisTemplate.watch(key);
            if (identifier.equals(redisTemplate.opsForValue().get(key))) {
                redisTemplate.multi();
                redisTemplate.delete(key);
                List<Object> results = redisTemplate.exec();
                if (results == null) {//如果返回null代表执行失败,需要重试
                    continue;
                }
            }
            redisTemplate.unwatch();
            break;
        }
    }
}

2.3 示例:秒杀系统的分布式锁

假设有一个秒杀系统,需实现高并发的订单处理。可以设定一定的抢购时间,并用分布式锁解决订单重复处理的问题。

  1. 设计模型

假设订单数据模型如下:

@Data
public class Order {
    private Long orderId;
    private Long productId;
    private Integer amount;
    private Integer status; // 订单状态:0-未支付,1-已支付
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}
  1. 创建订单

使用数据库中的库存信息和请求中的抢购数量计算出真实的库存量,然后使用Redis分布式锁保证订单不会重复创建:

@Autowired
private RedisLock redisLock;

@Autowired
private OrderRepository orderRepository;

@Transactional
public Order createOrder(Long productId, Integer amount, long timeout) {
    // 获取分布式锁
    String identifier = redisLock.lock("product_" + productId, timeout);
    if (identifier == null) {
        throw new RuntimeException("No lock available");
    }
    try {
        // 查询库存信息
        Product product = productService.getProduct(productId);
        if (product.getAmount() < amount) {
            throw new RuntimeException("Not enough stock");
        }
        // 扣减库存
        product.setAmount(product.getAmount() - amount);
        productService.updateProduct(product);
        // 创建订单
        Order order = new Order();
        order.setOrderId(System.currentTimeMillis());
        order.setProductId(productId);
        order.setAmount(amount);
        order.setStatus(0);
        order.setCreateTime(LocalDateTime.now());
        order.setUpdateTime(LocalDateTime.now());
        orderRepository.save(order);
        return order;
    } finally {
        // 释放分布式锁
        redisLock.unlock("product_" + productId, identifier);
    }
}
  1. 查询订单

查询订单的流程较为简单,不再赘述。

总结

通过本文的介绍,希望读者能够了解Spring Cloud Config配置中心和Redis分布式锁的使用方法。配置中心用于管理分布式系统中的各种配置信息,避免在每个微服务中都需要进行相同的配置;而Redis分布式锁用于保证互斥访问,避免数据不一致的情况出现。本文还给出了一些示例,希望对读者的实际开发起到一些参考作用。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringCloud之Config配置中心与Redis分布式锁详解 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • mybatis-plus团队新作mybatis-mate实现数据权限

    下面我简单讲解一下 “mybatis-plus团队新作mybatis-mate实现数据权限” 的完整攻略。 1. 简介 mybatis-mate 是 mybatis-plus 团队新推出的一个框架,它可以帮助我们更方便地实现数据权限控制。通过使用 mybatis-mate,我们可以很容易地设置数据过滤规则,以保证用户只能看到他们有权限访问的数据。 2. 实现…

    Java 2023年5月20日
    00
  • java应用cpu占用过高问题分析及解决方法

    Java应用CPU占用过高问题分析及解决方法 现象描述 在运行Java应用过程中,发现CPU占用率过高,导致系统响应变慢,严重影响应用的性能和稳定性 原因分析 Java应用CPU占用高的原因可能有很多,下面列举一些常见的原因: 程序中存在大量的死循环或者无限递归调用 程序中存在大量的同步操作,导致CPU不停的进行上下文切换 程序中存在大量的IO操作,导致CP…

    Java 2023年5月26日
    00
  • Java运用SWT插件编写桌面记事本应用程序

    Java运用SWT插件编写桌面记事本应用程序 简介 SWT(Standard Widget Toolkit)是一种Java库,它提供了一组本地GUI控件,使开发者可以使用本地的GUI控件制作图形用户界面。SWT的特点是高效和快速响应,可以充分利用本地操作系统的GUI库。 本篇攻略将详细介绍如何使用SWT插件编写一个桌面记事本应用程序。 步骤 步骤一:准备SW…

    Java 2023年5月23日
    00
  • Spring源码分析容器启动流程

    下面是针对“Spring源码分析容器启动流程”的完整攻略。 1. 前言 Spring是一个非常流行的Java开发框架,它最基本的组成部分就是一个IOC容器。在了解Spring的使用过程中,我们需要知道Spring容器启动的过程,这样可以更好的理解Spring的原理和运作机制。 2. Spring容器启动流程概述 Spring容器启动流程可以分为以下几个基本步…

    Java 2023年5月31日
    00
  • 详解Java String类常用方法有哪些

    详解Java String类常用方法有哪些 在Java语言中,String类是一个非常重要的类,可以理解为字符串类型。在使用String类型时,我们通常需要对其进行一些常用的方法操作,以方便我们得到预期的结果。下面将会介绍一些常用的String类方法。 1. 字符串比较 在Java中,字符串的比较使用equals()方法完成。equals()方法会比较两个字…

    Java 2023年5月27日
    00
  • 举例讲解Java的JSON类库GSON的基本用法

    下面就给您详细讲解Java的JSON类库GSON的基本用法的攻略。 什么是GSON GSON是Google开发的用于Java解析JSON数据的类库。它可以将一个JSON字符串转化成Java对象,同样也可以将Java对象转化成对应的JSON字符串。GSON可以编码和解码任何Java对象。 导入GSON的Jar包 在使用GSON之前,我们需要先在项目中导入GSO…

    Java 2023年5月26日
    00
  • SpringDataRedis入门和序列化方式解决内存占用问题小结

    下面就是关于“SpringDataRedis入门和序列化方式解决内存占用问题小结”的完整攻略。 SpringDataRedis入门 什么是Redis? Redis(Remote Dictionary Server)是一个开源的基于内存的数据结构存储系统,可以用作数据库、缓存和消息中间件。Redis支持多种类型的数据结构,如字符串(strings)、哈希(ha…

    Java 2023年5月20日
    00
  • java编程实现并查集的路径压缩代码详解

    Java编程实现并查集的路径压缩代码详解 什么是并查集? 并查集(Union-Find)是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。 为什么需要路径压缩? 在并查集的运行过程中,当进行多次find操作时,可能出现树深度太深的问题,导致find操作的时间复杂度增加。在这种情况下,就需要使…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部