实现自定义SpringBoot的Starter

embedded/2024/9/20 7:26:47/ 标签: spring boot, java, spring

starter机制

Spring Boot Starter机制是Spring Boot项目中的一个重要概念,它主要用于简化Maven或Gradle等构建工具中的依赖管理。每个Starter都包含了实现特定功能所需的库和组件,以及相应的配置文件。开发者只需在项目中引入相应的Starter依赖,即可快速搭建起具备该功能的项目骨架。

自定义starter好处

简化依赖管理:与Spring Boot内置的Starter类似,自定义Starter同样可以隐藏底层库的复杂依赖关系,使开发者只需关注业务逻辑,而无需担心底层的依赖问题。这有助于降低项目的复杂性,提升开发效率。
统一配置和自动装配:自定义Starter可以包含默认的配置信息和自动装配类,使得相关功能或组件的集成更加统一和便捷。开发者无需为每个项目重复编写相同的配置代码,只需引入自定义Starter即可实现快速集成。
提高可复用性:通过自定义Starter,可以将一些通用的功能或组件进行封装,使得这些功能或组件可以在多个项目之间共享和复用。这不仅可以减少代码冗余,还可以确保不同项目之间的功能实现保持一致。
扩展性和灵活性:自定义Starter允许开发者根据实际需求进行定制和扩展。开发者可以添加自己的配置项和默认配置值,以满足特定的业务需求。此外,自定义Starter还可以与其他第三方组件或库进行集成,以提供更加丰富的功能。
易于维护:由于自定义Starter对底层依赖进行了封装和统一配置,因此在维护和升级时只需关注自定义Starter的变更,而无需对每个使用到该Starter的项目进行逐一修改。这大大简化了维护工作,提高了开发效率。
综上所述,自定义Spring Boot Starter通过简化依赖管理、统一配置和自动装配、提高可复用性、扩展性和灵活性以及易于维护等好处,为开发者提供了一种高效、便捷的方式来构建和集成Spring Boot应用程序中的特定功能或组件。

使用场景

在日常开发工作中,如统一整合redis,mq,minIO,鉴权,日志等,用于框架集成,供自己和公司其他团队使用,通过简化配置来提高开发效率。

实现原理

具体来说,Spring Boot Starter通过自动配置(Auto-configuration)和依赖管理来实现其机制。自动配置类使用@Configuration注解进行标记,并通过条件注解(如@ConditionalOnClass、@ConditionalOnBean、@ConditionalOnProperty等)来确定是否应用自动配置。当在Spring Boot应用的pom.xml文件中添加了一个Starter的依赖时,它会触发Spring Boot的自动配置机制。自动配置类中的配置将被应用于应用程序上下文,并根据需要创建和配置相关的Bean。

实现步骤

源码地址:https://github.com/mikewuhao/redis-spring-boot-starter
项目结构
在这里插入图片描述
RedisConfiguration

