diff --git a/tamguo-crawler/src/main/java/com/tamguo/config/redis/CacheService.java b/tamguo-crawler/src/main/java/com/tamguo/config/redis/CacheService.java index 8498300..285bbb3 100644 --- a/tamguo-crawler/src/main/java/com/tamguo/config/redis/CacheService.java +++ b/tamguo-crawler/src/main/java/com/tamguo/config/redis/CacheService.java @@ -11,108 +11,125 @@ import redis.clients.jedis.ShardedJedis; /** * 缓存中心 - * + * 该类主要用于提供与 Redis 缓存相关的操作服务,是对 Redis 功能的一层封装,方便在项目中统一管理和使用缓存功能。 */ @Service("cacheService") public class CacheService { - private final static String REDIS_PRE_KEY = "TAMGUO:"; - private SerializeTranscoder objectSerialize = new ObjectUtil(); - @Autowired - private RedisXMLConfigure redisXMLConfigure; + // 定义一个常量作为 Redis 中键的前缀,用于区分不同项目或者模块在 Redis 中的数据,统一添加前缀便于管理和识别。 + private final static String REDIS_PRE_KEY = "TAMGUO:"; + // 创建一个用于对象序列化和反序列化的工具类实例,用于处理需要存入 Redis 的对象,使其能以合适的格式在 Redis 中存储和读取。 + private SerializeTranscoder objectSerialize = new ObjectUtil(); - /** - * - * @Title: get @Description: @param @return String 返回类型 @throws - */ - public String get(String key) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - return conn.get(key); - } finally { - redisXMLConfigure.closeConnection(conn); - } - } + // 通过 Spring 的依赖注入,自动装配 RedisXMLConfigure 实例,该实例可能用于配置 Redis 连接相关信息以及获取和关闭连接等操作。 + @Autowired + private RedisXMLConfigure redisXMLConfigure; - /** - * - * @Title: set @Description: @param @return void 返回类型 @throws - */ - public void set(String key, String value) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - conn.set(key, value); - } finally { - redisXMLConfigure.closeConnection(conn); - } - } + /** + * 根据传入的键获取对应的值,如果键在 Redis 中存在,则返回对应的值,否则返回 null。 + * + * @param key 要获取值的键,在实际操作前会先添加 REDIS_PRE_KEY 前缀。 + * @return 返回对应键在 Redis 中存储的字符串值,如果不存在则返回 null。 + */ + public String get(String key) { + // 给传入的键添加前缀,使其符合项目在 Redis 中键的规范格式。 + key = getPreKey(key); + ShardedJedis conn = null; + try { + // 通过 RedisXMLConfigure 获取 Redis 连接对象,ShardedJedis 通常用于在 Redis 集群等场景下获取连接进行操作。 + conn = redisXMLConfigure.getConnection(); + // 使用获取到的连接对象,调用 get 方法从 Redis 中获取对应键的值。 + return conn.get(key); + } finally { + // 无论是否成功获取到值,都需要关闭 Redis 连接,通过 RedisXMLConfigure 提供的方法来关闭连接,释放资源。 + redisXMLConfigure.closeConnection(conn); + } + } - /** - * - * set 设置带过期时间的字符缓存 - * - * @param key - * @param value - * @param time - * 过期时间,秒 - * @description - * @exception @since - * 1.0.0 - */ - public void set(String key, String value, int time) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - conn.set(key, value); - conn.expire(key, time); - } finally { - redisXMLConfigure.closeConnection(conn); - } - } + /** + * 将键值对存入 Redis 中,如果键已存在则覆盖原有值。 + * + * @param key 要存入的键,同样会先添加前缀。 + * @param value 要存入的字符串值。 + */ + public void set(String key, String value) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + conn.set(key, value); + } finally { + redisXMLConfigure.closeConnection(conn); + } + } - /** - * redis中存放对象 - * - * @param key 对象key - * @param value 可序列化的对象 - */ - public void setObject(String key, Object value) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - conn.set(key.getBytes(), objectSerialize.serialize(value)); - } catch (Exception ex) { - ex.printStackTrace(); - } finally { - redisXMLConfigure.closeConnection(conn); - } - } + /** + * set 设置带过期时间的字符缓存 + * 设置键值对存入 Redis 中,并指定过期时间,一旦超过过期时间,对应键值对将自动从 Redis 中删除。 + * + * @param key 要存入的键,会先添加前缀。 + * @param value 要存入的字符串值。 + * @param time 过期时间,单位为秒,表示键值对在 Redis 中有效的时长。 + */ + public void set(String key, String value, int time) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + conn.set(key, value); + // 在设置完键值对后,调用 expire 方法设置对应键的过期时间。 + conn.expire(key, time); + } finally { + redisXMLConfigure.closeConnection(conn); + } + } - /** - * 设置过期时间存储对象 - * - * @param key 对象key - * @param value 对象值 - * @param time 过期时间 秒 - */ - public void setObject(String key, Object value, int time) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - conn.setex(key.getBytes(), time, objectSerialize.serialize(value)); - } catch (Exception ex) { - ex.printStackTrace(); - } finally { - redisXMLConfigure.closeConnection(conn); - } - } + /** + * redis中存放对象 + * 将可序列化的对象存入 Redis 中,通过 SerializeTranscoder 将对象进行序列化后再存入,以便能在 Redis 中存储对象类型的数据。 + * + * @param key 对象键,同样会先添加前缀,用于在 Redis 中唯一标识该对象。 + * @param value 可序列化的对象,即需要实现了序列化接口的对象,才能正确存入 Redis。 + */ + public void setObject(String key, Object value) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 将键转换为字节数组形式(因为 Redis 的底层存储很多操作是基于字节数组的), + // 并使用 objectSerialize 工具类将对象序列化后存入 Redis。 + conn.set(key.getBytes(), objectSerialize.serialize(value)); + } catch (Exception ex) { + // 如果在序列化或者存入过程中出现异常,打印异常堆栈信息,方便排查问题。 + ex.printStackTrace(); + } finally { + redisXMLConfigure.closeConnection(conn); + } + } + + /** + * 设置过期时间存储对象 + * 将可序列化的对象存入 Redis 中,并同时指定过期时间,在过期时间后对象将自动从 Redis 中删除。 + * + * @param key 对象键,先添加前缀后用于存储。 + * @param value 对象值,需要是可序列化的对象。 + * @param time 过期时间,单位为秒,控制对象在 Redis 中的有效时长。 + */ + public void setObject(String key, Object value, int time) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 使用 setex 方法,它可以在设置对象值的同时直接指定过期时间,一次性完成存储和过期时间设置操作, + // 先将键转换为字节数组,再将序列化后的对象存入 Redis,并设置过期时间。 + conn.setex(key.getBytes(), time, objectSerialize.serialize(value)); + } catch (Exception ex) { + ex.printStackTrace(); + } finally { + redisXMLConfigure.closeConnection(conn); + } + } +} /** * 获取存储的对象 @@ -120,79 +137,101 @@ public class CacheService { * @param key 对象key * @return 存储的对象 */ - public Object getObject(String key) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - byte[] obj = conn.get(key.getBytes()); - if (null == obj) - return null; - return objectSerialize.deserialize(obj); - } catch (Exception ex) { - ex.printStackTrace(); - } finally { - redisXMLConfigure.closeConnection(conn); - } - return null; - } + // 根据给定的键从Redis中获取对应的对象。先对键添加前缀处理,然后通过Redis连接获取对象数据,若获取到数据则进行反序列化后返回,若出现异常或未获取到数据则返回null。 + public Object getObject(String key) { + // 给传入的键添加前缀,使其符合项目在Redis中键的规范格式,便于统一管理和准确获取对应的数据。 + key = getPreKey(key); + ShardedJedis conn = null; + try { + // 通过RedisXMLConfigure获取Redis连接对象,ShardedJedis用于在Redis集群等场景下进行操作,以便后续与Redis进行交互。 + conn = redisXMLConfigure.getConnection(); + // 从Redis中获取以字节数组形式存储的对象数据,因为Redis底层很多操作基于字节数组来处理数据存储和读取。 + byte[] obj = conn.get(key.getBytes()); + // 如果获取到的字节数组为null,说明Redis中不存在对应键的数据,直接返回null。 + if (null == obj) + return null; + // 使用objectSerialize工具类对获取到的字节数组进行反序列化操作,将其转换为原始的对象形式并返回。 + return objectSerialize.deserialize(obj); + } catch (Exception ex) { + // 如果在获取数据或者反序列化过程中出现异常,打印异常堆栈信息,方便排查问题所在。 + ex.printStackTrace(); + } finally { + // 无论是否成功获取到对象,都需要关闭Redis连接,通过RedisXMLConfigure提供的方法来关闭连接,释放相关资源。 + redisXMLConfigure.closeConnection(conn); + } + return null; + } - /** - * 删除一个对象 - * - * @param key 对象key值 - * @return - */ - public boolean deleteObject(String key) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - return conn.del(key.getBytes()) == 1L; - } catch (Exception ex) { - ex.printStackTrace(); - } finally { - redisXMLConfigure.closeConnection(conn); - } - return false; - } +/** + * 删除一个对象 + * 该方法用于从Redis中删除指定键对应的对象数据,先对键添加前缀处理,然后尝试通过Redis连接执行删除操作, + * 如果删除操作成功(即返回值表示删除的键数量为1)则返回true,若出现异常或删除失败则返回false。 + * + * @param key 对象key值,即要删除的对象在Redis中对应的键。 + * @return 返回一个布尔值,表示是否成功删除对象,true表示删除成功,false表示删除失败或出现异常情况。 + */ +public boolean deleteObject(String key) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用Redis连接对象的del方法,传入要删除的对象键的字节数组形式,尝试删除对应的数据。 + // 该方法返回被删除键的数量,若返回值等于1L,表示成功删除了1个键(即对应要删除的对象键),则返回true,否则返回false。 + return conn.del(key.getBytes()) == 1L; + } catch (Exception ex) { + ex.printStackTrace(); + } finally { + redisXMLConfigure.closeConnection(conn); + } + return false; +} - /** - * - * @Title: isExist @Description: 判断key是否存在 @param @return boolean - * 返回类型 @throws - */ - public boolean isExist(String key) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - return conn.exists(key); - } catch (Exception ex) { - ex.printStackTrace(); - } finally { - redisXMLConfigure.closeConnection(conn); - } - return false; - } - - public boolean notExist(String key) { - return !isExist(key); - } - - public boolean delete(String key) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - return conn.del(key) == 1; - } catch (Exception ex) { - ex.printStackTrace(); - } finally { - redisXMLConfigure.closeConnection(conn); - } - return false; - } +/** + * 判断key是否存在 + * 通过给定的键,先添加前缀使其符合项目规范后,尝试从Redis中查询该键是否存在, + * 如果存在则返回true,若出现异常或键不存在则返回false。 + * + * @Title: isExist + * @Description: 判断key是否存在 + * @param key 要检查是否存在的键。 + * @return 返回一个布尔值,表示键是否存在于Redis中,true表示存在,false表示不存在或者出现异常情况。 + */ +public boolean isExist(String key) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用Redis连接对象的exists方法,传入要检查的键,该方法会在Redis中查询该键是否存在,存在则返回true,不存在返回false。 + return conn.exists(key); + } catch (Exception ex) { + ex.printStackTrace(); + } finally { + redisXMLConfigure.closeConnection(conn); + } + return false; +} + +// 对isExist方法的结果取反,用于判断给定的键在Redis中是否不存在,返回值为true表示键不存在,false表示键存在。 +public boolean notExist(String key) { + return!isExist(key); +} + +// 从Redis中删除指定的键及其对应的数据,先对键添加前缀处理,然后通过Redis连接执行删除操作, +// 如果删除操作成功(即返回值表示删除的键数量为1)则返回true,若出现异常或删除失败则返回false。 +public boolean delete(String key) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用Redis连接对象的del方法,传入要删除的键,该方法返回被删除键的数量,若返回值等于1,表示成功删除了1个键(即对应要删除的键),则返回true,否则返回false。 + return conn.del(key) == 1; + } catch (Exception ex) { + ex.printStackTrace(); + } finally { + redisXMLConfigure.closeConnection(conn); + } + return false; +} /** * 关于 redis list的操作 将 值 value 插入到列表 key 的表尾(最右边)。 @@ -201,288 +240,359 @@ public class CacheService { * @param value * @return */ - public long putToListEnd(String key, String value) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - long length = conn.rpush(key, value); - return length; - } finally { - redisXMLConfigure.closeConnection(conn); - } - } + // 将指定的值插入到以给定键标识的列表(List)的末尾,并返回插入操作后列表的长度。 +// 先对键添加前缀进行规范处理,然后通过获取的 Redis 连接执行插入操作,最后返回列表长度。 + public long putToListEnd(String key, String value) { + // 给传入的键添加前缀,使其符合项目在 Redis 中键的规范格式,便于准确操作对应的列表数据。 + key = getPreKey(key); + ShardedJedis conn = null; + try { + // 通过 RedisXMLConfigure 获取 Redis 连接对象,用于后续与 Redis 进行交互操作。 + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 rpush 方法,将指定的值插入到键对应的列表末尾, + // 该方法会返回操作后列表的长度,即元素个数,然后将此长度返回给调用者。 + long length = conn.rpush(key, value); + return length; + } finally { + // 无论插入操作是否成功,都需要关闭 Redis 连接,通过 RedisXMLConfigure 提供的方法来关闭连接,释放资源。 + redisXMLConfigure.closeConnection(conn); + } + } - /** - * 将value插入集合key的尾部, 并设置过期时间 - * - * @author zhangxin - * @param key - * @param value - * @param seconds - * @param score - * @return long 被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员 - */ - public long addToSortedSetAndExpire(String key, String value, int seconds, double score) { - return addToSortedSet(key, value, seconds, true, score); - } - - - /** - * 将value插入集合key的尾部 增加value的score - * - * @author zhangxin - * @param key - * @param value - * @param score - * @return long 被成功添加的新成员的分数 - */ - public double addToSortedSetScore(String key, String value, double score) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - Double zincrby = conn.zincrby(key, score, value); - return zincrby; - } finally { - redisXMLConfigure.closeConnection(conn); - } - } - - /** - * 获取member的Score - * @param key - * @param value - * @return - */ - public Double getMemberScore(String key, String member) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - Double zscore = conn.zscore(key, member); - return zscore == null ? 0 : zscore; - } finally { - redisXMLConfigure.closeConnection(conn); - } - } - +/** + * 将value插入集合key的尾部, 并设置过期时间 + * 该方法用于将给定的值插入到有序集合(Sorted Set)中,并为该有序集合设置过期时间, + * 实际调用了 addToSortedSet 方法进行插入操作,传入合适的参数来实现带过期时间的插入功能。 + * + * @author zhangxin + * @param key 有序集合对应的键,用于在 Redis 中唯一标识该有序集合。 + * @param value 要插入到有序集合中的值。 + * @param seconds 过期时间,单位为秒,表示有序集合在 Redis 中有效的时长,超过该时间后集合将自动被删除。 + * @param score 用于给插入的元素设置一个分数(score),有序集合会根据元素的分数来进行排序。 + * @return long 被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员,这里返回值实际上是调用 addToSortedSet 方法后的返回结果。 + */ +public long addToSortedSetAndExpire(String key, String value, int seconds, double score) { + return addToSortedSet(key, value, seconds, true, score); +} - /** - * 将value插入集合key的尾部, 不设置过期时间 - * - * @author zhangxin - * @param key - * @param value - * @param score - * @return long 被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员 - */ - public long addToSortedSet(String key, String value, double score) { - return addToSortedSet(key, value, -1, false, score); - } - - - /** - * 判断member在集合里是否存在 - * - * @return isExist 存在 true 不存在 - */ - public boolean isExistSortedSet(String key, String member) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - Long zrank = conn.zrank(key, member); - return zrank != null; - } finally { - redisXMLConfigure.closeConnection(conn); - } - } +/** + * 将value插入集合key的尾部 增加value的score + * 此方法用于将给定的值插入到有序集合(Sorted Set)的末尾,并增加该值对应的分数(score), + * 通过获取 Redis 连接,调用相应的 Redis 命令来实现该功能,最后返回更新后的分数值。 + * + * @author zhangxin + * @param key 有序集合对应的键,用于在 Redis 中唯一标识该有序集合。 + * @param value 要插入到有序集合中的值。 + * @param score 要增加的分数值,用于更新该值在有序集合中的排序位置等相关逻辑。 + * @return long 被成功添加的新成员的分数,这里返回的是操作后该成员对应的新分数值,通过 Redis 的 zincrby 命令返回的结果转换得到。 + */ +public double addToSortedSetScore(String key, String value, double score) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 zincrby 方法,将指定的值插入到键对应的有序集合中,并按照给定的分数增量(score)增加其分数, + // 该方法返回更新后的分数值(以 Double 类型表示),然后将此分数值返回给调用者。 + Double zincrby = conn.zincrby(key, score, value); + return zincrby; + } finally { + redisXMLConfigure.closeConnection(conn); + } +} + +/** + * 获取member的Score + * 用于获取给定成员(member)在指定有序集合(以键 key 标识)中的分数(score)值, + * 如果成员不存在于有序集合中,则返回默认值 0,否则返回其实际的分数值。 + * + * @param key 有序集合对应的键,用于在 Redis 中唯一标识该有序集合。 + * @param value 有序集合中的成员,即要获取其分数值的元素。 + * @return 返回该成员对应的分数值,如果成员不存在则返回 0,通过 Redis 的 zscore 命令获取并进行相应的返回值处理。 + */ +public Double getMemberScore(String key, String member) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 zscore 方法,尝试获取指定成员在键对应的有序集合中的分数值, + // 该方法返回的分数值可能为 null(表示成员不存在),若为 null 则返回默认值 0,否则返回实际的分数值。 + Double zscore = conn.zscore(key, member); + return zscore == null? 0 : zscore; + } finally { + redisXMLConfigure.closeConnection(conn); + } +} + +/** + * 将value插入集合key的尾部, 不设置过期时间 + * 此方法用于将给定的值插入到有序集合(Sorted Set)的末尾,不设置过期时间, + * 实际是调用 addToSortedSet 方法并传入合适的参数来实现不带过期时间的插入功能,返回插入操作后成功添加的新成员数量。 + * + * @author zhangxin + * @param key 有序集合对应的键,用于在 Redis 中唯一标识该有序集合。 + * @param value 要插入到有序集合中的值。 + * @param score 用于给插入的元素设置一个分数(score),有序集合会根据元素的分数来进行排序。 + * @return long 被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员,这里返回值实际上是调用 addToSortedSet 方法后的返回结果。 + */ +public long addToSortedSet(String key, String value, double score) { + return addToSortedSet(key, value, -1, false, score); +} + +/** + * 判断member在集合里是否存在 + * 通过检查给定成员(member)在指定有序集合(以键 key 标识)中的排名(rank)情况, + * 来判断该成员是否存在于有序集合中,若排名不为 null,则表示成员存在,返回 true,否则返回 false。 + * + * @return isExist 存在 true 不存在 false,表示给定成员是否存在于指定的有序集合中。 + */ +public boolean isExistSortedSet(String key, String member) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 zrank 方法,获取指定成员在键对应的有序集合中的排名, + // 如果成员存在于集合中,该方法返回其排名(Long 类型),若不存在则返回 null, + // 根据返回值是否为 null 来判断成员是否存在,并返回相应的布尔值结果。 + Long zrank = conn.zrank(key, member); + return zrank!= null; + } finally { + redisXMLConfigure.closeConnection(conn); + } +} /** * 删除member * * @return isExist 存在 true 不存在 */ - public boolean delSortedSetMember(String key, String[] member) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - Long zrem = conn.zrem(key, member); - return zrem >= 1; - } finally { - redisXMLConfigure.closeConnection(conn); - } - } + // 从指定的有序集合(Sorted Set)中删除给定的成员(member),并根据删除操作的结果返回一个布尔值表示是否删除成功。 +// 成功删除至少一个成员时返回 true,否则返回 false。先对键添加前缀规范处理,再通过 Redis 连接执行删除操作并判断结果。 + public boolean delSortedSetMember(String key, String[] member) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 zrem 方法,传入有序集合的键和要删除的成员数组,尝试从有序集合中删除这些成员。 + // 该方法返回被成功删除的成员数量(Long 类型),通过判断返回值是否大于等于 1 来确定是否至少成功删除了一个成员,进而返回相应的布尔值结果。 + Long zrem = conn.zrem(key, member); + return zrem >= 1; + } finally { + // 无论删除操作是否成功,都要关闭 Redis 连接,通过 RedisXMLConfigure 提供的方法来释放资源。 + redisXMLConfigure.closeConnection(conn); + } + } - /** - * 将value插入集合key的尾部, 对于setExpire为false的情况, seconds无效 - * - * @return 被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员 - */ - private long addToSortedSet(String key, String value, int seconds, boolean setExpire, double score) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - long addNum = conn.zadd(key, score, value); - if (setExpire) { - conn.expire(key, seconds); - } - return addNum; - } finally { - redisXMLConfigure.closeConnection(conn); - } - } +/** + * 将value插入集合key的尾部, 对于setExpire为false的情况, seconds无效 + * 此方法是一个私有方法,用于将给定的值插入到有序集合(Sorted Set)中,并可根据参数决定是否设置过期时间。 + * 返回值为被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。 + * + * @param key 有序集合对应的键,用于在 Redis 中唯一标识该有序集合。 + * @param value 要插入到有序集合中的值。 + * @param seconds 过期时间,单位为秒,当 setExpire 参数为 true 时,此参数用于设置有序集合的过期时间,否则无效。 + * @param setExpire 布尔值,表示是否设置过期时间,为 true 时设置过期时间,为 false 则不设置。 + * @param score 用于给插入的元素设置一个分数(score),有序集合会根据元素的分数来进行排序。 + * @return long 被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员,通过 Redis 的 zadd 命令插入元素后返回相应的添加数量结果。 + */ +private long addToSortedSet(String key, String value, int seconds, boolean setExpire, double score) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 zadd 方法,将指定的值按照给定的分数(score)插入到键对应的有序集合中, + // 该方法返回成功添加的新成员数量(不包含已存在被更新的成员情况),将此数量赋值给 addNum 变量。 + long addNum = conn.zadd(key, score, value); + if (setExpire) { + // 如果 setExpire 参数为 true,调用 Redis 连接对象的 expire 方法,为有序集合设置过期时间(以 seconds 参数指定的秒数为准)。 + conn.expire(key, seconds); + } + return addNum; + } finally { + redisXMLConfigure.closeConnection(conn); + } +} - /** - * 按score降序分页获取有序集合中内容 - * - * @author zhangxin - * @param key - * @param pageNo - * 首页从1开始 - * @param pageSize - * @return Set - */ - public Set getSortedSetByPage(String key, int pageNo, int pageSize) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - if (pageNo < 1) { - pageNo = 1; - } - if (pageSize < 1) { - pageSize = 1; - } - int start = (pageNo - 1) * pageSize; - conn = redisXMLConfigure.getConnection(); - return conn.zrevrange(key, start, start + pageSize - 1); - } catch (Exception ex) { - ex.printStackTrace(); - } finally { - redisXMLConfigure.closeConnection(conn); - } - return null; - } - - public List getListHead(String key) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - List result = conn.blpop(1000, key); - - if (null == result || result.size() == 0) - return null; - return result; - } finally { - redisXMLConfigure.closeConnection(conn); - } - } +/** + * 按score降序分页获取有序集合中内容 + * 按照分数(score)降序的顺序,对指定的有序集合进行分页查询,获取对应页面范围的成员内容,返回以字符串集合(Set)形式表示的结果。 + * + * @author zhangxin + * @param key 有序集合对应的键,用于在 Redis 中唯一标识该有序集合。 + * @param pageNo 页码,首页从 1 开始,表示要获取第几页的数据,若传入小于 1 的值,则会自动修正为 1。 + * @param pageSize 每页显示的记录数量,若传入小于 1 的值,则会自动修正为 1。 + * @return Set 返回对应页面范围内的有序集合成员内容,以集合形式返回,如果出现异常则返回 null。 + */ +public Set getSortedSetByPage(String key, int pageNo, int pageSize) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + // 对传入的页码进行合法性校验,如果小于 1,则将其修正为 1,确保页码从 1 开始计数。 + if (pageNo < 1) { + pageNo = 1; + } + // 对传入的每页记录数量进行合法性校验,如果小于 1,则将其修正为 1,确保每页至少有 1 条记录。 + if (pageSize < 1) { + pageSize = 1; + } + // 根据页码和每页记录数量计算出在有序集合中查询的起始索引位置,用于分页获取数据。 + int start = (pageNo - 1) * pageSize; + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 zrevrange 方法,按照分数降序的顺序,从指定的有序集合中获取从起始索引到结束索引(通过计算得出)范围内的成员内容, + // 并将结果以集合形式返回,集合中的元素为有序集合的成员(以字符串形式表示)。 + return conn.zrevrange(key, start, start + pageSize - 1); + } catch (Exception ex) { + // 如果在获取数据过程中出现异常,打印异常堆栈信息,方便排查问题,然后返回 null。 + ex.printStackTrace(); + } finally { + redisXMLConfigure.closeConnection(conn); + } + return null; +} - /** - * 存储map - * - * @param key 键值 - * @param field map field - * @param value map value - * @return if filed exist return 0 else return 1 - */ - public Long hset(String key, String field, String value) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - return conn.hset(key, field, value); - } finally { - redisXMLConfigure.closeConnection(conn); - } - } - - public String hset(String key, Map values) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - return conn.hmset(key, values); - } finally { - redisXMLConfigure.closeConnection(conn); - } - } - - public String hset(String key, Map values, int time) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - String hmset = conn.hmset(key, values); - conn.expire(key, time); - return hmset; - } finally { - redisXMLConfigure.closeConnection(conn); - } - } +// 从以给定键标识的列表(List)头部获取元素,返回获取到的元素列表(List),如果列表为空或者获取操作出现异常则返回 null。 +public List getListHead(String key) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 blpop 方法,尝试从列表头部获取元素,传入超时时间(这里是 1000 毫秒)和列表键, + // 该方法会阻塞等待元素出现,直到超时或者获取到元素,返回获取到的元素列表(可能包含一个或多个元素,以 List 形式表示)。 + List result = conn.blpop(1000, key); - /** - * 得到map中存储的field值 - * - * @param key 键值 - * @param field map field - * @return - */ - public String hget(String key, String field) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - return conn.hget(key, field); - } finally { - redisXMLConfigure.closeConnection(conn); - } - } + // 如果获取到的结果为 null 或者结果列表大小为 0(即没有获取到元素),则返回 null,表示列表为空或获取失败。 + if (null == result || result.size() == 0) + return null; + return result; + } finally { + redisXMLConfigure.closeConnection(conn); + } +} - /** - * 名称为key的string减1操作 - * - * @param key - * @return - */ - public Long decr(String key) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - return conn.decr(key); - } finally { - redisXMLConfigure.closeConnection(conn); - } - } - - /** - * 名称为key的string加1操作 - * - * @param key - * @return - */ - public Long incr(String key) { - key = getPreKey(key); - ShardedJedis conn = null; - try { - conn = redisXMLConfigure.getConnection(); - return conn.incr(key); - } finally { - redisXMLConfigure.closeConnection(conn); - } - } - - private String getPreKey(String key) { - String temp_pre = redisXMLConfigure.getPreKey(); - if (null == temp_pre) { - return REDIS_PRE_KEY + key; - } - return temp_pre + key; - } +/** + * 存储map + * 此方法用于将单个键值对存储到 Redis 的哈希(Hash)数据结构中,对应的键(key)下的指定字段(field)中, + * 返回值表示如果字段已存在则返回 0,否则返回 1,表示插入操作的结果情况。 + * + * @param key 键值,用于在 Redis 中定位到对应的哈希数据结构所在的位置,类似哈希表的名称。 + * @param field map field,哈希表中的字段名,用于在对应的哈希结构下唯一标识一个键值对。 + * @param value map value,要存储到指定字段下的值,即哈希表中字段对应的值内容。 + * @return if filed exist return 0 else return 1,表示如果指定的字段在哈希表中已存在,则返回 0,若不存在则返回 1,根据 Redis 的 hset 命令的返回规则确定。 + */ +public Long hset(String key, String field, String value) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 hset 方法,将指定的键(key)、字段(field)和值(value)存储到 Redis 的哈希数据结构中, + // 该方法会根据字段是否已存在返回相应的结果(已存在返回 0,不存在返回 1),将此结果返回给调用者。 + return conn.hset(key, field, value); + } finally { + redisXMLConfigure.closeConnection(conn); + } +} + +// 存储map +// 此方法用于将整个映射(Map)存储到 Redis 的哈希(Hash)数据结构中,以给定的键(key)作为哈希表的标识,一次性存储多个键值对。 +// 返回值为存储操作后的结果信息(具体含义可能取决于 Redis 底层实现对应的返回值情况)。 +public String hset(String key, Map values) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 hmset 方法,将给定的映射(包含多个键值对的 Map)存储到指定键对应的哈希数据结构中, + // 该方法会执行批量存储操作,并返回相应的结果信息(通常用于表示操作是否成功等情况),将此结果返回给调用者。 + return conn.hmset(key, values); + } finally { + redisXMLConfigure.closeConnection(conn); + } +} + +// 将给定的映射(Map)存储到 Redis 的哈希(Hash)数据结构中,并为该哈希数据结构设置过期时间。 +// 先获取 Redis 连接,执行存储操作后设置过期时间,最后返回存储操作的结果信息。 +public String hset(String key, Map values, int time) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 hmset 方法,将包含多个键值对的映射(values)存储到以 key 为标识的哈希数据结构中, + // 该方法执行存储操作后会返回相应的结果信息(通常用于表示操作是否成功等情况),将此结果暂存到 hmset 变量中。 + String hmset = conn.hmset(key, values); + // 调用 Redis 连接对象的 expire 方法,为以 key 为标识的哈希数据结构设置过期时间,单位为秒,由 time 参数指定。 + conn.expire(key, time); + return hmset; + } finally { + // 无论存储和设置过期时间操作是否成功,都要关闭 Redis 连接,通过 RedisXMLConfigure 提供的方法来释放资源。 + redisXMLConfigure.closeConnection(conn); + } +} + +/** + * 得到map中存储的field值 + * 此方法用于从 Redis 的哈希(Hash)数据结构中,根据给定的键(key)和字段(field)获取对应的值,返回获取到的字符串值。 + * + * @param key 键值,用于在 Redis 中定位到对应的哈希数据结构所在的位置,类似哈希表的名称。 + * @param field map field,哈希表中的字段名,用于在对应的哈希结构下唯一标识一个键值对,通过该字段名获取对应的值。 + * @return 返回在指定哈希数据结构中,对应字段存储的字符串值,如果字段不存在则返回 null(取决于 Redis 的 hget 方法返回值情况)。 + */ +public String hget(String key, String field) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 hget 方法,从以 key 为标识的哈希数据结构中获取指定字段(field)对应的字符串值, + // 并将获取到的值直接返回给调用者。 + return conn.hget(key, field); + } finally { + redisXMLConfigure.closeConnection(conn); + } +} + +/** + * 名称为key的string减1操作 + * 对 Redis 中以给定键(key)标识的字符串类型的值执行减 1 操作,返回操作后的结果值(以 Long 类型表示)。 + * + * @param key 要进行减 1 操作的键,对应 Redis 中存储的字符串类型的数据的键名。 + * @return 返回减 1 操作后的结果值(Long 类型),如果键对应的值不存在,则 Redis 会按照默认规则进行处理(通常初始化为 0 后再减 1),返回相应的结果。 + */ +public Long decr(String key) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 decr 方法,对以 key 为标识的字符串值执行减 1 操作, + // 该方法会自动将字符串值转换为数字类型(如果能转换成功)进行减 1 操作,并返回操作后的结果(以 Long 类型表示),将此结果返回给调用者。 + return conn.decr(key); + } finally { + redisXMLConfigure.closeConnection(conn); + } +} + +/** + * 名称为key的string加1操作 + * 对 Redis 中以给定键(key)标识的字符串类型的值执行加 1 操作,返回操作后的结果值(以 Long 类型表示)。 + * + * @param key 要进行加 1 操作的键,对应 Redis 中存储的字符串类型的数据的键名。 + * @return 返回加 1 操作后的结果值(Long 类型),如果键对应的值不存在,则 Redis 会按照默认规则进行处理(通常初始化为 0 后再加 1),返回相应的结果。 + */ +public Long incr(String key) { + key = getPreKey(key); + ShardedJedis conn = null; + try { + conn = redisXMLConfigure.getConnection(); + // 调用 Redis 连接对象的 incr 方法,对以 key 为标识的字符串值执行加 1 操作, + // 该方法会自动将字符串值转换为数字类型(如果能转换成功)进行加 1 操作,并返回操作后的结果(以 Long 类型表示),将此结果返回给调用者。 + return conn.incr(key); + } finally { + redisXMLConfigure.closeConnection(conn); + } +} +// 获取处理后的键,用于在 Redis 操作前统一添加前缀,使键符合项目在 Redis 中的命名规范。 +// 如果通过 redisXMLConfigure 获取到的前缀为空,则使用类中定义的默认前缀(REDIS_PRE_KEY)与传入的键拼接,否则使用获取到的前缀与键拼接。 +private String getPreKey(String key) { + String temp_pre = redisXMLConfigure.getPreKey(); + if (null == temp_pre) { + return REDIS_PRE_KEY + key; + } + return temp_pre + key; } diff --git a/tamguo-crawler/src/main/java/com/tamguo/config/redis/ObjectUtil.java b/tamguo-crawler/src/main/java/com/tamguo/config/redis/ObjectUtil.java index 724149a..e11d86d 100644 --- a/tamguo-crawler/src/main/java/com/tamguo/config/redis/ObjectUtil.java +++ b/tamguo-crawler/src/main/java/com/tamguo/config/redis/ObjectUtil.java @@ -6,9 +6,13 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +// ObjectUtil类继承自SerializeTranscoder,主要用于实现对象的序列化、反序列化以及提供对象相等性比较的功能。 public class ObjectUtil extends SerializeTranscoder { + + // 重写父类的serialize方法,用于将给定的对象进行序列化操作,即将对象转换为字节数组的形式,以便在某些场景下(如存储到Redis中)进行传输或持久化存储。 @Override public byte[] serialize(Object value) { + // 如果传入要序列化的对象为null,则抛出空指针异常,因为无法对null对象进行序列化操作。 if (value == null) { throw new NullPointerException("Can't serialize null"); } @@ -16,54 +20,76 @@ public class ObjectUtil extends SerializeTranscoder { ByteArrayOutputStream bos = null; ObjectOutputStream os = null; try { + // 创建一个ByteArrayOutputStream,它用于在内存中缓冲要序列化的对象数据,最终可以转换为字节数组形式。 bos = new ByteArrayOutputStream(); + // 创建一个ObjectOutputStream,它基于ByteArrayOutputStream,用于将对象以Java的序列化机制写入到输出流中。 os = new ObjectOutputStream(bos); + // 使用ObjectOutputStream将传入的对象写入到输出流中,进行实际的序列化操作。 os.writeObject(value); + // 关闭ObjectOutputStream,释放相关资源,一般在写入完成后进行关闭操作,确保数据正确写入到输出流中。 os.close(); + // 关闭ByteArrayOutputStream,释放其占用的内存资源,此时内部缓冲的数据已经准备好可以转换为字节数组了。 bos.close(); + // 将ByteArrayOutputStream中缓冲的数据转换为字节数组,这就是最终序列化后的结果,赋值给result变量以便返回。 result = bos.toByteArray(); } catch (IOException e) { + // 如果在序列化过程中出现IO异常(比如对象不支持序列化、流操作出现问题等), + // 则抛出一个非法参数异常,并将原始的IO异常作为原因附带上,方便排查问题,表明传入的对象可能无法进行序列化操作。 throw new IllegalArgumentException("Non-serializable object", e); } finally { + // 无论是否成功完成序列化操作,都要关闭ObjectOutputStream和ByteArrayOutputStream,释放资源,避免内存泄漏等问题。 close(os); close(bos); } return result; } + // 重写父类的deserialize方法,用于将给定的字节数组进行反序列化操作,即将字节数组转换回原始的对象形式,通常用于从存储(如Redis)中读取数据后还原对象。 @Override public Object deserialize(byte[] in) { Object result = null; ByteArrayInputStream bis = null; ObjectInputStream is = null; try { - if (in != null) { + // 首先判断传入的字节数组是否为null,如果为null则不进行后续的反序列化操作,直接返回null。 + if (in!= null) { + // 创建一个ByteArrayInputStream,它以传入的字节数组作为数据源,用于后续通过输入流读取数据进行反序列化操作。 bis = new ByteArrayInputStream(in); + // 创建一个ObjectInputStream,它基于ByteArrayInputStream,用于按照Java的序列化机制从输入流中读取数据并还原为对象。 is = new ObjectInputStream(bis); + // 使用ObjectInputStream从输入流中读取数据并还原为对象,这是实际的反序列化操作,将还原后的对象赋值给result变量。 result = is.readObject(); + // 关闭ObjectInputStream,释放相关资源,确保反序列化操作完成后资源正确释放。 is.close(); + // 关闭ByteArrayInputStream,释放其占用的内存资源。 bis.close(); } } catch (IOException e) { + // 如果在反序列化过程中出现IO异常(比如读取流出现问题、数据格式不正确等),打印异常堆栈信息,方便排查问题。 e.printStackTrace(); } catch (ClassNotFoundException e) { + // 如果在反序列化过程中出现找不到对应类的异常(比如还原对象时找不到对象对应的类定义),同样打印异常堆栈信息,便于查找问题所在。 e.printStackTrace(); } finally { + // 无论是否成功完成反序列化操作,都要关闭ObjectInputStream和ByteArrayInputStream,释放资源,避免内存泄漏等问题。 close(is); close(bis); } return result; } + // 定义一个静态方法equals,用于比较两个对象是否相等,遵循Java中对象相等性比较的常规规则。 public static boolean equals(Object o1, Object o2) { + // 如果两个对象引用完全相同(即指向同一个内存地址),则直接返回true,表示它们相等。 if (o1 == o2) { return true; } else if (o1 == null || o2 == null) { + // 如果其中一个对象为null,而另一个不为null,则返回false,表示它们不相等。 return false; } else { + // 如果两个对象都不为null,调用对象的equals方法(一般需要重写该方法来定义具体的相等性逻辑)来比较它们是否相等,并返回相应的结果。 return o1.equals(o2); } } - -} +} \ No newline at end of file diff --git a/tamguo-crawler/src/main/java/com/tamguo/config/redis/PoolConfigBean.java b/tamguo-crawler/src/main/java/com/tamguo/config/redis/PoolConfigBean.java index c1b9bc1..43e3f9b 100644 --- a/tamguo-crawler/src/main/java/com/tamguo/config/redis/PoolConfigBean.java +++ b/tamguo-crawler/src/main/java/com/tamguo/config/redis/PoolConfigBean.java @@ -1,13 +1,20 @@ package com.tamguo.config.redis; +// PoolConfigBean类用于封装与连接池相关的配置参数,通过定义相应的属性、构造方法以及访问器(getter和setter)方法,方便对这些配置信息进行设置和获取操作,同时重写了toString方法用于方便地输出配置信息的字符串表示形式。 public class PoolConfigBean { + + // 表示连接池中允许的最大活动连接数,即同一时刻能够同时从连接池中获取并使用的最大连接数量。 private int max_active; + // 表示连接池中允许的最大空闲连接数,即连接池中可以闲置的最大连接数量,当空闲连接数超过这个值时,多余的空闲连接可能会被回收。 private int max_idle; + // 表示从连接池中获取连接时,最长的等待时间(单位通常为毫秒),如果在这个时间内无法获取到可用连接,则可能会抛出相应的异常,提示获取连接超时。 private long max_wait; + // 默认的无参构造方法,用于创建PoolConfigBean类的实例,在没有传入初始参数时可以使用,后续可以通过对应的setter方法来设置各个属性的值。 public PoolConfigBean() { } + // 带参数的构造方法,用于在创建PoolConfigBean类实例时,同时初始化各个配置属性的值,方便一次性设置好相关的连接池配置信息。 public PoolConfigBean(int max_active, int max_idle, long max_wait) { super(); this.max_active = max_active; @@ -15,33 +22,39 @@ public class PoolConfigBean { this.max_wait = max_wait; } + // 获取max_active属性值的方法,外部代码可以通过调用这个方法获取连接池中允许的最大活动连接数。 public int getMax_active() { return max_active; } + // 设置max_active属性值的方法,外部代码可以通过调用这个方法来设置连接池中允许的最大活动连接数。 public void setMax_active(int max_active) { this.max_active = max_active; } + // 获取max_idle属性值的方法,外部代码可以通过调用这个方法获取连接池中允许的最大空闲连接数。 public int getMax_idle() { return max_idle; } + // 设置max_idle属性值的方法,外部代码可以通过调用这个方法来设置连接池中允许的最大空闲连接数。 public void setMax_idle(int max_idle) { this.max_idle = max_idle; } + // 获取max_wait属性值的方法,外部代码可以通过调用这个方法获取从连接池中获取连接时的最长等待时间。 public long getMax_wait() { return max_wait; } + // 设置max_wait属性值的方法,外部代码可以通过调用这个方法来设置从连接池中获取连接时的最长等待时间。 public void setMax_wait(long max_wait) { this.max_wait = max_wait; } + // 重写toString方法,用于将PoolConfigBean类的实例以特定的字符串格式进行表示,方便在调试、日志输出等场景下直观地查看连接池配置信息的具体内容。 @Override public String toString() { return "PoolConfig [max_active=" + max_active + ", max_idle=" + max_idle + ", max_wait=" + max_wait + "]"; } - -} +} \ No newline at end of file diff --git a/tamguo-crawler/src/main/java/com/tamguo/config/redis/RedisServerNodeBean.java b/tamguo-crawler/src/main/java/com/tamguo/config/redis/RedisServerNodeBean.java index d8b4297..06702b8 100644 --- a/tamguo-crawler/src/main/java/com/tamguo/config/redis/RedisServerNodeBean.java +++ b/tamguo-crawler/src/main/java/com/tamguo/config/redis/RedisServerNodeBean.java @@ -1,11 +1,18 @@ package com.tamguo.config.redis; +// RedisServerNodeBean类用于封装Redis服务器节点的相关信息,通过定义相应的属性、构造方法以及对应的访问器(getter和setter)方法,方便对这些信息进行设置、获取以及以字符串形式展示等操作。 public class RedisServerNodeBean { + + // 用于存储Redis服务器的IP地址,通过该IP地址可以定位到对应的Redis服务器所在的网络位置,以便建立连接。 private String ip; + // 用于存储Redis服务器监听的端口号,客户端通过指定的IP地址和对应的端口号来与Redis服务器进行通信交互。 private int port; + // 表示是否需要进行身份验证(例如密码验证)才能连接到该Redis服务器,true表示需要验证,false表示不需要验证。 private boolean needAuth; + // 如果needAuth为true,即需要进行身份验证时,此属性用于存储连接Redis服务器所需的验证密码(或其他认证凭据),以确保连接的合法性。 private String auth; + // 构造方法,用于创建RedisServerNodeBean类的实例,并在实例化时初始化各个属性的值,传入的参数分别对应Redis服务器节点的IP地址、端口号、是否需要认证以及认证凭据(密码)。 public RedisServerNodeBean(String ip, int port, boolean needAuth, String auth) { this.ip = ip; this.port = port; @@ -13,41 +20,49 @@ public class RedisServerNodeBean { this.auth = auth; } + // 获取ip属性值的方法,外部代码可以通过调用这个方法获取Redis服务器节点的IP地址信息。 public String getIp() { return ip; } + // 设置ip属性值的方法,外部代码可以通过调用这个方法来修改Redis服务器节点的IP地址信息。 public void setIp(String ip) { this.ip = ip; } + // 获取port属性值的方法,外部代码可以通过调用这个方法获取Redis服务器节点的端口号信息。 public int getPort() { return port; } + // 设置port属性值的方法,外部代码可以通过调用这个方法来修改Redis服务器节点的端口号信息。 public void setPort(int port) { this.port = port; } + // 获取needAuth属性值的方法,外部代码可以通过调用这个方法获取表示是否需要对Redis服务器进行身份验证的布尔值。 public boolean isNeedAuth() { return needAuth; } + // 设置needAuth属性值的方法,外部代码可以通过调用这个方法来修改表示是否需要对Redis服务器进行身份验证的布尔值。 public void setNeedAuth(boolean needAuth) { this.needAuth = needAuth; } + // 获取auth属性值的方法,外部代码可以通过调用这个方法获取连接Redis服务器所需的认证凭据(如密码)信息。 public String getAuth() { return auth; } + // 设置auth属性值的方法,外部代码可以通过调用这个方法来修改连接Redis服务器所需的认证凭据(如密码)信息。 public void setAuth(String auth) { this.auth = auth; } + // 重写toString方法,用于将RedisServerNodeBean类的实例以特定的字符串格式进行表示,方便在调试、日志输出等场景下直观地展示Redis服务器节点的相关信息内容。 @Override public String toString() { return "RedisServer [ip=" + ip + ", port=" + port + ", needAuth=" + needAuth + ", auth=" + auth + "]"; } - -} +} \ No newline at end of file diff --git a/tamguo-crawler/src/main/java/com/tamguo/config/redis/RedisXMLConfigure.java b/tamguo-crawler/src/main/java/com/tamguo/config/redis/RedisXMLConfigure.java index e58c66a..86b3d57 100644 --- a/tamguo-crawler/src/main/java/com/tamguo/config/redis/RedisXMLConfigure.java +++ b/tamguo-crawler/src/main/java/com/tamguo/config/redis/RedisXMLConfigure.java @@ -16,89 +16,126 @@ import redis.clients.jedis.JedisShardInfo; import redis.clients.jedis.ShardedJedis; import redis.clients.jedis.ShardedJedisPool; +// 标识该类是一个Spring组件,在Spring容器启动时会被扫描并实例化,其Bean名称为"redisConfigure",用于配置和管理Redis相关的连接等操作。 @Component("redisConfigure") +// 实现InitializingBean接口,意味着该类在所有属性被设置后,会执行afterPropertiesSet方法来进行一些初始化操作,通常用于加载配置等前置准备工作。 public class RedisXMLConfigure implements InitializingBean { + + // 创建一个日志记录器实例,用于记录与该类相关的操作日志,方便在运行过程中排查问题以及查看关键信息,记录的日志类别基于当前类RedisXMLConfigure。 private static final Logger logger = Logger.getLogger(RedisXMLConfigure.class); + // 用于存储Redis键的前缀,是一个静态变量,在整个应用中可以统一为Redis中的键添加特定的前缀,方便管理和区分不同用途的键。 private static String preKey; + // 用于存储解析后的XML配置文档对象,后续通过操作这个对象来获取各种Redis配置相关的元素和属性信息,初始化为null,后续在初始化方法中进行赋值。 private static Document document = null; + // 定义一个ShardedJedisPool对象,用于管理多个Redis节点的连接池,通过它可以获取到ShardedJedis连接,实现对Redis集群等多节点环境下的数据访问。 private ShardedJedisPool shardedJedisPool; + // 实现InitializingBean接口的方法,在Spring容器完成属性注入后自动调用,用于进行Redis相关配置的初始化工作,比如加载XML配置文件、解析配置信息、创建连接池等操作。 @Override public void afterPropertiesSet() throws Exception { + // 创建一个XMLConfiguration对象,用于读取和解析XML配置文件,它可能封装了一些底层的XML解析相关的逻辑。 XMLConfiguration xmlConfiguration = new XMLConfiguration(); + // 定义要加载的Redis配置文件的路径和文件名,这里指定为"redis.xml",表示从类路径下查找该文件来获取Redis配置信息。 String REDIS_PATH = "redis.xml"; InputStream stream = null; try { + // 通过类加载器获取指定路径下的配置文件输入流,如果获取不到(即配置文件不存在或路径错误),则记录错误日志并抛出运行时异常,表示加载配置文件失败。 stream = this.getClass().getClassLoader().getResourceAsStream(REDIS_PATH); if (stream == null) { logger.error("load redis.xml failed!!!" + REDIS_PATH); throw new RuntimeException("load redis.xml failed"); } logger.info("Redis XML config path:" + REDIS_PATH); + // 使用xmlConfiguration对象读取配置文件输入流中的内容,如果读取成功(返回true),则将解析后的文档对象赋值给document变量,以便后续使用;若读取失败则记录错误日志。 if (xmlConfiguration.readConfigFile(stream)) { document = xmlConfiguration.getDocument(); } else { logger.error("load redis.xml failed!!!"); } } finally { - if (null != stream) + // 无论是否成功读取配置文件,都要关闭输入流,释放相关资源,避免资源泄漏,通过判断输入流是否为null来进行关闭操作。 + if (null!= stream) stream.close(); } - //初始化参数 + + // 调用初始化方法,用于初始化Redis键的前缀信息,从解析后的XML配置中获取相应的值进行设置。 initPreKey(); + // 调用方法初始化连接池的配置参数,从XML配置中读取相关属性值,创建并返回一个PoolConfigBean对象,该对象封装了如最大空闲连接数、最大等待时间等连接池配置信息。 PoolConfigBean pcb = initPoolConfigBean(); + // 调用方法解析配置文件中关于Redis服务器节点的信息,读取每个服务器节点的IP、端口、是否需要认证以及认证密码等信息,返回一个包含多个RedisServerNodeBean对象的列表。 List rsnbs = initRedisServerNodeBeans(); - //实现shardedJedisPool + + // 创建一个JedisPoolConfig对象,用于配置Jedis连接池的相关参数,后续会基于这个配置对象来创建ShardedJedisPool连接池。 JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); + // 注意这里没有设置maxActive(可能在当前配置逻辑中有其他考虑,比如依赖默认值或者后续有特殊处理),而是设置了最大空闲连接数和最大等待时间,从之前初始化得到的PoolConfigBean对象中获取相应的参数值进行设置。 //no maxActive config jedisPoolConfig.setMaxIdle(pcb.getMax_idle()); jedisPoolConfig.setMaxWaitMillis(pcb.getMax_wait()); - shardedJedisPool = new ShardedJedisPool(jedisPoolConfig,getJedisShardInfo(rsnbs)); - if(shardedJedisPool == null){ + + // 创建ShardedJedisPool连接池对象,传入配置好的JedisPoolConfig对象以及根据解析得到的Redis服务器节点信息转换而来的JedisShardInfo列表,用于管理多个Redis节点的连接池,方便后续获取连接进行数据操作。 + shardedJedisPool = new ShardedJedisPool(jedisPoolConfig, getJedisShardInfo(rsnbs)); + if (shardedJedisPool == null) { + // 如果创建连接池失败(返回值为null),则抛出运行时异常,表示Redis配置文件存在错误,导致无法正确创建连接池。 throw new RuntimeException("config redis.xml error"); } } /** * 初始化jedis参数 + * 该方法用于从解析后的XML配置文件中读取连接池相关的配置参数,创建并返回一个PoolConfigBean对象,其中封装了连接池的最大活动连接数、最大空闲连接数以及最大等待时间等参数信息。 */ private PoolConfigBean initPoolConfigBean() { PoolConfigBean poolConfigBean = new PoolConfigBean(); + // 通过文档对象查找名为"pool"的XML元素,获取配置文件中关于连接池的配置节点,假设配置文件中以特定的XML结构来定义连接池相关属性。 Element poolElement = (Element) document.getElementsByTagName("pool").item(0); - int max_active = poolElement.hasAttribute("maxActive") ? Integer.parseInt(poolElement.getAttribute("maxActive")) : -1; - int max_idle = poolElement.hasAttribute("maxIdle") ? Integer.parseInt(poolElement.getAttribute("maxIdle")) : -1; - long max_wait = poolElement.hasAttribute("maxWait") ? Long.parseLong(poolElement.getAttribute("maxWait")) : -1; + // 判断"pool"元素是否有"maxActive"属性,如果有则将其解析为整数并赋值给max_active变量,否则将其设置为 -1(表示可能使用默认值或者后续有其他处理逻辑来确定该参数)。 + int max_active = poolElement.hasAttribute("maxActive")? Integer.parseInt(poolElement.getAttribute("maxActive")) : -1; + // 类似地,获取"maxIdle"属性的值,如果存在则解析为整数赋值给max_idle变量,否则设置为 -1。 + int max_idle = poolElement.hasAttribute("maxIdle")? Integer.parseInt(poolElement.getAttribute("maxIdle")) : -1; + // 获取"maxWait"属性的值,存在则解析为长整型赋值给max_wait变量,否则设置为 -1。 + long max_wait = poolElement.hasAttribute("maxWait")? Long.parseLong(poolElement.getAttribute("maxWait")) : -1; + + // 通过PoolConfigBean对象的setter方法,将获取到的各个参数值设置到对象中,以便后续返回并用于创建JedisPoolConfig对象时设置相应的连接池参数。 poolConfigBean.setMax_active(max_active); poolConfigBean.setMax_idle(max_idle); poolConfigBean.setMax_wait(max_wait); + return poolConfigBean; } /** * 解析配置redis的server列表 + * 该方法用于从解析后的XML配置文件中读取关于Redis服务器节点的配置信息,解析每个服务器节点的IP、端口、是否需要认证以及认证密码等属性,创建并返回一个包含多个RedisServerNodeBean对象的列表,每个对象代表一个Redis服务器节点的配置信息。 */ private List initRedisServerNodeBeans() { List redisServers = new ArrayList(); + // 通过文档对象查找所有名为"server"的XML元素,获取配置文件中定义的所有Redis服务器节点的配置节点列表,后续遍历该列表来解析每个服务器节点的详细信息。 NodeList serverElements = document.getElementsByTagName("server"); int serverLen = serverElements.getLength(); if (serverLen < 1) { - logger.error("redis.servers.server must have one !"); + // 如果没有找到任何"server"元素,即没有配置Redis服务器节点信息,记录错误日志并返回null,表示配置不合法。 + logger.error("redis.servers.server must have one!"); return null; } for (int i = 0; i < serverLen; i++) { + // 遍历每个"server"元素,获取对应的Element对象,用于解析该服务器节点的具体属性信息。 Element serverElement = (Element) serverElements.item(i); - String temp_ip = serverElement.hasAttribute("ip") ? serverElement.getAttribute("ip") : null; + // 获取"server"元素中"ip"属性的值,如果存在则赋值给temp_ip变量,否则设置为null,表示IP地址未配置(这是不符合要求的情况,后续会进行相应的错误处理)。 + String temp_ip = serverElement.hasAttribute("ip")? serverElement.getAttribute("ip") : null; if (temp_ip == null) { + // 如果IP地址为空,记录错误日志并返回null,表示配置不合法,因为IP地址是连接Redis服务器必需的信息。 logger.error("redis.servers.server.ip must be supplied!"); return null; } - String temp_port = serverElement.hasAttribute("port") ? serverElement.getAttribute("port") : "6379"; - String temp_needAuth = serverElement.hasAttribute("needAuth") ? serverElement.getAttribute("needAuth") : "false"; + // 获取"server"元素中"port"属性的值,如果存在则赋值给temp_port变量,否则默认设置为"6379"(Redis默认端口号),确保端口号有一个合理的值。 + String temp_port = serverElement.hasAttribute("port")? serverElement.getAttribute("port") : "6379"; + // 获取"server"元素中"needAuth"属性的值,如果存在则赋值给temp_needAuth变量,否则默认设置为"false",表示默认不需要进行身份验证。 + String temp_needAuth = serverElement.hasAttribute("needAuth")? serverElement.getAttribute("needAuth") : "false"; String temp_auth = null; - // need auth + // 如果"needAuth"属性的值为"true",即表示需要进行身份验证,那么获取"auth"属性的值(认证密码),如果不存在则记录错误日志并返回null,表示配置不合法,因为需要认证时密码是必需的。 if ("true".equals(temp_needAuth)) { - temp_auth = serverElement.hasAttribute("auth") ? serverElement.getAttribute("auth") : null; + temp_auth = serverElement.hasAttribute("auth")? serverElement.getAttribute("auth") : null; if (null == temp_auth) { logger.error("since needAuth is true,auth must be supplied!"); return null; @@ -107,11 +144,14 @@ public class RedisXMLConfigure implements InitializingBean { RedisServerNodeBean rs = null; try { + // 尝试创建一个RedisServerNodeBean对象,传入解析得到的IP地址、端口号、是否需要认证的布尔值以及认证密码(如果需要认证)等信息,将创建的对象赋值给rs变量。 + // 如果端口号解析为整数失败(即不是合法的数字格式),会捕获NumberFormatException异常,记录错误日志并返回null,表示配置不合法。 rs = new RedisServerNodeBean(temp_ip, Integer.parseInt(temp_port), Boolean.parseBoolean(temp_needAuth), temp_auth); } catch (NumberFormatException e) { logger.error("port must be a number!\n" + e.getMessage()); return null; } + // 将创建好的代表Redis服务器节点配置信息的对象添加到列表中,最终返回包含所有服务器节点配置信息的列表。 redisServers.add(rs); } return redisServers; @@ -119,55 +159,71 @@ public class RedisXMLConfigure implements InitializingBean { /** * 转换自定义配置为JedisShardInfo对象 - * @param redisServers - * @return + * 该方法用于将之前解析得到的包含Redis服务器节点配置信息的列表(List)转换为适用于创建ShardedJedisPool连接池的JedisShardInfo列表, + * 每个JedisShardInfo对象包含了单个Redis服务器节点的连接信息,如IP、端口以及密码(如果需要认证)等,方便连接池管理和使用这些节点连接。 + * + * @param redisServers 包含Redis服务器节点配置信息的列表,由initRedisServerNodeBeans方法解析得到。 + * @return 返回一个包含JedisShardInfo对象的列表,用于创建ShardedJedisPool连接池时传入,以配置连接池与各个Redis服务器节点的连接信息。 */ private List getJedisShardInfo(List redisServers) { - if(redisServers == null){ + if (redisServers == null) { + // 如果传入的Redis服务器节点列表为null,记录错误日志并返回null,表示参数不合法,无法进行后续的转换操作。 logger.error("redisServers must not be empty null"); return null; } int serverLen = redisServers.size(); if (serverLen < 1) { + // 如果列表中没有任何元素(即没有配置有效的Redis服务器节点),记录错误日志并返回null,表示不符合要求,因为连接池至少需要一个有效的节点信息来创建。 logger.error("redisServers must not be empty "); return null; } List servers = new ArrayList(serverLen); for (int i = 0; i < serverLen; i++) { + // 遍历传入的Redis服务器节点列表,获取每个RedisServerNodeBean对象,代表一个服务器节点的配置信息。 RedisServerNodeBean redisServer = redisServers.get(i); + // 创建一个JedisShardInfo对象,传入该服务器节点的IP地址和端口号信息,用于构建与该节点的连接相关信息,初始状态下不包含密码信息(如果需要认证,后续再单独设置)。 JedisShardInfo jedisShardInfo = new JedisShardInfo(redisServer.getIp(), redisServer.getPort()); if (redisServer.isNeedAuth()) { + // 如果该服务器节点需要进行身份验证(通过RedisServerNodeBean对象的isNeedAuth方法判断),则设置对应的认证密码,从RedisServerNodeBean对象中获取密码信息并设置到JedisShardInfo对象中。 jedisShardInfo.setPassword(redisServer.getAuth()); } + // 将配置好的JedisShardInfo对象添加到列表中,最终返回包含所有服务器节点连接信息的JedisShardInfo列表,用于创建ShardedJedisPool连接池。 servers.add(jedisShardInfo); } return servers; } - + /* * 初始化redis的key前缀 + * 该方法用于从解析后的XML配置文件中读取Redis键的前缀信息,将其赋值给静态变量preKey,方便后续在操作Redis键时统一添加前缀,进行规范管理。 */ private void initPreKey() { Element preKeyElement = (Element) document.getElementsByTagName("preKey").item(0); - preKey = preKeyElement.hasAttribute("value") ? preKeyElement.getAttribute("value") : ""; + preKey = preKeyElement.hasAttribute("value")? preKeyElement.getAttribute("value") : ""; } + // 获取Redis键前缀的方法,外部代码可以通过调用该方法获取当前配置的Redis键前缀信息,用于在操作Redis时为键添加合适的前缀。 public String getPreKey() { return preKey; } + /** * 从jedis连接池获得一个连接 - * @return + * 该方法用于从之前创建并配置好的ShardedJedisPool连接池中获取一个ShardedJedis连接对象,以便后续通过该连接对象对Redis进行数据操作,如读写数据等。 + * + * @return 返回一个ShardedJedis连接对象,用于与Redis进行交互操作,如果连接池配置或获取连接出现问题可能会抛出相应的异常。 */ public ShardedJedis getConnection() { return shardedJedisPool.getResource(); } + /** * 把连接放回jedis连接池 - * @param resource + * 该方法用于将使用完的ShardedJedis连接对象归还到ShardedJedisPool连接池中,释放连接资源,以便连接池可以对连接进行管理和复用,避免资源浪费和连接泄漏等问题。 + * + * @param resource 要归还的ShardedJedis连接对象,通常是之前通过getConnection方法获取并使用完的连接。 */ public void closeConnection(ShardedJedis resource) { resource.close(); } - -} +} \ No newline at end of file diff --git a/tamguo-crawler/src/main/java/com/tamguo/config/redis/SerializeTranscoder.java b/tamguo-crawler/src/main/java/com/tamguo/config/redis/SerializeTranscoder.java index 63f928f..e0cb7e9 100644 --- a/tamguo-crawler/src/main/java/com/tamguo/config/redis/SerializeTranscoder.java +++ b/tamguo-crawler/src/main/java/com/tamguo/config/redis/SerializeTranscoder.java @@ -2,14 +2,24 @@ package com.tamguo.config.redis; import java.io.Closeable; +// SerializeTranscoder是一个抽象类,用于定义对象序列化和反序列化相关的操作规范,同时提供了一个用于关闭可关闭资源(实现了Closeable接口的对象)的通用方法, +// 具体的序列化和反序列化逻辑需要由继承它的子类去实现。 public abstract class SerializeTranscoder { + // 抽象方法serialize,用于将给定的对象进行序列化操作,将对象转换为字节数组的形式。 + // 具体的序列化实现细节由继承该抽象类的子类来定义,不同的子类可以根据实际需求采用不同的序列化策略(如Java原生序列化、JSON序列化等)。 + // 参数value表示要进行序列化的对象,返回值为序列化后的字节数组。 public abstract byte[] serialize(Object value); + // 抽象方法deserialize,用于将给定的字节数组进行反序列化操作,将字节数组还原为原始的对象形式。 + // 同样,具体的反序列化实现由子类负责,要根据序列化时采用的策略来正确还原对象。 + // 参数in表示要进行反序列化的字节数组,返回值为反序列化后得到的对象。 public abstract Object deserialize(byte[] in); + // 定义一个方法close,用于关闭实现了Closeable接口的资源对象(如输入输出流等),以释放相关的系统资源,避免资源泄漏等问题。 + // 参数closeable表示要关闭的可关闭资源对象,如果传入的对象不为null,则尝试调用其close方法进行关闭操作,若关闭过程中出现异常,则打印异常堆栈信息以便排查问题。 public void close(Closeable closeable) { - if (closeable != null) { + if (closeable!= null) { try { closeable.close(); } catch (Exception e) { @@ -17,4 +27,4 @@ public abstract class SerializeTranscoder { } } } -} +} \ No newline at end of file diff --git a/tamguo-crawler/src/main/java/com/tamguo/config/redis/XMLConfiguration.java b/tamguo-crawler/src/main/java/com/tamguo/config/redis/XMLConfiguration.java index 43b5a56..660a7e1 100644 --- a/tamguo-crawler/src/main/java/com/tamguo/config/redis/XMLConfiguration.java +++ b/tamguo-crawler/src/main/java/com/tamguo/config/redis/XMLConfiguration.java @@ -8,25 +8,37 @@ import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; +// XMLConfiguration类主要用于读取和解析XML配置文件,并提供获取解析后文档对象(Document)的方法,支持通过文件名和输入流(InputStream)两种方式来加载配置文件进行解析。 public class XMLConfiguration { + + // 用于存储解析后的XML文档对象,初始化为null,在成功读取并解析配置文件后,会将对应的Document对象赋值给该变量,方便后续获取和使用解析结果。 private Document document = null; + // 通过指定的配置文件名称(字符串形式的文件名及路径)来读取并解析XML配置文件,若解析成功则返回true,若出现异常导致解析失败(document仍为null)则返回false。 public boolean readConfigFile(String configFilename) { + // 创建一个DocumentBuilderFactory实例,它是用于创建DocumentBuilder对象的工厂类,通过它可以按照默认配置创建用于解析XML文档的DocumentBuilder。 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { + // 使用DocumentBuilderFactory创建一个DocumentBuilder对象,该对象用于实际解析XML文档,将其解析为内存中的Document对象表示形式。 DocumentBuilder db = dbf.newDocumentBuilder(); + // 调用DocumentBuilder的parse方法,传入配置文件的名称(路径)作为参数,尝试解析该XML配置文件,并将解析后的Document对象赋值给document变量。 document = db.parse(configFilename); } catch (IOException e) { + // 如果在解析过程中出现IO异常(例如文件不存在、无法读取文件等情况),打印异常堆栈信息,方便排查问题,但不中断程序执行,继续执行后续的返回值判断逻辑。 e.printStackTrace(); } catch (Exception e) { + // 捕获其他可能出现的异常(除了IO异常之外的,比如XML格式错误等导致解析失败的异常),同样打印异常堆栈信息,以便查找问题所在,然后继续执行返回值判断逻辑。 e.printStackTrace(); } + // 判断解析后的Document对象是否为null,如果为null说明解析过程出现问题导致没有成功获取到有效的文档对象,返回false表示读取配置文件失败;否则返回true表示成功。 if (document == null) { return false; } return true; } + // 通过给定的输入流(InputStream)来读取并解析XML配置文件,逻辑与readConfigFile(String configFilename)方法类似,若解析成功则返回true,失败则返回false。 + // 常用于从类路径下获取资源流或者其他来源的输入流来解析配置文件的场景。 public boolean readConfigFile(InputStream stream) { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { @@ -43,11 +55,13 @@ public class XMLConfiguration { return true; } + // 获取解析后的XML文档对象的方法,外部代码可以通过调用该方法获取之前成功解析配置文件后得到的Document对象,以便进一步操作文档中的元素、属性等内容。 public Document getDocument() { return document; } + // 受保护的方法,用于设置解析后的XML文档对象,一般在类内部或者子类中可以根据需要调用该方法来更新document变量的值,通常不是由外部直接调用,而是在特定的内部逻辑中使用。 protected void setDocument(Document document) { this.document = document; } -} +} \ No newline at end of file