Spring Boot 的自动配置,以rabbitmq为例,请详细说明

Spring Boot 的自动配置特性能够大大简化集成外部服务和组件的配置过程。以 RabbitMQ 为例,Spring Boot 通过 spring-boot-starter-amqp 提供了自动配置支持,开发者只需在应用中添加相关依赖并配置必要的属性,Spring Boot 会自动配置所需的连接工厂、消息队列、交换机、消息模板等。

以下是以 RabbitMQ 为例的详细说明。

1. 引入 RabbitMQ 依赖

要使用 Spring Boot 集成 RabbitMQ,首先需要在项目的 pom.xml 文件中添加 spring-boot-starter-amqp 依赖,这个依赖包含了与 RabbitMQ 交互的所有必要组件。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

spring-boot-starter-amqp 依赖包含了 Spring AMQPRabbitMQ 的连接组件,自动配置会根据此依赖自动启用 RabbitMQ 相关功能。

2. 配置 RabbitMQ 连接属性

接下来,你需要在 application.propertiesapplication.yml 中配置 RabbitMQ 的连接信息。例如:

使用 application.properties
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
spring.rabbitmq.publisher-confirm-type=simple
spring.rabbitmq.listener.simple.concurrency=3
spring.rabbitmq.listener.simple.max-concurrency=10
  • spring.rabbitmq.host:RabbitMQ 服务器的地址,通常是 localhost
  • spring.rabbitmq.port:RabbitMQ 服务器的端口,默认是 5672
  • spring.rabbitmq.username 和 spring.rabbitmq.password:RabbitMQ 的认证信息。
  • spring.rabbitmq.virtual-host:虚拟主机,通常是 /
  • spring.rabbitmq.publisher-confirm-type:确认模式,simple 为简单确认。
  • spring.rabbitmq.listener.simple.concurrency:并发消费者数量。
  • spring.rabbitmq.listener.simple.max-concurrency:最大消费者数量。

 

Spring Boot 会读取这些配置并自动配置连接工厂、消息队列监听器等。

3. 自动配置的原理

Spring Boot 在启动时会通过 spring-boot-autoconfigure 模块自动配置 RabbitMQ 相关的 Bean,主要通过以下几个步骤:

3.1 自动配置连接工厂(ConnectionFactory

Spring Boot 会根据 spring.rabbitmq.* 配置自动创建一个 ConnectionFactory,它负责与 RabbitMQ 服务器建立连接。通常,Spring Boot 默认使用 CachingConnectionFactory 来实现连接工厂。

@Bean
@Primary
@ConditionalOnMissingBean(ConnectionFactory.class)
public CachingConnectionFactory connectionFactory() {CachingConnectionFactory connectionFactory = new CachingConnectionFactory();connectionFactory.setHost(rabbitProperties.getHost());connectionFactory.setPort(rabbitProperties.getPort());connectionFactory.setUsername(rabbitProperties.getUsername());connectionFactory.setPassword(rabbitProperties.getPassword());connectionFactory.setVirtualHost(rabbitProperties.getVirtualHost());return connectionFactory;
}
  • @ConditionalOnMissingBean 表示如果应用上下文中没有 ConnectionFactory 的 Bean,Spring Boot 会创建一个默认的 CachingConnectionFactory
  • 配置的 spring.rabbitmq.* 参数将被注入到这个 ConnectionFactory 中。
3.2 自动配置 RabbitTemplate

RabbitTemplate 是 Spring AMQP 用来发送消息的核心类。Spring Boot 会自动配置一个 RabbitTemplate,它使用 ConnectionFactory 来与 RabbitMQ 服务器进行交互。

@Bean
@ConditionalOnMissingBean(RabbitTemplate.class)
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate template = new RabbitTemplate(connectionFactory);template.setMessageConverter(new Jackson2JsonMessageConverter());return template;
}
  • RabbitTemplate 被用来发送消息,Spring Boot 自动创建并配置。
  • 默认使用 JSON 消息转换器(Jackson2JsonMessageConverter)将消息转换为 JSON 格式。
3.3 自动配置 RabbitListenerContainerFactory

如果你想使用 @RabbitListener 注解来监听 RabbitMQ 消息队列,Spring Boot 会自动配置 RabbitListenerContainerFactory