java">package com.wuhao.redis.config;import com.wuhao.redis.utils.RedisUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import redis.clients.jedis.JedisPoolConfig;/*** Copyright 2022 skyworth** @Author: wuhao* @CreateTime: 2024-04-22 11:51* @Description: redis配置类* @Version: 1.0**/
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfiguration {private final RedisProperties properties;public RedisConfiguration(RedisProperties redisProperties) {this.properties = redisProperties;}@Bean(name = "redisHandler")@ConditionalOnMissingBean(RedisUtils.class)public RedisUtils redisUtils() {JedisPoolConfig poolConfig = new JedisPoolConfig();//最大连接数poolConfig.setMaxTotal(properties.getMaxTotal());//最多空闲数poolConfig.setMaxIdle(properties.getMaxIdLe());//当池中没有连接时,最多等待5秒poolConfig.setMaxWaitMillis(properties.getMaxWaitMillis());String pw = StringUtils.isEmpty(properties.getPassword()) ? null : properties.getPassword();return new RedisUtils(poolConfig, properties.getHost(), properties.getPort(), properties.getTimeOut(), pw, properties.getDatabase());}
}

RedisProperties

java">
package com.wuhao.redis.config;import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;/*** Copyright 2022 skyworth** @Author: wuhao* @CreateTime: 2024-04-22 11:51* @Description: redis配置属性* @Version: 1.0**/
@ConfigurationProperties("spring.redis")
public class RedisProperties {@Value("${host:127.0.0.1}")private String host;@Value("${port:6379}")private int port;@Value("${database:0}")private int database;@Value("${password:}")private String password;@Value("${timeOut:3000}")private int timeOut;@Value("${maxTotal:10000}")private int maxTotal;@Value("${maxIdLe:50}")private int maxIdLe;@Value("${maxWaitMillis:5000}")private long maxWaitMillis;public String getHost() {return host;}public void setHost(String host) {this.host = host;}public int getPort() {return port;}public void setPort(int port) {this.port = port;}public int getDatabase() {return database;}public void setDatabase(int database) {this.database = database;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public int getTimeOut() {return timeOut;}public void setTimeOut(int timeOut) {this.timeOut = timeOut;}public int getMaxTotal() {return maxTotal;}public void setMaxTotal(int maxTotal) {this.maxTotal = maxTotal;}public int getMaxIdLe() {return maxIdLe;}public void setMaxIdLe(int maxIdLe) {this.maxIdLe = maxIdLe;}public long getMaxWaitMillis() {return maxWaitMillis;}public void setMaxWaitMillis(long maxWaitMillis) {this.maxWaitMillis = maxWaitMillis;}
}

RedisUtils

java">package com.wuhao.redis.utils;import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Tuple;import java.util.*;/*** Copyright 2022 skyworth** @Author: wuhao* @CreateTime: 2024-04-22 11:51* @Description: redis工具类* @Version: 1.0**/
public final class RedisUtils {/*除了该工具类提供的方法外,还可以在外面调用getJedis()方法,获取到jedis实例后,调用它原生的api来操作*/private final JedisPool jedisPool;static final Long OPERATE_SUCCESS = 1L;/*** 定义获取锁的lua脚本*/static final String LOCK_LUA_SCRIPT = "if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then return redis.call('expire', KEYS[1], ARGV[2]) else return 0 end";/*** 定义释放锁的lua脚本*/static final String UNLOCK_LUA_SCRIPT = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return -1 end";/*** 获取jedis对象,并选择redis库。jedis默认是0号库,可传入1-16之间的数选择库存放数据* 原则上使用一个redis库存放数据,通过特定的key的命令规则来区分不同的数据就行了。** @param index redis库号。使用可变参数的目的就是该参数可传可不传。* @return 返回jedis对象*/public Jedis getJedis(int... index) {Jedis jedis = jedisPool.getResource();if (index != null && index.length > 0) {if (index[0] > 0 && index[0] <= 16) {jedis.select(index[0]);}}return jedis;}/*########################  key的操作  ################################*//*** 删除一个或多个key** @param key 一个或多个key*/public Long del(String... key) {try (Jedis jedis = getJedis()) {return jedis.del(key);}}/*** 批量删除** @param keyList 要删除的key的集合*/public void mDel(List<String> keyList) {Jedis jedis = getJedis();//获取pipelinePipeline pipeline = jedis.pipelined();for (String key : keyList) {pipeline.del(key);}//执行结果同步,这样才能保证结果的正确性。实际上不执行该方法也执行了上面的命令,但是结果确不一定完全正确。//注意pipeline.sync();//关闭连接jedis.close();}/*** 判断某个key是否还存在** @param key key*/public Boolean exists(String key) {try (Jedis jedis = getJedis()) {return jedis.exists(key);}}/*** 设置某个key的过期时间,单位秒** @param key     key* @param seconds 过期时间秒*/public void expire(String key, int seconds) {try (Jedis jedis = getJedis()) {jedis.expire(key, seconds);}}/*** 设置某个key的过期时间,单位秒** @param key     key* @param seconds 过期时间秒*/public void expire(String key, Long seconds) {try (Jedis jedis = getJedis()) {jedis.expire(key, seconds.intValue());}}/*** 设置某个key的过期时间,单位毫秒** @param key     key* @param seconds 过期时间秒*/public void expireAt(String key, long seconds) {try (Jedis jedis = getJedis()) {jedis.expireAt(key, seconds);}}/*** 查看某个key还有几秒过期,-1表示永不过期 ,-2表示已过期*/public Long ttl(String key) {try (Jedis jedis = getJedis()) {return jedis.ttl(key);}}/*** 查看某个key对应的value的类型*/public String type(String key) {try (Jedis jedis = getJedis()) {return jedis.type(key);}}/*########################  string(字符串)的操作  ####################*//*** 获取某个key的value,类型要对,只能value是string的才能获取*/public String get(String key) {try (Jedis jedis = getJedis()) {return jedis.get(key);}}/*** 设置某个key的value*/public String set(String key, String value) {try (Jedis jedis = getJedis()) {return jedis.set(key, value);}}/*** 设置某个key的value*/public String set(String key, String value, int expireSeconds) {try (Jedis jedis = getJedis()) {return jedis.setex(key, expireSeconds, value);}}/*** 设置某个key的value*/public String set(String key, String value, Long expireSeconds) {try (Jedis jedis = getJedis()) {return jedis.setex(key, expireSeconds.intValue(), value);}}public String set(String key, String value, String nxxx, String expx, long time) {try (Jedis jedis = getJedis()) {return jedis.set(key, value, nxxx, expx, time);}}/*** 字符串后追加内容** @param key           key* @param appendContent 要追加的内容*/public Long append(String key, String appendContent) {try (Jedis jedis = getJedis()) {return jedis.append(key, appendContent);}}/*** 返回key的value的长度*/public Long strLen(String key) {try (Jedis jedis = getJedis()) {return jedis.strlen(key);}}/*** value 加1 必* 须是字符型数字*/public Long incr(String key) {try (Jedis jedis = getJedis()) {return jedis.incr(key);}}/*** value* 须是字符型数字*/public Long incr(String key, int num) {try (Jedis jedis = getJedis()) {return jedis.incrBy(key, num);}}/*** value 减1   必须是字符型数字*/public Long decr(String key) {try (Jedis jedis = getJedis()) {return jedis.decr(key);}}/*** value 加increment*/public Long incrBy(String key, int increment) {try (Jedis jedis = getJedis()) {return jedis.incrBy(key, increment);}}public Double incrByFloat(String key, double increment) {try (Jedis jedis = getJedis()) {return jedis.incrByFloat(key, increment);}}/*** value 加increment*/public Long incrBy(String key, Long increment) {try (Jedis jedis = getJedis()) {return jedis.incrBy(key, increment);}}/*** value 减increment*/public Long decrBy(String key, int increment) {try (Jedis jedis = getJedis()) {return jedis.decrBy(key, increment);}}/*** 给某个key设置过期时间和value,成功返回OK** @param key     key* @param seconds 过期时间秒* @param value   设置的值*/public String setEx(String key, int seconds, String value) {try (Jedis jedis = getJedis()) {return jedis.setex(key, seconds, value);}}/*########################  list(列表)的操作  #######################*//*** 从左边向列表中添加值*/public void lPush(String key, String str) {try (Jedis jedis = getJedis()) {jedis.lpush(key, str);}}/*** 从左边向列表中添加值*/public void lPushAll(String key, String... strings) {try (Jedis jedis = getJedis()) {jedis.lpush(key, strings);}}public void rPushAll(String key, String... strings) {try (Jedis jedis = getJedis()) {jedis.rpush(key, strings);}}/*** 从右边向列表中添加值*/public void rPush(String key, String str) {try (Jedis jedis = getJedis()) {jedis.rpush(key, str);}}/*** 从左边取出一个列表中的值*/public String lPop(String key) {try (Jedis jedis = getJedis()) {return jedis.lpop(key);}}/*** 从右边取出一个列表中的值*/public String rPop(String key) {try (Jedis jedis = getJedis()) {return jedis.rpop(key);}}/*** 取出列表中指定范围内的值,0 到 -1 表示全部*/public List<String> lRange(String key, int startIndex, int endIndex) {try (Jedis jedis = getJedis()) {return jedis.lrange(key, startIndex, endIndex);}}/*** 返回某列表指定索引位置的值*/public String lIndex(String key, int index) {try (Jedis jedis = getJedis()) {return jedis.lindex(key, index);}}/*** 返回某列表的长度*/public Long lLen(String key) {try (Jedis jedis = getJedis()) {return jedis.llen(key);}}/*** 给某列表指定位置设置为指定的值*/public String lSet(String key, Long index, String str) {try (Jedis jedis = getJedis()) {return jedis.lset(key, index, str);}}/*** 对列表进行剪裁,保留指定闭区间的元素(索引位置也会重排)*/public void ltrim(String key, Integer startIndex, Integer endIndex) {try (Jedis jedis = getJedis()) {jedis.ltrim(key, startIndex, endIndex);}}/*** 从列表的左边阻塞弹出一个元素*/public List<String> blpop(String key, Integer timeout) {try (Jedis jedis = getJedis()) {return jedis.blpop(timeout, key);}}/*** 从列表的右边阻塞弹出一个元素*/public List<String> brpop(String key, Integer timeout) {try (Jedis jedis = getJedis()) {return jedis.brpop(timeout, key);}}/*########################  hash(哈希表)的操作  #######################*///hset hget hmset hmget hgetall hdel hkeys hvals hexists hincrby/*** 给某个hash表设置一个键值对*/public void hset(String key, String field, String value) {try (Jedis jedis = getJedis()) {jedis.hset(key, field, value);}}/*** 取出某个hash表中某个field对应的value*/public String hget(String key, String field) {try (Jedis jedis = getJedis()) {return jedis.hget(key, field);}}/*** 某个hash表设置一个或多个键值对*/public void hmset(String key, Map<String, String> kvMap) {try (Jedis jedis = getJedis()) {jedis.hmset(key, kvMap);}}/*** 取出某个hash表中任意多个key对应的value的集合*/public List<String> hmget(String key, String... fields) {try (Jedis jedis = getJedis()) {return jedis.hmget(key, fields);}}/*** 取出某个hash表中所有的键值对*/public Map<String, String> hgetAll(String key) {try (Jedis jedis = getJedis()) {return jedis.hgetAll(key);}}/*** 判断某个hash表中的某个key是否存在*/public Boolean hexists(String key, String field) {try (Jedis jedis = getJedis()) {return jedis.hexists(key, field);}}/*** 返回某个hash表中所有的key*/public Set<String> hkeys(String key) {try (Jedis jedis = getJedis()) {return jedis.hkeys(key);}}/*** 返回某个hash表中所有的value*/public List<String> hvals(String key) {try (Jedis jedis = getJedis()) {return jedis.hvals(key);}}/*** 删除某个hash表中的一个或多个键值对*/public Long hdel(String key, String... fields) {try (Jedis jedis = getJedis()) {return jedis.hdel(key, fields);}}/*** 给某个hash表中的某个field的value增加多少*/public Long hincrBy(String key, String field, Long increment) {try (Jedis jedis = getJedis()) {return jedis.hincrBy(key, field, increment);}}/*** 给某个hash表中的某个field的value增加多少*/public Long hincrBy(String key, String field, Integer increment) {try (Jedis jedis = getJedis()) {return jedis.hincrBy(key, field, increment);}}/*** 给某个hash表中的某个field的value增加多少*/public Long hdecrBy(String key, String field, Integer increment) {try (Jedis jedis = getJedis()) {return jedis.hincrBy(key, field, -increment);}}public Double hincrByFloat(String key, String field, Double increment) {try (Jedis jedis = getJedis()) {return jedis.hincrByFloat(key, field, increment);}}/*########################  set(集合)的操作  ###########################*//*** 往set集合中添加一个或多个元素*/public Long sadd(String key, String... members) {try (Jedis jedis = getJedis()) {return jedis.sadd(key, members);}}/*** 返回set集合中的所有元素,顺序与加入时的顺序一致*/public Set<String> smembers(String key) {try (Jedis jedis = getJedis()) {return jedis.smembers(key);}}/*** 判断集合中是否存在某个元素*/public Boolean sismember(String key, String member) {try (Jedis jedis = getJedis()) {return jedis.sismember(key, member);}}/*** 返回set集合的长度*/public Long scard(String key) {try (Jedis jedis = getJedis()) {return jedis.scard(key);}}/*** 删除set集合中指定的一个或多个元素*/public Long srem(String key, String... members) {try (Jedis jedis = getJedis()) {return jedis.srem(key, members);}}/*** 将key1中的元素key1Member移动到key2中*/public Long smove(String key1, String key2, String key1Member) {try (Jedis jedis = getJedis()) {return jedis.smove(key1, key2, key1Member);}}/*** 随机查询返回集合中的指定个数的元素(若count为负数,返回的元素可能会重复)*/public List<String> srandmember(String key, int count) {try (Jedis jedis = getJedis()) {return jedis.srandmember(key, count);}}/*** 从set集合中随机弹出指定个数个元素** @param key   key* @param count 要弹出的个数* @return 随机弹出的元素*/public Set<String> spop(String key, int count) {try (Jedis jedis = getJedis()) {return jedis.spop(key, count);}}/*** 求交集,返回多个set集合相交的部分*/public Set<String> sinter(String... setKeys) {try (Jedis jedis = getJedis()) {return jedis.sinter(setKeys);}}/*** 求并集,求几个set集合的并集(因为set中不会有重复的元素,合并后的集合也不会有重复的元素)*/public Set<String> sunion(String... setKeys) {try (Jedis jedis = getJedis()) {return jedis.sunion(setKeys);}}/*** 求差集,求几个集合之间的差集*/public Set<String> sdiff(String... setKeys) {try (Jedis jedis = getJedis()) {return jedis.sdiff(setKeys);}}/*########################  zset(有序集合)的操作  #######################*//*** 添加一个元素到zset*/public Long zadd(String key, double score, String member) {try (Jedis jedis = getJedis()) {return jedis.zadd(key, score, member);}}/*** 添加一个或多个元素到zset*/public Long zadd(String key, Map<String, Double> memberScores) {try (Jedis jedis = getJedis()) {return jedis.zadd(key, memberScores);}}/*** 查询指定闭区间的元素(根据分数升序)* (0,-1表示全部)*/public Set<String> zrange(String key, long start, long end) {try (Jedis jedis = getJedis()) {return jedis.zrange(key, start, end);}}/*** 查询指定闭区间的元素,带着分数* (0,-1表示全部)*/public Set<Tuple> zrangeWithScores(String key, long start, long end) {try (Jedis jedis = getJedis()) {return jedis.zrangeWithScores(key, start, end);}}/*** 查询指定索引闭区间的元素(根据分数降序)* (0,-1表示全部)*/public Set<String> zrevrange(String key, long start, long end) {try (Jedis jedis = getJedis()) {return jedis.zrevrange(key, start, end);}}/*** 查询指定索引闭区间的元素,带着分数(根据分数降序)* (0,-1表示全部)*/public Set<Tuple> zrevrangeWithScores(String key, long start, long end) {try (Jedis jedis = getJedis()) {return jedis.zrevrangeWithScores(key, start, end);}}/*** 返回有序集合(zset)中的元素个数*/public Long zcard(String key) {try (Jedis jedis = getJedis()) {return jedis.zcard(key);}}/*** 返回指定分数区间的元素个数(闭区间)*/public Long zcount(String key, Long startScore, Long endScore) {try (Jedis jedis = getJedis()) {return jedis.zcount(key, startScore, endScore);}}/*** 返回某元素在集合中的排名(根据分数降序排列时)*/public Long zrevrank(String key, String member) {try (Jedis jedis = getJedis()) {return jedis.zrevrank(key, member);}}/*** 返回某元素在集合中的排名(根据分数升序排列时)*/public Long zrank(String key, String member) {try (Jedis jedis = getJedis()) {return jedis.zrank(key, member);}}/*** 升序查询指定分数闭区间的元素*/public Set<String> zrangeByScore(String key, double min, double max) {try (Jedis jedis = getJedis()) {return jedis.zrangeByScore(key, min, max);}}/*** 升序查询指定分数闭区间的元素,并指定偏移量*/public Set<String> zrangeByScore(String key, double min, double max, int offset, int size) {try (Jedis jedis = getJedis()) {return jedis.zrangeByScore(key, min, max, offset, size);}}/*** 升序查询指定分数闭区间的元素,带着分数*/public Set<Tuple> zrangeByScoreWithScores(String key, double min, double max) {try (Jedis jedis = getJedis()) {return jedis.zrangeByScoreWithScores(key, min, max);}}/*** 升序查询指定分数闭区间的元素,并指定偏移量,带着分数*/public Set<Tuple> zrangeByScoreWithScores(String key, double min, double max, int offset, int size) {try (Jedis jedis = getJedis()) {return jedis.zrangeByScoreWithScores(key, min, max, offset, size);}}/*** 降序查询指定分数闭区间的元素*/public Set<String> zrevrangebyscore(String key, double max, double min) {try (Jedis jedis = getJedis()) {return jedis.zrevrangeByScore(key, max, min);}}/*** 降序查询指定分数闭区间的元素,并指定偏移量*/public Set<String> zrevrangebyscore(String key, double max, double min, int offset, int size) {try (Jedis jedis = getJedis()) {return jedis.zrevrangeByScore(key, max, min, offset, size);}}/*** 降序查询指定分数闭区间的元素,并带着分数*/public Set<Tuple> zrevrangeByScoreWithScores(String key, double max, double min) {try (Jedis jedis = getJedis()) {return jedis.zrevrangeByScoreWithScores(key, max, min);}}/*** 降序查询指定分数闭区间的元素,并指定偏移量,带着分数*/public Set<Tuple> zrevrangeByScoreWithScores(String key, double max, double min, int offset, int size) {try (Jedis jedis = getJedis()) {return jedis.zrevrangeByScoreWithScores(key, min, max, offset, size);}}/*** 有序集合中指定删除一或多个元素*/public Long zrem(String key, String... member) {try (Jedis jedis = getJedis()) {return jedis.zrem(key, member);}}/*** 分数升序排名时,删除指定索引区间的元素*/public Long zremrangebyrank(String key, long start, long end) {try (Jedis jedis = getJedis()) {return jedis.zremrangeByRank(key, start, end);}}/*** 分数升序排名时,删除指定分数区间的元素*/public Long zremrangeByScore(String key, long min, long max) {try (Jedis jedis = getJedis()) {return jedis.zremrangeByScore(key, min, max);}}/*** 查询有序集合中某元素的分数*/public Double zscore(String key, String member) {try (Jedis jedis = getJedis()) {return jedis.zscore(key, member);}}/*** 给有序集合中某元素的分数增加(正数)或减少(负数)*/public Double zincrby(String key, double score, String member) {try (Jedis jedis = getJedis()) {return jedis.zincrby(key, score, member);}}/*########################  lock 相关  #######################*//*** 获取一把锁*/public boolean lock(String key, String lockValue, int expire) {if (key == null || lockValue == null) {return false;}try (Jedis jedis = getJedis()) {List<String> args = new ArrayList<>();args.add(lockValue);args.add(String.valueOf(expire));Object res = jedis.eval(LOCK_LUA_SCRIPT, Collections.singletonList(key), args);return res != null && res.equals(OPERATE_SUCCESS);} catch (Exception e) {return false;}}/*** 获取一把锁*/public boolean lock(String key, String lockValue, long expire) {if (key == null || lockValue == null) {return false;}try (Jedis jedis = getJedis()) {List<String> args = new ArrayList<>();args.add(lockValue);args.add(String.valueOf(expire));Object res = jedis.eval(LOCK_LUA_SCRIPT, Collections.singletonList(key), args);return res != null && res.equals(OPERATE_SUCCESS);} catch (Exception e) {return false;}}public boolean releaseLock(String key, String lockValue) {if (key == null || lockValue == null) {return false;}try (Jedis jedis = getJedis()) {Object res = jedis.eval(UNLOCK_LUA_SCRIPT, Collections.singletonList(key), Collections.singletonList(lockValue));return res != null && res.equals(OPERATE_SUCCESS);} catch (Exception e) {return false;}}/*** 私有化构造器,不让实例化对象*/public RedisUtils(final GenericObjectPoolConfig poolConfig, final String host, int port, int timeout, final String password, int database) {this.jedisPool = new JedisPool(poolConfig, host, port, timeout, password, database);}
}

spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.wuhao.redis.config.RedisConfiguration

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.wuhao</groupId><artifactId>redis-spring-boot-starter</artifactId><version>1.0-SNAPSHOT</version><properties><revision>2.0.2.RELEASE</revision><redis.revision>2.9.0</redis.revision><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>${revision}</version></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>${redis.revision}</version></dependency></dependencies></project>

对starter打jar包
先clean,再install安装到本地仓库
在这里插入图片描述
外部引用
pom文件加入依赖的starter的jar包
在这里插入图片描述
配置文件填写redis的配置信息
在这里插入图片描述
注入依赖redis工具类,写业务代码
在这里插入图片描述


http://www.ppmy.cn/embedded/16457.html

相关文章

HTTP 网络协议请求的消息结构,具体详解(2024-04-25)

一、简介 HTTP 是基于客户端/服务端&#xff08;C/S&#xff09;的架构模型&#xff0c;通过一个可靠的链接来交换信息&#xff0c;是一个无状态的请求/响应协议。 HTTP 消息是客户端和服务器之间通信的基础&#xff0c;它们由一系列的文本行组成&#xff0c;遵循特定的格式和…

网络安全之防范钓鱼邮件

随着互联网的快速发展&#xff0c;新的网络攻击形式“网络钓鱼”呈现逐年上升的趋势&#xff0c;利用网络钓鱼进行欺骗的行为越来越猖獗&#xff0c;对互联网的安全威胁越来越大。网络钓鱼最常见的欺骗方式就是向目标群体发送钓鱼邮件&#xff0c;而邮件标题和内容&#xff0c;…

【线性代数 C++】结合逆矩阵的克拉默法则

1 原理 对于 n n n个变量、 n n n个方程的线性方程组 { a 11 x 1 a 12 x 2 ⋯ a 1 n x n b 1 a 21 x 1 a 22 x 2 ⋯ a 2 n x n b 2 ⋯ ⋯ ⋯ a n 1 x 1 a n 2 x 2 ⋯ a n n x n b n , (1) \begin{cases} a_{11}x_1a_{12}x_2\cdots a_{1n}x_nb_1 \\ a_{21}x_1a_{22}…

设计模式:迪米特法则(Law of Demeter,LoD)介绍

迪米特法则&#xff08;Law of Demeter&#xff0c;LoD&#xff09;&#xff0c;也称为最少知识原则&#xff08;Least Knowledge Principle&#xff0c;LKP&#xff09;&#xff0c;是面向对象设计原则之一&#xff0c;它强调一个对象应该对其他对象有尽可能少的了解&#xff…

汽车组装3D电子说明书更通俗易懂

激光打印机由于造价高、技术更先进&#xff0c;因此在使用和维护上需要更专业的手法&#xff0c;而对于普通客户来说并不具备专业操作激光打印机的技能&#xff0c;为了通俗易懂地让客户理解激光打印机&#xff0c;我们为企业定制了激光打印机3D产品说明书&#xff0c;将为您带…

unity中压缩文件与解压文件

今天研究了一下在unity中 把文件压缩后转二进制发送到服务器并从服务器下载后解压使用文件&#xff0c;废话不多说直接上代码&#xff0c;zip压缩插件是用的dotnetzip插件&#xff0c;网上可以搜索下载这个dll private static void GetPathMeshData_ZIP(Milling_ProjectData da…

kotlin根据文件的filePath转化为uri

方法实现 使用File类来创建一个文件对象&#xff0c;然后通过FileProvider来获取文件的URI import android.content.Context import android.net.Uri import androidx.core.content.FileProvider import java.io.Filefun getFileUri(context: Context, filePath: String): Ur…

Delta模拟器:iOS上的复古游戏天堂

Delta模拟器&#xff1a;iOS上的复古游戏天堂 在数字时代&#xff0c;我们有时会怀念起那些早期的电子游戏&#xff0c;它们简单、纯粹&#xff0c;带给我们无尽的乐趣。虽然现在的游戏在画质和玩法上都有了巨大的提升&#xff0c;但那种复古的感觉却始终无法替代。幸运的是&a…

【漏洞复现】用友政务财务系统 FileDownload 任意文件读取漏洞

0x01 产品简介 用友政务财务系统是面向政府部门、事业单位、非赢利组织的全方位业务管理信息化解决方案提供商。该系统具备一系列的功能特点,能够满足不同规模和类型企业的财务管理需求。 0x02 漏洞概述 用友政务财务系统存在任意文件读取漏洞,未授权的攻击者可以通过该漏…

算法-动态规划专题

文章目录 前言 : 动态规划简述1 . 斐波那契模型1.1 泰波那契数列1.2 最小花费爬楼梯1.3 解码方法 前言 : 动态规划简述 动态规划在当前我们的理解下,其实就是一种变相的递归,我们查看一些资料也可以知道,动态规划其实属于递归的一个分支,通过把递归问题开辟的栈帧通过一定的手…

Qt : 禁用控件默认的鼠标滚轮事件

最近在写一个模拟器&#xff0c;在item中添加了很多的控件&#xff0c;这些控件默认是支持鼠标滚动事件的。在数据量特别大的时候&#xff0c;及容易不小心就把数据给修改了而不自知。所有&#xff0c;我们这里需要禁用掉这些控件的鼠标滚轮事件。 实现的思想很简单&#xff0c…

先进制造aps专题三 为什么java语言不适合作为aps算法的开发语言

为什么java语言不适合作为aps算法的开发语言 主要两个原因 1 java的list在特定位置插入&#xff0c;其实是重新生成一个新list,而不像c就是指针操作 2 数据量大&#xff0c;运行时间长&#xff0c;会跑崩 所以商业aps产品&#xff0c;都是清一色的用c写aps算法 先进制造…

物联网鸿蒙实训解决方案

一、建设背景 在数字化浪潮汹涌的时代&#xff0c;华为鸿蒙系统以其前瞻的技术视野和创新的开发理念&#xff0c;成为了引领行业发展的风向标。 据华为开发者大会2023&#xff08;HDC. Together&#xff09;公布的数据&#xff0c;鸿蒙生态系统展现出了强劲的发展动力&#x…

mybatis-plus 动态表名简易使用

场景&#xff1a;由于有些表是分表的&#xff0c;需要给表名添加后缀才能正确地访问表&#xff0c;如sys_user_2024_01 代码 依赖版本 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><ve…

mysql机试题笔记425

题目 Sql题&#xff0c;有一个学生信息表&#xff0c; stu_info_table(stu_id, name, class) 和一张学生成绩表 stu_score_table(stu_id, course_id, score) 和一张课程表 stu_course(course_id, course_name)因为有可能存在挂科&#xff0c;所以在学生成绩表中&#xff0c; 一…

Swift 中如何四舍五入

在 Swift 中&#xff0c;你可以使用不同的方法来进行四舍五入操作&#xff0c;具体取决于你的需求和场景。以下是几种常见的方法&#xff1a; round()函数 round()函数可以对浮点数进行四舍五入&#xff0c;并返回最接近的整数。 let number 3.75let roundedNumber round(n…

Docker——开源的应用容器的引擎

目录 一、前言 1.虚拟化产品有哪些 1.1寄居架构 1.2源生架构 2.虚拟化产品对比/介绍 2.1虚拟化产品 2.1.1仿真虚拟化 2.1.2半虚拟化 2.1.3全虚拟化 2.2重点 2.2.1KVM——Linux内核来完成的功能和性能 2.2.2ESXI——用的比较多 二、Docker概述 1.Docker定义 2.Do…

代码随想录训练营Day 32|Python|Leetcode|● 738.单调递增的数字

738.单调递增的数字 当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单调递增的。 给定一个整数 n &#xff0c;返回 小于或等于 n 的最大数字&#xff0c;且数字呈 单调递增 。 解题思路&#xff1a; 对于所给数字进行str()并从后向前…

[ACTF2020 新生赛]BackupFile 1 [极客大挑战 2019]BuyFlag 1 [护网杯 2018]easy_tornado 1

目录 [ACTF2020 新生赛]BackupFile 1 1.打开页面&#xff0c;叫我们去找源文件 2.想到用disearch扫描&#xff0c;发现源文件index.php.bak 3.访问这个文件&#xff0c;下载一个文件&#xff0c;用记事本打开 4.翻译php代码 5.构造payload url/?key123&#xff0c;得到fl…

MemFire案例-政务应急物联网实时监测预警项目

客户背景 党的十八大以来&#xff0c;中央多次就应急管理工作做出重要指示&#xff1a;要求坚持以防为主、防抗救相结合&#xff0c;全面提升综合防灾能力&#xff1b;坚持生命至上、安全第一&#xff0c;完善安全生产责任制&#xff0c;坚决遏制重特大安全事故。 面对新形势…