springboot获取Request的方式和线程是否安全讨论

1.获取Request的三种方式

一、直接注入的方式(推荐

作为一名轻微强迫症的开发人员,只推荐这种方式,因为这种直接注入的可以在controller、service等任何你想要注入的地方注入,容易理解,这种方式后面将会继续讨论是否是线程安全。

@RestController
@RequestMapping("/request")
@RequiredArgsConstructor  //通过构造器注入
public class RequestController {
        
    private final HttpServletRequest request1;

    @GetMapping("/test1")
    public void test1() {
        //注入后就可以直接使用
        request1.setAttribute("userName","leakey");
    }
}

二、在controller里面使用参数注入(不推荐

这种方式request是作为controller的参数注入进来的,优点就是直观,让人感觉到每个请求都是独立的request(硬夸),缺点是后面的service或者其他地方需要用request对象的时候,需要带着他到处跑,那么优秀的你,想必也不能忍受吧!

@RestController
@RequestMapping("/request")
public class RequestController {

    @GetMapping("/test2")
    public void test2(HttpServletRequest request2){
        request2.setAttribute("userName","leakey");
    }
}

三、通过RequestContextHolder获取

这种方式也可以在任何地方获取Request,优点当然是方便,缺点稍微不那么直观

@RestController
@RequestMapping("/request")
public class RequestController {

    @GetMapping("/test3")
    public void test3(){
        ServletRequestAttributes servletRequest
Spring Boot应用中结合RabbitMQ实现“发送消息并等待另一条消息返回”的场景,通常可以借助 **`RabbitTemplate`** 的回调机制以及手动管理消息队列的方式来完成。 以下是具体的思路及步骤: --- ### 1. 使用 `RabbitTemplate.convertAndSend()` 发送消息 通过 RabbitMQ 提供的模板工具类 `RabbitTemplate` 可以轻松地将消息发送到指定的交换机(Exchange)。例如: ```java rabbitTemplate.convertAndSend("exchangeName", "routingKey", message); ``` 这会把一条消息推送到目标队列中。 --- ### 2. 设置回调监听响应消息 为了能够接收从其他服务发回的消息,需要设置一个临时队列,并使用消费者来监听该队列。一般有以下两种常见方式实现这一功能: #### 方式一:基于 Correlation ID 和 Temporary Queue - 每次发送消息时生成唯一的 **Correlation ID** 并将其绑定至消息头信息。 - 创建匿名或动态随机命名的临时队列用于接收应答数据。 - 配置回复地址 (`replyTo`) 参数指向此临时队列名称以便对方知道结果应该反馈何处。 - 监听这个特定的 queue 获取最终的结果通知即可。 示例代码片段如下所示: ```java // 定义一个线程安全的对象存储待处理请求状态 private final Map<String, CountDownLatch> latchMap = new ConcurrentHashMap<>(); private final Map<String, Object> responseMap = new ConcurrentHashMap<>(); public void sendMessageWithCallback(String exchange, String routingKey, Message request) { // Generate unique correlation id for tracking replies. String corrId = UUID.randomUUID().toString(); // Set up a countdown latch to wait until we get the reply or timeout happens. CountDownLatch latch = new CountDownLatch(1); latchMap.put(corrId, latch); // Use convertSendAndReceive method which internally uses DirectReplyToMessageListenerContainer under hood if no 'reply-to' property is set manually in headers otherwise it will use provided one as destination where answer should be sent back after processing initial command from client side perspective . rabbitTemplate.setReturnCallback((message1 , cause)->{ System.out.println("Returned Message:"+new String(message1.getBody())); }); Address address=new Address("#"); rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter()); rabbitTemplate.send(exchange,routingKey,request,(correlationData)->{ SimpleResourceHolder.bind(rabbitTemplate.getConnectionFactory(),address.getValue()); return null; },new CorrelationData(corrId)); } @RabbitListener(queues = "#{autoDeleteQueueBean.name}") public void receiveResponse(Object response, @Header(AmqpHeaders.CORRELATION_ID) String corrId) throws InterruptedException { // Once received put into responses map then count down corresponding lock associated with given key (which represents original query). synchronized(latchMap){ if(latchMap.containsKey(corrId)){ responseMap.put(corrId,response); latchMap.get(corrId).countDown(); } } } ``` 上述例子展示了如何利用同步原语如信号量锁(CountDownLatch),使得主线程可以在发出命令之后阻塞直至收到预期的答案为止;同时维护两个共享结构——一个是关联任务与其生命周期控制装置之间映射表latches,另一个则是实际获取回来的数据容器responses. #### 方式二:采用 RPC 样式的通信模式 如果交互流程更倾向于远程过程调用(RPC),可以直接依赖于 Spring AMQP 内建支持此类操作的功能模块。只需要简单的几行配置就能让框架自动创建必要的资源并且简化编码复杂度。 启用RPC风格的支持非常简单,在yml文件里添加类似下面这样的属性值就足够了: ```yaml spring.rabbitmq.listener.direct.consumers-per-queue=5 #调整消费端并发数 ``` 然后直接调用相应api 即可获得异步结果 ```java Object result=rabbitTemplate.convertSendAndReceiveAsType( ExchangeEnum.EXCHANGE delayed.getName(), RouteKeyEnum.DELAYED_ROUTE_KEY.getName() ,"hello world", Type type); ``` 这种方式背后的工作原理本质上还是围绕着之前提到过的那些关键要素展开讨论,只不过由底层库替我们完成了大部分繁琐细节管理工作罢了! --- ### 注意事项 无论是选择哪种方案都需要注意以下几个方面的问题: - 确保生产者和消费者的序列化反序列化的规则保持一致; - 如果存在跨语言互操的情况则更要小心兼容性隐患的存在; - 合理设定超时期限避免长时间占用系统资源; - 对可能出现异常状况进行全面考虑加入相应的容错措施等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值