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

yizhihongxing

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日

相关文章

  • 使用SpringBoot+AOP实现可插拔式日志的示例代码

    下面是使用SpringBoot+AOP实现可插拔式日志的完整攻略。 什么是SpringBoot+AOP Spring AOP(Aspect Oriented Programming)是Spring框架中的一个重要模块,用于将额外的行为(横切逻辑)注入到系统中的特定点。SpringBoot是Spring框架的一个特殊版本,通过预先配置好常用的Bean并提供自动…

    Java 2023年5月20日
    00
  • JavaSpringBoot报错“TransactionSystemException”的原因和处理方法

    当使用Java的Spring Boot框架时,可能会遇到“TransactionSystemException”错误。这个错误通常是由以下原因之一引起的: 事务管理器配置错误:如果事务管理器配置错误,则可能会出现此错误。在这种情况下,需要检查事务管理器的配置并进行必要的更改。 事务注解使用错误:如果事务注解使用错误,则可能会出现此错误。在这种情况下,需要检查…

    Java 2023年5月5日
    00
  • Java反射简易教程

    下面是Java反射简易教程的完整攻略。 什么是反射? Java是一门静态语言,一般情况下,我们需要在编译时就定义好变量和类的类型。但是有些情况下,我们需要在运行时动态获取或者创建对象,这时候就需要使用反射技术。 Java反射是指程序可以访问、检测和修改它本身的某些属性或者方法,而这些属性或者方法都是在编译时完全未知的,只有在运行时才能确定。Java反射使得我…

    Java 2023年5月26日
    00
  • JDBC利用C3P0数据库连接池连接数据库

    JDBC连接到数据库时,如果每次都重新创建一个新的连接,会造成资源浪费,影响性能。因此,使用连接池进行连接管理是一个比较好的选择,C3P0是一个常用的数据库连接池。 以下是详细的攻略: 1. 导入C3P0依赖库 在pom.xml文件中添加C3P0依赖: <dependencies> <!–…省略其他依赖–> <depen…

    Java 2023年6月16日
    00
  • Mybatis的动态Sql组合模式详情

    Mybatis的动态Sql组合模式详情 Mybatis 中动态Sql的组合模式使得我们可以根据不同的条件转换为不同的Sql语句,从而能够满足更加灵活的业务需求。在 Mybatis 中,动态 Sql 的组合模式主要采用了 OGNL 表达式的方式来实现。在本文中,我们将详细讲解 Mybatis 中动态Sql组合模式的使用方法和示例。 1. 动态Sql的组合模式 …

    Java 2023年5月20日
    00
  • Java实现四则混合运算代码示例

    下面详细讲解一下”Java实现四则混合运算代码示例”的攻略。 一、分析需求 在实现四则混合运算之前,我们需要先分析需求,根据问题的实际情况,确定实现的功能和需求。 四则混合运算包括”加、减、乘、除”四种基本运算,以及括号嵌套。我们需要考虑以下几个方面的需求: 支持四则运算以及括号嵌套。 具有运算符优先级和算数优先级, 先乘除后加减。 括号中的表达式优先级最高…

    Java 2023年5月19日
    00
  • Java实现简单学生信息管理系统

    Java实现简单学生信息管理系统攻略 一、项目背景 随着教育信息化的发展,学生信息管理系统已经成为了中小学校管理工作不可或缺的一部分。Java是一门广泛应用于企业级开发的编程语言,具有高效性、安全性、跨平台性等特点。本篇攻略将介绍如何用Java语言实现一个简单的学生信息管理系统。 二、系统功能设计 该学生信息管理系统的主要功能包括:- 添加学生信息- 删除学…

    Java 2023年5月19日
    00
  • SpringBoot整合mybatis-generator插件流程详细讲解

    下面是SpringBoot整合mybatis-generator插件的详细攻略,我们将分为以下几个步骤进行操作: 添加mybatis-generator插件依赖 配置mybatis-generator插件 配置生成代码的输出路径和文件名 自动生成代码 示例展示 1. 添加mybatis-generator插件依赖 首先,我们需要在项目中添加mybatis-g…

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