@Bean
@ConditionalOnMissingBean(RabbitListenerContainerFactory.class)
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory, RabbitProperties rabbitProperties) {SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();factory.setConnectionFactory(connectionFactory);factory.setConcurrency(rabbitProperties.getListener().getSimple().getConcurrency());factory.setMaxConcurrency(rabbitProperties.getListener().getSimple().getMaxConcurrency());return factory;
}
  • 这个工厂用于创建 RabbitMQ 消息监听容器,容器负责消费队列中的消息。
  • setConcurrency 和 setMaxConcurrency 用来配置消息消费者的并发数。
3.4 自动配置消息监听器(@RabbitListener

Spring Boot 会自动启用对 @RabbitListener 注解的支持。你可以使用 @RabbitListener 注解创建消息监听器,而无需手动配置监听容器。

4. 创建消费者和生产者

4.1 消息生产者(发送消息)

你可以使用 RabbitTemplate 发送消息到 RabbitMQ 队列。

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class MessageProducer {@Autowiredprivate RabbitTemplate rabbitTemplate;public void sendMessage(String message) {rabbitTemplate.convertAndSend("myQueue", message);}
}
  • rabbitTemplate.convertAndSend 方法用于将消息发送到指定的队列(myQueue)。
  • Spring Boot 会自动为你配置队列、交换机、路由等。
4.2 消息消费者(监听消息)

你可以使用 @RabbitListener 注解来创建消息消费者,监听指定的队列,并在消息到达时处理它。

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;@Service
public class MessageConsumer {@RabbitListener(queues = "myQueue")public void receiveMessage(String message) {System.out.println("Received message: " + message);}
}
  • @RabbitListener 注解会告诉 Spring Boot 自动创建一个消息监听器并连接到指定的队列。
  • 每当有消息进入 myQueue 队列时,receiveMessage 方法就会被调用。

5. 自定义配置

你可以进一步自定义 RabbitMQ 的配置,以下是一些常见的自定义场景:

5.1 配置交换机、队列和绑定

你可以定义自己的交换机、队列和绑定,确保它们符合你的应用需求。例如:

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitConfig {@Beanpublic Queue myQueue() {return new Queue("myQueue", true);}@Beanpublic TopicExchange exchange() {return new TopicExchange("myExchange");}@Beanpublic Binding binding(Queue myQueue, TopicExchange exchange) {return BindingBuilder.bind(myQueue).to(exchange).with("myQueue.#");}
}
  • Queue 定义了一个消息队列。
  • TopicExchange 定义了一个交换机。
  • Binding 定义了队列和交换机之间的绑定关系。
5.2 配置消息监听器的并发

你可以通过 application.propertiesapplication.yml 来调整消息监听器的并发配置:

spring.rabbitmq.listener.simple.concurrency=5
spring.rabbitmq.listener.simple.max-concurrency=10

这将允许 Spring Boot 动态调整消费者线程的数量,确保队列消息能够高效消费。

总结

Spring Boot 通过自动配置 RabbitMQ 连接、消息发送和消费等相关组件,极大地简化了 RabbitMQ 的集成过程。只需添加 spring-boot-starter-amqp 依赖并在配置文件中指定必要的参数,Spring Boot 就会自动配置所需的所有组件,并根据需求自动启动消息生产者和消费者。你可以通过注解 @RabbitListener 来定义消息监听器,也可以自定义交换机、队列和绑定等配置,从而满足不同的业务需求。

通过源码再次,详细说明

要深入了解 Spring Boot 如何通过自动配置集成 RabbitMQ,我们需要通过源码分析它是如何工作的。Spring Boot 使用了 spring-boot-starter-amqp 来简化 RabbitMQ 的配置。以下是从源代码角度对 Spring Boot 如何自动配置 RabbitMQ 进行详细说明的过程。

1. Spring Boot 启动流程和自动配置

Spring Boot 使用了 @EnableAutoConfiguration 注解和 spring.factories 文件来实现自动配置。在启动时,Spring Boot 会扫描并自动配置与应用上下文相关的配置类。RabbitMQ 的自动配置就是通过这些配置类实现的。

1.1 spring-boot-starter-amqp 依赖

首先,spring-boot-starter-amqp 依赖包含了 Spring AMQP 和 RabbitMQ 的集成依赖,并提供了 RabbitMQ 自动配置的支持。它的 spring.factories 文件列出了与 RabbitMQ 相关的自动配置类。

spring-boot-starter-amqp 中,spring.factories 文件会自动引入 RabbitAutoConfiguration 类。你可以在 spring-boot-starter-amqp 依赖中看到这一点:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

当你引入了这个依赖后,Spring Boot 会自动加载 RabbitMQ 的相关配置。

2. RabbitAutoConfiguration 类

Spring Boot 的 RabbitMQ 自动配置类是 RabbitAutoConfiguration,它位于 org.springframework.boot.autoconfigure.amqp 包中。这个类的作用是基于你的配置自动设置 RabbitMQ 连接、队列、交换机等。

我们来分析一下 RabbitAutoConfiguration 类的源码:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CachingConnectionFactory.class)
@ConditionalOnProperty(prefix = "spring.rabbitmq", name = "host")
@EnableConfigurationProperties(RabbitProperties.class)
@Import({ RabbitListenerConfiguration.class, RabbitManagementConfigurer.class })
public class RabbitAutoConfiguration {private static final Logger logger = LoggerFactory.getLogger(RabbitAutoConfiguration.class);private final RabbitProperties properties;public RabbitAutoConfiguration(RabbitProperties properties) {this.properties = properties;}@Bean@ConditionalOnMissingBean(ConnectionFactory.class)public CachingConnectionFactory connectionFactory() {logger.debug("Creating CachingConnectionFactory");CachingConnectionFactory factory = new CachingConnectionFactory();factory.setHost(this.properties.getHost());factory.setPort(this.properties.getPort());factory.setUsername(this.properties.getUsername());factory.setPassword(this.properties.getPassword());factory.setVirtualHost(this.properties.getVirtualHost());return factory;}@Bean@ConditionalOnMissingBean(RabbitTemplate.class)public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());return rabbitTemplate;}@Bean@ConditionalOnMissingBean(SimpleRabbitListenerContainerFactory.class)public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory, RabbitProperties rabbitProperties) {SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();factory.setConnectionFactory(connectionFactory);factory.setConcurrency(rabbitProperties.getListener().getSimple().getConcurrency());factory.setMaxConcurrency(rabbitProperties.getListener().getSimple().getMaxConcurrency());return factory;}
}

