# @SpringBootApplication
#
@SpringBootConfiguration
@Configuration
#
@EnableAutoConfiguration
#
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
# 自动配置
# 依赖管理与版本仲裁
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version>
</parent>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.8.RELEASE</version>
</parent>
如需更换依赖版本号,在当前项目中通过<properties></properties>
标签指定即可(maven就近优先原则)
# 自定义组件扫描与场景启动器配置
# @EnableAutoConfiguration
#
@AutoConfigurationPackage
@Import(AutoConfigurationPackages.Registrar.class)
默认将主程序类所在包及其子包内所有组件扫描进Spring容器;如需扩大包扫描层级范围,需通过
@SpringBootApplication(scanBasePackages="com.xxx")
进行指定// AutoConfigurationPackages.class /** * {@link ImportBeanDefinitionRegistrar} to store the base package from the importing configuration. */ static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0])); } @Override public Set<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new PackageImports(metadata)); } }
#
@Import(EnableAutoConfigurationImportSelector.class)
public class AutoConfigurationImportSelector implements DeferredImportSelector { @Override public String[] selectImports(AnnotationMetadata metadata) { List<String> Configurations = getCandidateConfigurations(metadata, attributes); // 获取所有可能加入容器的EnableAutoConfiguration } // ... protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { if(!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = this.getAttributes(annotationMetadata); List<String> Configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass()/*此处的类加载器为AppClassLoader*/, gerBeanClassLoader()); configurations = this.removeDuplicates(configurations); Set<String> exclusions = this.getExclusions(annotationMetadata, attributes); this.checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = this.filter(configurations, autoConfigurationMetadata); this.fireAutoConfigurationImportEvents(configurations, exclusions); return StringUtils.toStringArray(configurations); } } }
# 自动配置核心流程
// SpringFactoriesLoader.class public static list<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { // ... Enumeration ex = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); // 从类路径(spring-boot-autoconfigure-xxx-RELEASE)下META-INFO/spring.factories文件中获取org.springframework.boot.autoconfigure.EnableAutoConfiguration所对应的组件(配置类)key值,最终通过反射对配置类中的组件进行实例化 }
# 启动流程
# SpringBoot 1.x
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
// SpringApplication.class
public SpringApplication(Object... sources) {
initialize(sources);
}
// ...
private void initialize(Object[] sources) {
// SpringApplication.getSpringFactoriesInstances(...):
// 从类路径(spring-boot-autoconfigure-xxx-RELEASE)下META-INFO/spring.factories文件中获取所有的ApplicationContextInitializer和所有的ApplicationListener;两者都不需要手动加入容器,而只需在classpath:/META-INF/spring.factories中进行配置(ApplicationRunner需手动加入容器)
// 定位main()方法
}
# 运行流程
# SpringBoot 1.x
// SpringApplication.class
public ConfigurableApplicationContext run(String... args) {
Stopwatch stopwatch = new Stopwatch();
stopwatch.start();
ConfigurableApplicationContext context = null;
// ...
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(); // 回调所有SpringApplicationRunListener监听器的starting()方法
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 封装命令行参数
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 1. getOrCreateEnvironment() 2. configureEnvironment(environment, args) 3. listeners.environmentPrepared(environment)
Banner banner = printBanner(environment);
context = createApplicationContext();
}
// ...
prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 1. context.setEnvironment(environment) 2. postProcessApplicationContext(context) 向容器注册附加组件 3. applyInitializers(context) 依次执行所有ApplicationContextInitializer的initialize(ConfigurableApplicationContext)方法 3. listeners.contextPrepared(context) 4. context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments) 5. load(context, sources.toArray(new Object[sources.size()])) 向ConfigurableApplicationContext加载sources(主类信息) 6. listeners.contextLoaded(context);
refreshContext(context); // 自动扫描、创建、加载容器内所有组件(包括内嵌Servlet容器)
afterRefresh(context, applicationArguments); // 获取容器中所有的ApplicationRunner及CommandLineRunner,并传入args进行回调
listeners.finished(context, null);
stopwatch.stop();
// ...
return context;
}
# 自定义Starters
xxx-starter
只用于pom文件中所需依赖的导入,而前者引入的xxx-starter-autoconfigurer
真正负责依赖注入过程
# xxx-starter-autoconfigurer
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
public class AbcService(...) {
private AbcProperties properties;
public AbcProperties getAbcProperties() {
return properties;
}
// IoC
public void setAbcProperties(AbcProperties properties) {
this.properties = properties;
}
public AbcService() {
// ...
}
// ...
}
@ConfigurationProperties(abc = "abc")
public class AbcProperties {
private String abc;
// ...
}
@Configuration
@ConditionalOnXXX
@EnableConfigurationProperties(AbcProperties.class)
public class AbcAutoConfiguration {
@Autowired
private AbcProperties properties;
@Bean
public AbcService abcService() {
AbcService abcService = new AbcService();
abcService.setAbcProperties(properties);
return abcService;
}
}
# classpath:META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
xxx.AbcAutoConfiguration
# 自定义配置
# 自定义配置类并与配置文件绑定
@ConfigurationProperties(prefix = "xxx.yyy")
@Data
@Component
public class XXXConfiguration {
// 需在配置文件中使用的属性
}
# 使用自定义配置文件所配置属性
// @EnableConfigurationProperties(XXXConfiguration.class) // 因XXXConfiguration已加入容器,故无需再次声明
@Configuration
public class AAAConfiguration {
@Bean
public SomeClass someClass(XXXConfiguration config) {
// 使用config属性(即配置文件中所配置的值)进行进一步属性注入
}
}
# Web
# WebMvcAutoConfiguration
@Configuration(proxyBeanMethods = false)
// @Configuration // 1.x
@ConditionalOnWebApplication(type = Type.SERVLET)
// @ConditionalOnWebApplication // 1.x
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
// @AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class}) // 1.x
public class WebMvcAutoConfiguration {
// ...
}
# SpringBoot
对Spring MVC
的自动配置
# 自动配置了
ContentNegotiatingViewResolver
以及BeanNameViewResolver
// ContentNegotiatingViewResolver.class
@Override
protected void initServletContext(ServletContext context) {
Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncesters(getApplicationContext(), ViewResolver.class).values(); // 获取容器中所有的ViewResolver(并组合)
// ...
}
# 静态资源相关配置
#
前后端耦合架构下静态资源映射规则(SpringBoot 1.x)// ResourceProperties.java @ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false) public class ResourceProperties implements ResourceLoaderAware { // 设置与静态资源相关的参数,以便在配置文件中进行配置 }
#
静态资源默认映射路径// WebMvcAutoConfiguration.java @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // ... registry.addResourceHandler("/webjars/**") .addResourceLocation("classpath:/META-INF/resources/webjars/"); // 配置webjars静态资源映射 // ... registry.addResourceHandler(staticPathPattern) // 默认为"/**" .addResourceLocation(this.resourceProperties.getStaticLocations) // (在配置文件中指定静态资源路径后)在此配置路径映射:spring.resources.static.locations:"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/" }
#
欢迎页面默认映射路径遍历所有静态资源路径,映射第一个index.html#
HiddenHttpMethodFilter
支持RESTful请求
#
Formatter
及Converter
@ConditionalOnProperty(prefix="spring.mvc", name="xxx")
// WebMvcAutoConfiguration.java @Override public void addFormatters(FormatterRegistry registry) { ApplicationConversionService.addBeans(registry, this.beanFactory); // 容器中各类GenericConverter/Converter/Formatter/Printer/Parser在ApplicationConversionService中自动配置 }
DateFormatter
SpringBoot 2.x已废弃,==日期格式化工具配置可参考
FormattingConversionService
==HttpMessageConverters
处理响应体字符编码;如需自定义消息转换器,可手动在容器中加入
HttpMessageConverters
(==SpringBoot 2.x中如何手动配置==)SpringBoot 2.x中,不再直接配置
messageConverters
,改为配置messageConvertersProvider
// WebMvcAutoConfiguration.java @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { this.messageConvertersProvider.ifAvailable((customConverters) -> converters.addAll(customConverters.getConverters())); }
#
MessageCodesResolver
定义HTTP状态码生成规则
#
ConfigurableWebBindingInitializer
将(非
@RequestBody
)请求参数封装为POJO
# 自定义Spring MVC
配置类
SpringBoot 2.x新增
// 配置视图映射
@Configuration
public class CustomMvcConfiguration extends WebMvcConfigurationSupport {
@Override
protected void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/xxx").addViewName("yyy");
}
@Override
protected void addResourceHandlers(ViewControllerRegistry registry) {
// 添加自定义静态资源映射
}
@Override
protected void addInterceptors(ViewControllerRegistry registry) {
// 添加自定义拦截器(需要排除静态资源)
}
}
# EnableWebMvcConfiguration
(内部类WebMvcAutoConfigurationAdapter
的@Import
依赖类)
// DelegatingWebMvcConfiguration.class (EnableWebMvcConfiguration父类,WebMvcConfigurationSupport子类)
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers); // 调用容器中所有WebMvcConfigurer实现类的addViewControllers(ViewControllerRegistry)方法
}
}
若在配置类上标注
@EnableWebMvc
,则将全面接管Spring MVC
的自动配置
# ErrorMvcAutoConfiguration
DefaultErrorAttributes
为
ModelAndView
对象(或响应体)传递异常信息:public Map<String, Object> getErrorAttributes(RequestAttributes attr, boolean includesStackTrace) { Map<String, Object> errorAttributes = new LinkedHashMap<>(); errorAttributes.put("timestamp", new Date()); addStatus(errorAttributes, requestAttributes); addErrorDetails(errorAttributes, requestAttributes, includesStackTrace); addPath(errorAttributes, requestAttributes); return errorAttributes; }
SpringBoot 2.x中该方法参数为
WebRequest
的子类WebRequest
ErrorPageCustomizer
void registerErrorPages(ErrorPageRegistry); // 给容器添加错误页面请求映射(默认为/error)
BasicErrorController
处理ErrorPageCustomizer
注册的错误页面请求
DefaultErrorViewResolver
ModelAndView resolveErrorView(HttpServletRequest, HttpStatus, Model); // 解析HTTP状态码和model数据,返回ModelAndView对象
给浏览器响应页面:
调用
DefaultErrorViewResolver
返回ModelAndView
对象或默认的DefaultErrorView
(SpelView
默认错误页面,对应/error
视图)给其他客户端响应JSON数据:
# 定制错误页面
- 项目依赖模板引擎:
classpath:/templates/error/4xx.html
- 项目不依赖模板引擎:
classpath:/static/error/4xx.html
# 定制错误响应
- (错误信息完全由前端框架处理)自定义
@ExceptionHandler
方法,返回JSON数据 - (错误信息由SpringBoot自行处理)自定义
@ExceptionHandler
方法,转发至/error
请求(或自定义错误页面请求) - (如需给浏览器返回后端渲染的错误页面)在
request
域中自定义"javax.servlet.error.status_code"
属性,赋值为错误状态码,即可通过DefaultErrorViewResolver.resolveErrorView(...)
方法定位自定义错误页面- (扩展JSON属性)重写
DefaultErrorAttributes.getErrorAttributes(RequestAttributes)
方法
- (扩展JSON属性)重写
# 嵌入式Servlet
容器
配置文件(如配置文件中的
server.xxx
属性)@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered { // ... } // SpringBoot 2.x中对应WebServerProperties.class
配置类(
EmbeddedServletContainerCustomizer
,或SpringBoot 2.x中的WebServerFactoryCustomizer<ConfigurableWebServerFactory>
)
# 嵌入式Servlet
容器自动配置原理
# SpringBoot 1.x
# EmbeddedServletContainerAutoConfiguration
//@...
@Import(BeanPostProcessorRegistrar.class) // 向容器中导入EmbeddedServletContainerCustomizerBeanPostProcessor,遍历执行容器中所有EmbeddedServletContainerCustomizer.customize(...)方法
public class EmbeddedServletContainerAutoConfiguration {
// 根据容器中Servlet容器工厂类型,初始化特定的XXXEmbeddedServletContainerFactory工厂
}
配置内嵌Servlet容器的基本环境,并最终启动该容器
实现
EmbeddedServletContainerFactory
接口,在EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer...)
方法中对内嵌Servlet
容器的基本环境进行配置
# SpringBoot 2.x
# ServletWebServerFactoryAutoConfiguration
或实现
ServletWebServerFactory
接口,重写WebServer getWebServer(ServletContextInitializer...)
方法
# 嵌入式Servlet
容器启动原理
SpringApplication.class
public static ConfigurableApplicationContext run(Object[] sources, String[] args) { return new SpringApplication(sources).run(args); } // ... public ConfigurableApplicationContext run(String... args) { // ... ConfigurableApplicationContext context = createApplicationContext(); // ... refreshContext(context); // ... } // ... protected ConfigurableApplicationContext createApplicationContext() { // 如果需要创建Web容器,则初始化AnnotationConfigEmbeddedWebApplicationContext,否则初始化AnnotationConfigApplicationContext } // ... private void refreshContext(ConfigurableApplicationContext context) { refresh(context); // 调用AbstractApplicationContext.refresh()方法,在其中调用子容器的onRefresh()方法 // ... }
EmbeddedWebApplicationContext.class
@Override protected void onRefresh() { super.onRefresh(); try { createEmbeddedServletContainer(); } // ... } // ... private void createEmbeddedServletContainer() { // ... EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory(); // 通过内嵌Servlet容器工厂,并借助EmbeddedServletContainerCustomizerBeanPostProcessor后置处理器遍历容器中所有EmbeddedServletContainerCustomizer容器定制器对创建的Servlet容器进行环境配置 this.embeddedServletContainer containerFactory.getEmbeddedServletContainer(getSelfInitializer()); // 获取Servlet容器 }
# 日志
默认采用Logback
作为日志实现
org.springframework.boot:spring-boot-starter-logging
:
ch.qos.logback:logback-classic
org.slf4j:slf4j-api
ch.qos.logback:logback-core
org.apache.logging.log4j:log4j-to-slf4j
// 将Log4j
替换为Slf4j
org.slf4j:slf4j-api
org.apache.logging.log4j:log4j-api
org.slf4j:jul-to-slf4j
// 将JUL
替换为Slf4j
org.slf4j:slf4j-api
SLF4JBrindgeHandler
已存在
org.springframework:spring-core
:
spring-jcl
(内置jcl-slf4j
桥接?)
可在类路径下自定义日志配置文件(如logback-spring.xml),并实现基于不同开发环境的动态日志格式
<springProfile name="staging">
<!-- <pattern></pattern> -->
</springProfile>
# 数据源
# DataSourceAutoConfiguration
DataSourceConfiguration
自定义数据源类型
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
@Bean
public DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build(); // 利用反射创建spring.datasource.type对应类型的数据源,并绑定相关属性
}
}
DataSourceInitializer
监听容器启动,运行特定的SQL脚本
# SpringBoot 2.x spring: datasource: # ... initialization-mode: always schema: - xxx.sql
# 缓存
# Cacheable
(声明式缓存,默认缓存key为cacheNames
+ key
)
@Cacheable(cacheNames = {"abc"}, key = "#root.methodName + '[' + #id + ']'", condition = "#a0 > 0", unless = "#result == null")
public SomePOJO get(Integer id) {
// ...
}
value
/cacheNames
属性指定缓存组件名(可将公共组件名单独以@CacheConfig
注解方式配置在类上)key
属性指定缓存key(默认为方法参数值)- 属性值可使用SpEl表达式(如
#root.method.name
/#root.targetClass
/#root.args[0]
),若只使用字符串需加上单引号进行区分 sync
属性指定缓存操作逻辑是否使用synchronized
同步代码块
# CacheAutoConfiguration
// ...
@Import(CacheConfigurationImportSelector.class) // 获取所有可能加入容器的缓存配置类
public class CacheAutoConfiguration {
// ...
}
# SimpleCacheConfiguration
容器启动时默认的缓存配置类为
SimpleCacheConfiguration
,采用ConcurrentMapCacheManager
作为缓存管理器,后者使用ConcurrentHashMap
进行存储
@Override
public Cache getCache(String name) {
Cache cache = this.cacheMap.get(name);
if (cache == null && this.dynamic) {
synchronized (this.cacheMap) {
cache = this.cacheMap.get(name); // 二次获取(?)
if (cache == null) {
cache = createCocurrentMapCache(name);
this.cacheMap.put(name, cache);
}
}
}
return cache;
}
# @Cacheable
方法执行缓存存取流程
CacheManager.getCache(cacheId)
CacheAspectSupport.generateKey(result)
借助SimpleKeyGenerator.generate(...)
生成缓存key可在配置类中注入
KeyGenerator
实现类,重写Object generate(Object target, Method method, Object... params)
方法,配置自定义key生成器CacheAspectSupport.findInCaches(context, key)
->Cache.lookup(key)
利用生成的缓存key检查缓存
- (上述步骤没有缓存命中)
- 执行目标方法,返回目标数据
Cache.put(key, value)
- (上述步骤有缓存命中)直接返回该
Cache
对象
# CachePut
用于实现缓存双写模式解决分布式缓存一致性问题
- 执行目标方法,返回目标数据
Cache.put(key, value)
@CachePut(value = "abc", key = "#root.methodName + '[' + #result.id + ']'") // @CachePut在目标方法执行后调用,故可在SpEl表达式中使用#result
public SomePOJO update(SomePOJO pojo) {
// ...
}
# CacheEvict
用于实现缓存失效模式解决分布式缓存一致性问题
@CacheEvict(value = "abc", key = "#root.methodName + '[' + #id + ']'"/*, allEntries = true*/) // allEntries属性指定是否清除该缓存组件中所有缓存key(默认为否),beforeInvocation属性指定缓存清除操作是否在方法执行之前进行(默认为否)
public void delete(Integer id) {
// ...
}
# RedisAutoConfiguration
// RedisAutoConfiguration.class
@Configuration
protected static class RedisConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
return template;
}
// ...
}
# 自定义JSON序列化器
配置
RedisTemplate
所使用的序列化器(编程式缓存)// SpringBoot 1.x @Configuration public class CustomRedisConfiguration { @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) throws UnknownHostException { RedisTemplate<Object, SomePOJO> template = new RedisTemplate<>(); template.setConnectionFactory(factory); template.setDefaultSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class)); return template; } }
自定义
CacheManager
(声明式缓存)@EnableConfigurationProperties(CacheProperties.class) // 从配置文件中读取spring.cache配置 @EnableCaching @Configuration public class CustomRedisCacheConfiguration { // 入参自动从容器中获取 @Bean RedisCacheConfiguration redisCacheConfiguration(CacheProperties properties) { RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new Jackson2JsonRedisSerializer())); } if (properties.getTimeToLive != null) { config = config.entryTtl(properties.getTimeToLive); } if (properties.getKeyPrefix != null) { // 缓存key前缀,默认为cacheNames,一般使用默认值 config = config.prefixKeysWith(properties.getKeyPrefix); } if (!properties.isCacheNullValues()) { // 缓存空值,预防缓存穿透 config = config.disableCachingNullValues(); } if (!properties.isUseKeyPrefix()) { config = config.disableKeyPrefix(); } }
#
RedisCacheConfiguration
采用
RedisCacheManager
作为缓存管理器,后者使用RedisCache
进行缓存读写// 默认读写操作不加锁 protected Object lookup(Object key) { byte[] value = cacheWriter.get(name, createAndConvertCacheKey(key)); // ... } public void put(Object key, Object value) { // ... // cacheWriter.put(...) } // 只有读操作有加锁版本,通过Cacheable注解的sync属性开启 public synchronized <T> T get(Object key, Callable<T> valueLoader) { ValueWrapper result = get(key); if (result != null) { return (T) result.get(); } valueFromLoader(key, valueLoader); put(key, value); return value; }
# AMQP
# RabbitAutoConfiguration
// RabbitAutoConfiguration.class
@Configuration
@ConditionalOnMissingBean(ConnectionFactory.class)
protected static class RedisConfiguration {
@Bean
public ConnectionFactory connectionFactory(RabbitProperties config) throws Exception {
RabbitConnectionFactoryBean factory = new RabbitConnectionFactoryBean();
// 设置factory各种连接属性
CachingConnectionFactory connectionFactory = CachingConnectionFactory(factory.getObject());
// 设置connectionFactory各种连接属性
return connectionFactory;
}
// ...
@Bean
@ConditionalOnSingleCandidate(ConnectionFactory.class)
@ConditionalOnMissingBean(RabbitTemplate.class)
public RabbitTemplate rabiitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
// ...
return template;
}
// AmqpAdmin
@Bean
@ConditionalOnSingleCandidate(ConnectionFactory.class)
@ConditionalOnProperty(prefix = "spring.rabbitmq", name = "dynamic", matchIfMissing = true)
@ConditionalOnMissingBean(AmqpAdmin.class)
public AmqpAdmin amqpAdmin(ConnectionFactory connectionFactory) {
return new AmqpAdmin(connectionFactory);
}
}
# 自定义JSON序列化器
@Configuration
public class CustomRabbitConfiguration {
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
}
# A
← Spring基础 Spring MVC基础 →