当前位置: 首页 > news >正文

Java | 基于 ThreadLocal 实现多客户端访问设备的 REST 请求下发

关注:CodingTechWork

引言

  在分布式系统中,常常会遇到多个客户端同时访问同一个机器设备的情况。为了确保每个客户端的请求都能正确地发送到目标设备,并且能够根据当前线程自动获取对应的设备信息进行操作,我们可以利用 ThreadLocal 来实现线程隔离和上下文管理。本文将详细介绍如何使用 ThreadLocal 来实现这一功能,并结合 RestTemplate 完成对设备的 REST 请求下发。

ThreadLocal 简介

  ThreadLocal 是 Java 提供的一种线程局部变量存储机制。它为每个线程提供了一个独立的变量副本,使得每个线程都可以独立地访问和修改自己的变量副本,而不会相互干扰。这种机制非常适合处理多线程环境下的上下文信息传递问题。

需求分析

  假设我们有一个系统,多个客户端通过不同的 IP 和端口访问同一个机器设备。我们需要在每个线程中自动获取当前客户端对应的设备信息(IP 和端口),并使用 RestTemplate 向设备发送 REST 请求。具体需求如下:

  • 多客户端访问:支持多个客户端同时访问同一个设备。
  • 线程隔离:每个线程只能访问当前线程的设备信息。
  • 自动获取设备信息:在每个线程中自动获取当前线程的设备信息。
  • REST 请求下发:使用 RestTemplate 向设备发送 REST 请求。

实现思路

  1. 定义设备信息类:创建一个 Device 类,用于存储设备的 IP 和端口信息。
  2. 使用 ThreadLocal 存储设备信息:创建一个 DeviceContextHolder 类,使用 ThreadLocal 来存储当前线程的设备信息。
  3. REST 请求下发:创建一个 DeviceService 类,使用 RestTemplate 向设备发送 REST 请求。
  4. 测试:编写测试代码,模拟多个客户端访问设备的场景。

代码实现

定义设备信息类

创建一个 Device 类,用于存储设备的 IP 和端口信息。

public class Device {
    private String ip;
    private int port;

    public Device(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }

    public String getIp() {
        return ip;
    }

    public int getPort() {
        return port;
    }

    @Override
    public String toString() {
        return "Device{" +
                "ip='" + ip + '\'' +
                ", port=" + port +
                '}';
    }
}

使用 ThreadLocal 存储设备信息

创建一个 DeviceContextHolder 类,使用 ThreadLocal 来存储当前线程的设备信息。

import java.util.Optional;

public class DeviceContextHolder {
    private static final ThreadLocal<Device> DEVICE_THREAD_LOCAL = new ThreadLocal<>();

    public static void setDevice(Device device) {
        DEVICE_THREAD_LOCAL.set(device);
    }

    public static Optional<Device> getDevice() {
        return Optional.ofNullable(DEVICE_THREAD_LOCAL.get());
    }

    public static void clear() {
        DEVICE_THREAD_LOCAL.remove();
    }
}
  1. REST 请求下发
    创建一个 DeviceService 类,使用 RestTemplate 向设备发送 REST 请求。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class DeviceService {
    @Autowired
    private RestTemplate restTemplate;

    public void sendRequestToDevice() {
        Optional<Device> deviceOptional = DeviceContextHolder.getDevice();
        if (deviceOptional.isPresent()) {
            Device device = deviceOptional.get();
            String url = "http://" + device.getIp() + ":" + device.getPort() + "/api";
            System.out.println("Sending request to: " + url);
            restTemplate.getForObject(url, String.class);
        } else {
            System.out.println("No device information found in the current thread.");
        }
    }
}

测试代码

编写测试代码,模拟多个客户端访问设备的场景。

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@SpringBootApplication
public class DeviceRequestApplication {
    @Autowired
    private DeviceService deviceService;

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

    @Bean
    public CommandLineRunner commandLineRunner() {
        return args -> {
            ExecutorService executorService = Executors.newFixedThreadPool(5);

            // 模拟多个客户端访问设备
            executorService.submit(() -> {
                DeviceContextHolder.setDevice(new Device("192.168.1.1", 8080));
                deviceService.sendRequestToDevice();
                DeviceContextHolder.clear();
            });

            executorService.submit(() -> {
                DeviceContextHolder.setDevice(new Device("192.168.1.2", 8081));
                deviceService.sendRequestToDevice();
                DeviceContextHolder.clear();
            });

            executorService.shutdown();
        };
    }

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

运行结果

运行测试代码后,观察控制台输出:

Sending request to: http://192.168.1.1:8080/api
Sending request to: http://192.168.1.2:8081/api

从结果可以看出,每个线程都成功地获取了当前线程的设备信息,并向对应的设备发送了 REST 请求。

总结

  本文介绍了如何使用 ThreadLocal 实现多客户端访问设备的 REST 请求下发。通过 ThreadLocal,我们可以在每个线程中独立地存储和访问设备信息,确保线程隔离和上下文管理的正确性。结合 RestTemplate,我们可以轻松地向设备发送 REST 请求,实现分布式环境下的设备访问功能。在实际项目中,可以根据需求对代码进行扩展和优化,例如支持更复杂的设备信息管理、增加错误处理机制等。

相关文章:

  • 量子计算:开启信息时代新纪元的钥匙
  • 阀门流量控制系统MATLAB仿真PID
  • 从 YOLO11 模型格式导出到TF.js 模型格式 ,环境爬坑,依赖关系已经贴出来了
  • Python中multiprocessing的使用详解
  • git push的时候出现无法访问的解决
  • MinGW下编译ffmpeg源码时生成compile_commands.json
  • 微信小程序报错:600001 ERR_CERT_AUTHORITY_INVALID 的问题排查及解决
  • 区块链技术在投票系统中的应用:安全、透明与去中心化
  • (!常识!)C++中的内存泄漏和野指针——如何产生?如何避免?解决方案?基本原理?面试常问重点内容?
  • Springbean(二)@Component及其派生注解自动注入(2)使用注意和加载问题
  • JSON是什么
  • 【Git “reset“ 命令详解】
  • 论文浅尝 | C-ICL:用于信息抽取的对比式上下文学习(EMNLP2024)
  • 淘宝获取商品sku详情API接口如何调用?
  • 转发和重定向
  • 每天认识一个设计模式-桥接模式:在抽象与实现的平行宇宙架起彩虹桥
  • GPT-4o图像生成功能:技术突破与隐忧并存
  • R 安装和查看历史版本 R 包指南
  • 在Vue 3 + TypeScript + Vite 项目中安装和使用 SCSS
  • 如何在 Postman 中上传图片并在请求中正确引用?
  • 五大国货美妆去年业绩分化:珀莱雅百亿营收领跑,上海家化转亏
  • 陕西省通报6起违反八项规定典型问题,省卫健委原主任刘宝琴违规收受礼品礼金
  • 新型算法助力听障人士听得更清晰
  • 国务院安委会对辽宁辽阳一饭店重大火灾事故查处挂牌督办
  • 泽连斯基承认乌情报部门刺杀俄军高官
  • 长三角铁路“五一”假期运输今启动:预计发送旅客量增6%,5月1日当天有望创新高