2.1 @Configuration 和 @EnableConfigurationProperties

  • @Configuration(proxyBeanMethods = false):这是一个配置类,proxyBeanMethods = false 表示这个配置类不会使用代理,也就是说,它只会影响当前类中定义的 bean。
  • @EnableConfigurationProperties(RabbitProperties.class):该注解使得 RabbitProperties 类成为一个配置属性类,允许 Spring Boot 自动加载配置文件中的 spring.rabbitmq.* 属性,并将它们绑定到 RabbitProperties 对象。

2.2 connectionFactory Bean

@Bean
@ConditionalOnMissingBean(ConnectionFactory.class)
public CachingConnectionFactory connectionFactory() {CachingConnectionFactory factory = new CachingConnectionFactory();factory.setHost(this.properties.getHost());factory.setPort(this.properties.getPort());factory.setUsername(this.properties.getUsername());factory.setPassword(this.properties.getPassword());factory.setVirtualHost(this.properties.getVirtualHost());return factory;
}
  • @ConditionalOnMissingBean(ConnectionFactory.class):这表示如果应用上下文中没有 ConnectionFactory 类型的 Bean,Spring Boot 会自动创建一个 CachingConnectionFactory 的实例。CachingConnectionFactory 是 Spring AMQP 提供的一个连接工厂实现,它能缓存到 RabbitMQ 的连接以提高性能。
  • factory.setHost 等:这些配置项通过 RabbitProperties 类从 application.properties 或 application.yml 中读取并注入。

2.3 rabbitTemplate Bean

@Bean
@ConditionalOnMissingBean(RabbitTemplate.class)
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());return rabbitTemplate;
}
  • @ConditionalOnMissingBean(RabbitTemplate.class):如果 RabbitTemplate 已经存在于应用上下文中,Spring Boot 就不会再次创建它。
  • RabbitTemplate:它是与 RabbitMQ 交互的核心类,主要用于发送消息。Spring Boot 会自动创建并配置 RabbitTemplate,并将其与上面创建的 ConnectionFactory 关联。

2.4 rabbitListenerContainerFactory Bean

