赞
踩
目录
1. springboot 自定义的 starter 的用途
2. 自定义 Spring Boot Starter 可以用于各种场景
3.2 自定义 RedisTemplateAutoConfiguration
Spring Boot Starter 是一种用于简化 Spring Boot 应用程序依赖项管理的方式。它们是一组预定义的依赖项,可以将它们添加到您的应用程序中,以便您可以更轻松地配置和使用 Spring Boot 应用程序中的各种功能。
自定义 Spring Boot Starter 可以帮助您将自己的库或框架集成到 Spring Boot 应用程序中。通过创建自己的 Starter,您可以将所有必需的依赖项打包到一个单独的模块中,并提供一个简单的配置方式,以便其他开发人员可以轻松地使用您的库或框架。
自定义 Spring Boot Starter 的主要用途包括:
1. 简化依赖项管理:通过将所有必需的依赖项打包到一个单独的模块中,您可以简化其他开发人员使用您的库或框架的过程。
2. 提供简单的配置方式:通过提供一个简单的配置方式,您可以使其他开发人员更轻松地配置和使用您的库或框架。
3. 提供自定义的自动配置:通过提供自定义的自动配置,您可以使您的库或框架更容易地集成到 Spring Boot 应用程序中。
1. 数据库访问:您可以创建一个自定义 Starter,用于简化数据库访问的配置和使用。例如,您可以创建一个 Starter,用于集成 MyBatis 或 Hibernate 等 ORM 框架。
2. 缓存:您可以创建一个自定义 Starter,用于简化缓存的配置和使用。例如,您可以创建一个 Starter,用于集成 Redis 或 Ehcache 等缓存框架。
3. 消息队列:您可以创建一个自定义 Starter,用于简化消息队列的配置和使用。例如,您可以创建一个 Starter,用于集成 RabbitMQ 或 Kafka 等消息队列框架。
4. 安全性:您可以创建一个自定义 Starter,用于简化安全性的配置和使用。例如,您可以创建一个 Starter,用于集成 Spring Security 或 OAuth2 等安全框架。
5. 日志:您可以创建一个自定义 Starter,用于简化日志的配置和使用。例如,您可以创建一个 Starter,用于集成 Log4j2 或 Logback 等日志框
自定义 starter 必要的 配置类, 用于读取yml或properties中的配置, 目的是为了在不同的模块都可以引入我们的自定义配置
- /**
- * @author yukun.yan
- * @description RedisTemplateConfigProperties
- * @date 2023/5/4 17:18
- */
- @Data
- @PropertySource(value = "classpath:sp-redis.properties")
- @ConfigurationProperties(prefix = "sp.redis")
- public class RedisTemplateConfigProperties {
-
- private String host;
-
- private String password;
-
- private int port;
-
- private int database;
-
- private int minIdle;
-
- private int maxIdle;
-
- private int maxTotal;
-
- private int timeout;
-
- private int expire;
-
- private int maxWait;
-
- }
以及配置文件前缀, 这个不配置具体的参数, 目的是为了在其他模块配置
- sp.redis.database=
- sp.redis.password=
- sp.redis.port=
- sp.redis.host=
- sp.redis.timeout=
- sp.redis.min-idle=
- sp.redis.max-idle=
- sp.redis.max-total=
- sp.redis.expire=
- sp.redis.max-wait=
- sp.redis.enable=
这里需要用到一个关键的主键, @AutoConfigureBefore(RedisAutoConfiguration.class)
顾名思义, 这个注解的意思是在 RedisAutoConfiguration.class 注入之前去注入我们自定义的 RedisTemplateAutoConfiguration 中配置的 bean, 不然会出现这样的错误 :
错误的原因是, springboot 在启动时会优先加载 springboot 框架自带的 spring.factories 文件中的定义的自动配置类, 把框架原本的 redisTemplate 作为 bean 注入到 容器中, 之后才会加载我们自定义的 RedisTemplateAutoConfiguration, 并且再次把我们魔改过 redisTemplate 注入到 bean 中, 这样容器中出现了2个名字一样的 redisTemplate, 所以会出现上述的错误
我们自定义的 redis-starter 的目的是想让框架加载我们魔改后的 redisTemplate, 结合源码发现, 框架只会在缺失 redisTemplate 这个 bean 的时候才会加载框架自带的 redisTemplate, 源码位置 : org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
所以我们可以使用 @AutoConfigureBefore(RedisAutoConfiguration.class) 这个注解, 让框架优先加载我们自定义的 redisTemplate, 并注入到容器中, 之后框架在加载原本的 RedisAutoConfiguration 时候, 通过注解 @ConditionalOnMissingBean(name = "redisTemplate") 来控制不再做加载
- /**
- * @author yukun.yan
- * @description RedisTemplateAutoConfiguration redis操作类自动装配
- * @date 2023/5/4 16:43
- */
- @AutoConfigureBefore(RedisAutoConfiguration.class)
- @PropertySource(value = "classpath:sp-redis.properties")
- @EnableConfigurationProperties({RedisTemplateConfigProperties.class}) // 依赖配置文件
- public class RedisTemplateAutoConfiguration {
-
- /**
- * com.fasterxml.jackson.databind.deser.BeanDeserializer
- * ObjectMapper om = new ObjectMapper(); 调用 vanillaDeserialize方法
- * ObjectMapper om = mapperBuilder.build(); 调用 deserializeFromObject方法
- */
- @Bean
- public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory, Jackson2ObjectMapperBuilder mapperBuilder) {
- // Json序列化配置
- Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
- // ObjectMapper om = new ObjectMapper();
- ObjectMapper om = mapperBuilder.build();
- om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
- om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
- // 如果enableDefaultTyping过期(SpringBoot后续版本过期了)
- jackson2JsonRedisSerializer.setObjectMapper(om);
- // String的序列化配置
- StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
-
- RedisTemplate<String, Object> template = new RedisTemplate<>();
- template.setConnectionFactory(lettuceConnectionFactory);
- // key采用String的序列化方式
- template.setKeySerializer(stringRedisSerializer);
- // hash的key也采用String的序列化方式
-
- template.setHashKeySerializer(stringRedisSerializer);
- // value序列化方式采用jackson
- template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
- // hash的value序列化方式采用jackson
- template.setHashValueSerializer(jackson2JsonRedisSerializer);
- // 刷新属性设置
- template.afterPropertiesSet();
- return template;
- }
-
- @Bean
- public StringRedisTemplate stringRedisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
- StringRedisTemplate template = new StringRedisTemplate();
- template.setConnectionFactory(lettuceConnectionFactory);
- // String 的序列化
- StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
- template.setKeySerializer(stringRedisSerializer);
- template.setValueSerializer(stringRedisSerializer);
- template.setHashKeySerializer(stringRedisSerializer);
- return template;
- }
-
- }
同样的, @AutoConfigureAfter({RedisTemplateAutoConfiguration.class}) 这个注解是规定在我们自定义的 RedisTemplateAutoConfiguration 执行完毕之后, 在加载缓存配置, 否则在没有 redis 的情况下, 加载缓存没有意义
- /**
- * @author yukun.yan
- * @description RedisCacheAutoConfiguration redis缓存自动配置
- * @date 2023/5/5 10:15
- */
- @AutoConfigureAfter({RedisAutoConfiguration.class})
- @ConditionalOnMissingBean({CacheManager.class})
- @EnableConfigurationProperties(CacheProperties.class)
- public class RedisCacheAutoConfiguration {
-
- /**
- * 实例化自定义的缓存管理器
- */
- @Bean
- @SuppressWarnings(value = {"rawtypes"})
- public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
- RedisConnectionFactory redisConnectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory());
- RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
- RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
- return new CustomRedisCacheManager(redisCacheWriter, redisCacheConfiguration);
- }
-
- /**
- * 自定义缓存规则
- */
- private static class CustomRedisCacheManager extends RedisCacheManager {
- public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
- super(cacheWriter, defaultCacheConfiguration);
- }
-
- @Override
- protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
- String[] cells = StringUtils.delimitedListToStringArray(name, "#");
- name = cells[0];
- if (cells.length > 1) {
- long ttl = Long.parseLong(cells[1]);
- // 根据传参设置缓存失效时间,默认单位是秒
- cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl));
- }
- return super.createRedisCache(name, cacheConfig);
- }
- }
-
- }
如果没有连接池的话, SpringBoot2.0 版本之后 spring-boot-starter-data-redis 的底层默认使用了 Lettuce 来操作 redis ,早期的版本使用的是Jedis
使用 @Primary 注解来标注我们自定义的 Lettuce 连接池为主连接池
- /**
- * @author yukun.yan
- * @description LettuceConnectionAutoConfiguration redis连接池自动配置
- * @date 2023/5/5 10:24
- */
- @AutoConfigureAfter({RedisAutoConfiguration.class}) // 之后配置链接工厂
- @EnableConfigurationProperties({RedisTemplateConfigProperties.class}) // 依赖配置文件
- @ConditionalOnBean({RedisTemplate.class, RedisConnectionFactory.class, RedisTemplateConfigProperties.class})
- public class LettuceConnectionAutoConfiguration {
-
- /**
- * 配置连接池信息
- * 容器在缺失 RedisConnectionFactory 配置的时候, 会兜底注入 JedisConnectionFactory
- * @see JedisConnectionConfiguration#redisConnectionFactory(org.springframework.beans.factory.ObjectProvider)
- *
- * @param properties
- * @return
- */
- @Bean
- @Primary
- public LettuceConnectionFactory lettuceConnectionFactory(final RedisTemplateConfigProperties properties) {
- // 基础配置
- RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
- redisStandaloneConfiguration.setDatabase(properties.getDatabase());
- redisStandaloneConfiguration.setHostName(properties.getHost());
- redisStandaloneConfiguration.setPort(properties.getPort());
- redisStandaloneConfiguration.setPassword(RedisPassword.of(properties.getPassword()));
- // 连接池配置
- LettucePoolingClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration
- .builder()
- .commandTimeout(Duration.ofMillis(properties.getTimeout()))
- .poolConfig(getPoolConfig(properties)).build();
-
- // 根据配置和客户端配置创建连接
- LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration, lettuceClientConfiguration);
- lettuceConnectionFactory.afterPropertiesSet();
- return lettuceConnectionFactory;
- }
-
- /**
- * 获取连接池配置
- *
- * @param properties
- * @return
- */
- private GenericObjectPoolConfig getPoolConfig(final RedisTemplateConfigProperties properties) {
- GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
- genericObjectPoolConfig.setMaxIdle(properties.getMaxIdle());
- genericObjectPoolConfig.setMinIdle(properties.getMinIdle());
- genericObjectPoolConfig.setMaxTotal(properties.getMaxTotal());
- genericObjectPoolConfig.setMaxWaitMillis(properties.getMaxWait());
- return genericObjectPoolConfig;
- }
-
- }
模仿框架的定义方式, 在 resource 下创建一个 META-INF 包, 并创建 spring.factories 文件
- org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.kone.sp.common.redis2.config.RedissonAutoConfiguration,\
- com.kone.sp.common.redis2.config.RedisCacheAutoConfiguration,\
- com.kone.sp.common.redis2.config.RedisTemplateAutoConfiguration,\
- com.kone.sp.common.redis2.config.LettuceConnectionAutoConfiguration
对我们的自定义 redis-starter 使用 install 命令, 之后在 maven 仓库里可以看到
在 pom 文件中引入, 并在其他模块的 yml 文件中配置 RedisTemplateConfigProperties 需要的配置参数, 这里要注意前缀和属性名称要和配置类对应上
之后从配置文件中可以看到, 我们在其他模块编写的 yml 配置, 已经在创建连接工厂的时候被读取到
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。