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日

相关文章

  • JetCache 缓存框架的使用及源码解析(推荐)

    JetCache 缓存框架的使用及源码解析(推荐) 简介 JetCache 是一个基于 Java 语言的高性能缓存框架,具备很高的灵活性和扩展性,可以支持 Redis、Memory、Lru、Caffeine、Tair 等缓存模式。JetCache 提供了基于注解的缓存操作方式,也提供了编程式的缓存操作方式,使用起来非常简单。 安装 在 pom.xml 文件中…

    Java 2023年5月20日
    00
  • JAVA 十六进制与字符串的转换

    Java 中可以通过多种方式实现十六进制和字符串之间的转化。本文将介绍两种主要的方法:使用内置类库和字节数组转换。 使用内置类库实现 Java 内置的 Integer、Long 和 Short 等类库提供了十六进制和字符串之间的转化方法。下面是一个示例: // 十六进制转字符串 int hexVal = 0x1F; String hexStr = Integ…

    Java 2023年5月27日
    00
  • SpringBoot项目开发常用技术整合

    Spring Boot项目开发常用技术整合 Spring Boot是一个基于Spring框架的快速开发应用程序的工具。它提供了一种快速、便捷的方式来创建基于Spring的应用程序,同时也提供了一些默认的和约定,使得开发人员可以更加专注于业务逻辑的实现。本文将详细讲解如何使用Spring Boot整合常用技术,并提供两个示例。 1. 整合MyBatis MyB…

    Java 2023年5月15日
    00
  • 关于maven环境的安装及maven集成idea环境的问题

    下面是关于maven环境的安装及maven集成idea环境的问题的完整攻略。 1. Maven环境的安装 1.1 下载Maven 首先,需要从Maven官网上下载最新版的Maven。可以访问以下网址: https://maven.apache.org/download.cgi 选择最新版本的二进制zip文件,下载后解压缩到本地。 1.2 配置环境变量 在Ma…

    Java 2023年5月20日
    00
  • Java Servlet输出中文乱码问题解决方案

    针对“Java Servlet输出中文乱码问题解决方案”,我来给你一个完整的攻略。具体步骤如下: 1. 设置请求和响应的编码方式 在Servlet中,我们需要设置请求和响应的编码方式为utf-8,即: request.setCharacterEncoding("utf-8"); // 设置请求编码方式为utf-8 response.set…

    Java 2023年5月20日
    00
  • 在Java中使用基本的正则表达式

    下面就详细讲解“在Java中使用基本的正则表达式”的完整攻略。正则表达式是一种强大的文本匹配工具,可以用来搜索、置换和提取字符串中的特定字符或模式。Java可以使用基本的正则表达式实现这些功能。 1. 正则表达式的语法 正则表达式由普通字符(例如字母、数字等)和特殊字符组成。特殊字符通常由反斜线转义。以下是一些重要的特殊字符: 单个字符 .:匹配任何字符(除…

    Java 2023年5月27日
    00
  • MyBatis源码解析之Transaction事务模块

    MyBatis源码解析之Transaction事务模块 一、概述 MyBatis是一款优秀的持久层框架,它支持事务控制,能够帮助开发者方便地管理数据的事务。MyBatis的事务管理模块主要由Transaction接口、TransactionFactory接口、TransactionIsolationLevel枚举和JdbcTransaction、Manage…

    Java 2023年6月16日
    00
  • 带你重新认识MyBatis的foreach

    好的。MyBatis是一款非常流行的ORM框架,而foreach标签是MyBatis中比较常用的一个标签,可以方便地在SQL中进行集合参数的遍历操作。 以下是带你重新认识MyBatis的foreach的完整攻略: 1. 简介 foreach标签用于循环遍历集合参数中的元素,并将每个元素作为SQL查询的参数传递进去。它可以用在SELECT、INSERT、UPD…

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