@Bean
@ConditionalOnMissingBean(SimpleRabbitListenerContainerFactory.class)
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory, RabbitProperties rabbitProperties) {SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();factory.setConnectionFactory(connectionFactory);factory.setConcurrency(rabbitProperties.getListener().getSimple().getConcurrency());factory.setMaxConcurrency(rabbitProperties.getListener().getSimple().getMaxConcurrency());return factory;
}
  • SimpleRabbitListenerContainerFactory:这是一个用来创建 RabbitMQ 消息监听容器的工厂。该容器负责从 RabbitMQ 中接收并处理消息。
  • setConcurrency 和 setMaxConcurrency:这两个方法控制监听器的并发性,指定了消息监听的最小和最大并发数。

3. RabbitListenerConfiguration 和 RabbitManagementConfigurer

RabbitAutoConfiguration 类还通过 @Import 注解引入了 RabbitListenerConfigurationRabbitManagementConfigurer 类。这些类负责配置消息监听器和管理接口等。

 

java

@Import({ RabbitListenerConfiguration.class, RabbitManagementConfigurer.class })

  • RabbitListenerConfiguration:负责配置和启用 @RabbitListener 注解的处理。
  • RabbitManagementConfigurer:负责 RabbitMQ 管理的配置,通常是为了启用或配置 RabbitMQ 管理界面。

4. RabbitProperties 类

RabbitProperties 类是用来封装 application.propertiesapplication.yml 中与 RabbitMQ 相关的配置项的。它的主要作用是将这些配置绑定到 Java 对象上,方便后续使用。

@ConfigurationProperties(prefix = "spring.rabbitmq")
public class RabbitProperties {private String host = "localhost";private int port = 5672;private String username = "guest";private String password = "guest";private String virtualHost = "/";private Listener listener = new Listener();public static class Listener {private Simple simple = new Simple();public static class Simple {private int concurrency = 1;private int maxConcurrency = 1;}}// getters and setters
}

RabbitProperties 是一个 POJO 类,Spring Boot 会将 application.properties 中以 spring.rabbitmq.* 开头的属性自动映射到这个类的字段中。

5. @RabbitListener 注解支持

Spring Boot 自动配置还会启用 @RabbitListener 注解的支持,这意味着你可以通过注解驱动的方式来创建 RabbitMQ 消息监听器。例如:

@Service
public class MyListener {@RabbitListener(queues = "myQueue")public void handleMessage(String message) {System.out.println("Received message: " + message);}
}

6. 总结

通过 RabbitAutoConfiguration,Spring Boot 自动配置了与 RabbitMQ 交互所需的主要组件:ConnectionFactoryRabbitTemplateSimpleRabbitListenerContainerFactory 等。这些组件的创建是基于 application.properties 中的配置完成的。通过 Spring Boot 的自动配置,开发者只需要添加必要的依赖和配置,不必手动创建和配置这些复杂的 RabbitMQ 组件。

自动配置总结

  • ConnectionFactory:用于连接到 RabbitMQ 服务。
  • RabbitTemplate:用于发送消息。
  • SimpleRabbitListenerContainerFactory:用于配置消息监听容器。
  • RabbitListener 注解:用于处理消息监听。

RabbitAutoConfiguration 源码 1.5.9版本

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.boot.autoconfigure.amqp;import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties.Retry;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties.Ssl;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties.Template;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;@Configuration
@ConditionalOnClass({RabbitTemplate.class, Channel.class})
@EnableConfigurationProperties({RabbitProperties.class})
@Import({RabbitAnnotationDrivenConfiguration.class})
public class RabbitAutoConfiguration {public RabbitAutoConfiguration() {}@Configuration@ConditionalOnClass({RabbitMessagingTemplate.class})@ConditionalOnMissingBean({RabbitMessagingTemplate.class})@Import({RabbitAutoConfiguration.RabbitTemplateConfiguration.class})protected static class MessagingTemplateConfiguration {protected MessagingTemplateConfiguration() {}@Bean@ConditionalOnSingleCandidate(RabbitTemplate.class)public RabbitMessagingTemplate rabbitMessagingTemplate(RabbitTemplate rabbitTemplate) {return new RabbitMessagingTemplate(rabbitTemplate);}}@Configuration@Import({RabbitAutoConfiguration.RabbitConnectionFactoryCreator.class})protected static class RabbitTemplateConfiguration {private final ObjectProvider<MessageConverter> messageConverter;private final RabbitProperties properties;public RabbitTemplateConfiguration(ObjectProvider<MessageConverter> messageConverter, RabbitProperties properties) {this.messageConverter = messageConverter;this.properties = properties;}@Bean@ConditionalOnSingleCandidate(ConnectionFactory.class)@ConditionalOnMissingBean({RabbitTemplate.class})public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);MessageConverter messageConverter = (MessageConverter)this.messageConverter.getIfUnique();if (messageConverter != null) {rabbitTemplate.setMessageConverter(messageConverter);}rabbitTemplate.setMandatory(this.determineMandatoryFlag());Template templateProperties = this.properties.getTemplate();Retry retryProperties = templateProperties.getRetry();if (retryProperties.isEnabled()) {rabbitTemplate.setRetryTemplate(this.createRetryTemplate(retryProperties));}if (templateProperties.getReceiveTimeout() != null) {rabbitTemplate.setReceiveTimeout(templateProperties.getReceiveTimeout());}if (templateProperties.getReplyTimeout() != null) {rabbitTemplate.setReplyTimeout(templateProperties.getReplyTimeout());}return rabbitTemplate;}private boolean determineMandatoryFlag() {Boolean mandatory = this.properties.getTemplate().getMandatory();return mandatory != null ? mandatory : this.properties.isPublisherReturns();}private RetryTemplate createRetryTemplate(Retry properties) {RetryTemplate template = new RetryTemplate();SimpleRetryPolicy policy = new SimpleRetryPolicy();policy.setMaxAttempts(properties.getMaxAttempts());template.setRetryPolicy(policy);ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();backOffPolicy.setInitialInterval(properties.getInitialInterval());backOffPolicy.setMultiplier(properties.getMultiplier());backOffPolicy.setMaxInterval(properties.getMaxInterval());template.setBackOffPolicy(backOffPolicy);return template;}@Bean@ConditionalOnSingleCandidate(ConnectionFactory.class)@ConditionalOnProperty(prefix = "spring.rabbitmq",name = {"dynamic"},matchIfMissing = true)@ConditionalOnMissingBean({AmqpAdmin.class})public AmqpAdmin amqpAdmin(ConnectionFactory connectionFactory) {return new RabbitAdmin(connectionFactory);}}@Configuration@ConditionalOnMissingBean({ConnectionFactory.class})protected static class RabbitConnectionFactoryCreator {protected RabbitConnectionFactoryCreator() {}@Beanpublic CachingConnectionFactory rabbitConnectionFactory(RabbitProperties config) throws Exception {RabbitConnectionFactoryBean factory = new RabbitConnectionFactoryBean();if (config.determineHost() != null) {factory.setHost(config.determineHost());}factory.setPort(config.determinePort());if (config.determineUsername() != null) {factory.setUsername(config.determineUsername());}if (config.determinePassword() != null) {factory.setPassword(config.determinePassword());}if (config.determineVirtualHost() != null) {factory.setVirtualHost(config.determineVirtualHost());}if (config.getRequestedHeartbeat() != null) {factory.setRequestedHeartbeat(config.getRequestedHeartbeat());}Ssl ssl = config.getSsl();if (ssl.isEnabled()) {factory.setUseSSL(true);if (ssl.getAlgorithm() != null) {factory.setSslAlgorithm(ssl.getAlgorithm());}factory.setKeyStore(ssl.getKeyStore());factory.setKeyStorePassphrase(ssl.getKeyStorePassword());factory.setTrustStore(ssl.getTrustStore());factory.setTrustStorePassphrase(ssl.getTrustStorePassword());}if (config.getConnectionTimeout() != null) {factory.setConnectionTimeout(config.getConnectionTimeout());}factory.afterPropertiesSet();CachingConnectionFactory connectionFactory = new CachingConnectionFactory((com.rabbitmq.client.ConnectionFactory)factory.getObject());connectionFactory.setAddresses(config.determineAddresses());connectionFactory.setPublisherConfirms(config.isPublisherConfirms());connectionFactory.setPublisherReturns(config.isPublisherReturns());if (config.getCache().getChannel().getSize() != null) {connectionFactory.setChannelCacheSize(config.getCache().getChannel().getSize());}if (config.getCache().getConnection().getMode() != null) {connectionFactory.setCacheMode(config.getCache().getConnection().getMode());}if (config.getCache().getConnection().getSize() != null) {connectionFactory.setConnectionCacheSize(config.getCache().getConnection().getSize());}if (config.getCache().getChannel().getCheckoutTimeout() != null) {connectionFactory.setChannelCheckoutTimeout(config.getCache().getChannel().getCheckoutTimeout());}return connectionFactory;}}
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/502060.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025/1/4期末复习 密码学 按老师指点大纲复习

我们都要坚信&#xff0c;道路越是曲折&#xff0c;前途越是光明。 --------------------------------------------------------------------------------------------------------------------------------- 现代密码学 第五版 杨波 第一章 引言 1.1三大主动攻击 1.中断…

Vulnhub靶场(Earth)

项目地址 https://download.vulnhub.com/theplanets/Earth.ova.torrent 搭建靶机 官网下载.ova文件双击vm打开导入 获取靶机IP kail终端输入 arp-scan -l 获取靶机 IP 192.168.131.184 信息收集 端口扫描 sudo nmap -sC -sV -p- 192.168.131.184 可以看到开启22端口&…

Linux菜鸟级常用的基本指令和基础知识

前言:很多Linux初学者都会头疼于指令太多记不住&#xff0c;笔者刚学习Linux时也是如此&#xff0c;学习Linux指令时&#xff0c;学了后面的指令&#xff0c;前面的指令也会忘的差不多了&#xff0c;针对于以上这些情况&#xff0c;笔者今天来分享一篇Linux菜鸟级的常用指令的博…

使用SSH建立内网穿透,能够访问内网的web服务器

搞了一个晚上&#xff0c;终于建立了一个内网穿透。和AI配合&#xff0c;还是得自己思考&#xff0c;AI配合才能搞定&#xff0c;不思考只依赖AI也不行。内网服务器只是简单地使用了python -m http.server 8899&#xff0c;但是对于Gradio建立的服务器好像不行&#xff0c;会出…

2024年1月4日蜻蜓hr人才招聘系统v1.1.7更新-正式版发布-客户端源代码开源发布供学习-本产品完成上线正式版-修复多个bug-优雅草果果|小无

2024年1月4日蜻蜓hr人才招聘系统v1.1.7更新-正式版发布-客户端源代码开源发布供学习-本产品完成上线正式版-修复多个bug-优雅草果果|小无 前端代码开源库 关于开源说明&#xff1a;企业服务-招聘信息管理系统-前端uniapp-系统前端开放源代码仅供学习-优雅草科技-目前优雅草科…

HTML——75. 内联框架

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>内联框架</title><style type"text/css">iframe{width: 100%;height: 500px;}</style></head><body><!--iframe元素会创建包含…

Ajax原理-XMLHttpRequest

1. XMLHttpRequest 是什么&#xff1f; 和axios的关系&#xff1a; axios 内部采用 XMLHttpRequest 与服务器交互 学习XMLHttpRequest的目的&#xff1a; 掌握使用 XHR 与服务器进行数据交互&#xff0c;了解 axios 内部原理&#xff0c;加强对知识的理解&#xff0c;提升技…

离散数学 期末笔记

命题符号化 使用等值演算法证明 求公式范式 在自然推理体系中构造下列推理的证明 在一阶逻辑中将下列命题符号化 设A、B、C、D是 Z 的子集 证明下列集合恒等式 二元关系 性质 没有空的 没有漏的 没有重复 函数

Fabric环境部署-Git和Node安装

一.安装Git&#xff08;v2.43.0&#xff09; Git 是一个开源的分布式版本管理系统&#xff08;也是全球最大的开源软件存储服务器&#xff09;&#xff0c;用于敏捷高效地处理任何或小或大的项目。搭建区块链需要使用Git&#xff0c;因为区块链的开发和部署需要使用版本控制工…

springCloud 脚手架项目功能模块:Java分布式锁

文章目录 引言分布式锁产生的原因:集群常用的分布式锁分布式锁的三种实现方式I ZooKeeper 简介zookeeper本质上是一个分布式的小文件存储系zookeeper特性:全局数据一致性ZooKeeper的应用场景分布式锁(临时节点)II 基于ZooKeeper 实现一个排他锁创建锁获取锁释放锁Apache Zo…

stm32入门元件介绍

stm32入门元件介绍 文章目录 stm32入门元件介绍入门套件总览套件介绍面包板面包板跳线/飞线杜邦线STM32最小系统板STLINKOLED显示屏LED按键电位器蜂鸣器光敏/热敏电阻传感器/对射式/反射式红外传感器旋转编码器USB转串口MPU6050陀螺仪加速度计W25Q64 Flash闪存TB6612FNG电机驱动…

C语言:调试的概念和调试器的选择

所谓调试&#xff08;Dubug&#xff09;&#xff0c;就是跟踪程序的运行过程&#xff0c;从而发现程序的逻辑错误&#xff08;思路错误&#xff09;&#xff0c;或者隐藏的缺陷&#xff08;Bug&#xff09;。 在调试的过程中&#xff0c;我们可以监控程序的每一个细节&#xff…

Python深度学习GRU、LSTM 、BiLSTM-CNN神经网络空气质量指数AQI时间序列预测及机器学习分析|数据分享...

全文链接&#xff1a;https://tecdat.cn/?p38742 分析师&#xff1a;Zhixiong Weng 人们每时每刻都离不开氧&#xff0c;并通过吸入空气而获得氧。一个成年人每天需要吸入空气达6500升以获得足够的氧气&#xff0c;因此&#xff0c;被污染了的空气对人体健康有直接的影响&…

Flink源码编译与运行

1 准备 准备好Java 8环境和编译器&#xff08;如IDEA&#xff09;。 下载源码&#xff1a; 官网&#xff1a;https://flink.apache.org/downloads/。GitHub&#xff1a;https://github.com/apache/flink。 2 编译 在IDEA终端&#xff0c;使用下面命令之一编译源码&#xff…

Elasticsearch:Lucene 2024 年回顾

作者&#xff1a;来自 Elastic Chris Hegarty 2024 年对于 Apache Lucene 来说又是重要的一年。在本篇博文中&#xff0c;我们将探讨主要亮点。 Apache Lucene 在 2024 年表现出色&#xff0c;发布了许多版本&#xff0c;包括三年来的首次重大更新&#xff0c;其中包含令人兴奋…

(四)基于STM32通过Event Recoder实现时间测量功能

目录 1. 了解Event Recorder 2. 硬件和软件准备 硬件需求 软件需求 3. 配置STM32工程 使用STM32CubeMX初始化项目 配置Event Recorder 4. 实现时间记录功能 初始化Event Recorder 时间间隔计算 配置Debug选项 测量结果查看 5总结 在嵌入式系统开发中&#xff0c;精…

Java 内存溢出(OOM)问题的排查与解决

在 Java 开发中&#xff0c;内存溢出&#xff08;OutOfMemoryError&#xff0c;简称 OOM&#xff09;是一个常见且棘手的问题。相比于数组越界、空指针等业务异常&#xff0c;OOM 问题通常更难定位和解决。本文将通过一次线上内存溢出问题的排查过程&#xff0c;分享从问题表现…

Python、R用深度学习神经网络组合预测优化能源消费总量时间序列预测及ARIMA、xgboost对比...

全文链接&#xff1a;https://tecdat.cn/?p38726 分析师&#xff1a;Qingxia Wang 在能源领域&#xff0c;精准预测能源消费总量对制定合理能源战略至关重要。当前&#xff0c;能源消费预测分析主要运用单一模型&#xff08;如灰色预测法、时间序列分析法等&#xff09;和组合…

【LLM-Agent】Building effective agents和典型workflows

note Anthropic的工程经验&#xff1a; 大道至简&#xff0c;尽量维护系统的简洁&#xff1b;尽量让过程更加透明&#xff08;因为你依赖的是LLM的决策&#xff0c;如果只看输出不看过程&#xff0c;很容易陷入难以debug的情况&#xff09;&#xff1b;对LLM需要调用的工具&am…

音视频入门基础:MPEG2-PS专题(4)——FFmpeg源码中,判断某文件是否为PS文件的实现

一、引言 通过FFmpeg命令&#xff1a; ./ffmpeg -i XXX.ps 可以判断出某个文件是否为PS文件&#xff1a; 所以FFmpeg是怎样判断出某个文件是否为PS文件呢&#xff1f;它内部其实是通过mpegps_probe函数来判断的。从《FFmpeg源码&#xff1a;av_probe_input_format3函数和AVI…