广告位联系
返回顶部
分享到

SpringBoot实现缓存组件配置动态切换的步骤

java 来源:互联网 作者:佚名 发布时间:2024-07-26 21:24:53 人浏览
摘要

一、需求背景 现在有多个springboot项目,但是不同的项目中使用的缓存组件是不一样的,有的项目使用redis,有的项目使用ctgcache,现在需要用同一套代码通过配置开关,在不同的项目中切换这

一、需求背景

现在有多个springboot项目,但是不同的项目中使用的缓存组件是不一样的,有的项目使用redis,有的项目使用ctgcache,现在需要用同一套代码通过配置开关,在不同的项目中切换这两种缓存。

二、实现缓存组件的动态切换

1.第一步:配置文件新增切换开关

1

2

3

#缓存组件配置

#cache.type=ctgcache

cache.type=redis

2.第二步:创建ctgcache 缓存条件类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

package com.gstanzer.supervise.cache;

  

import org.springframework.context.annotation.Condition;

import org.springframework.context.annotation.ConditionContext;

import org.springframework.core.env.Environment;

import org.springframework.core.type.AnnotatedTypeMetadata;

  

/**

 * ctgcache 缓存条件类

 *

 * @author: tangbingbing

 * @date: 2024/7/22 14:31

 */

public class CtgCacheCondition implements Condition {

  

    @Override

    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        // 从 Environment 中获取属性

        Environment env = context.getEnvironment();

        String cacheType = env.getProperty("cache.type");

  

        // 检查 cache.type 是否与 metadata 中的某个值匹配(这里简单比较字符串)

        // 注意:实际应用中可能需要更复杂的逻辑来确定 metadata 中的值

        // 这里我们假设 metadata 中没有特定值,仅根据 cache.type 判断

        if ("ctgcache".equalsIgnoreCase(cacheType)) {

            // 使用 ctgcache

            return true;

        }

  

        // 如果没有明确指定,或者指定了其他值,我们可以选择默认行为

        // 这里假设默认不使用这个 Bean

        return false;

    }

  

}

3.第三步:创建redis 缓存条件类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

package com.gstanzer.supervise.cache;

  

import org.springframework.context.annotation.Condition;

import org.springframework.context.annotation.ConditionContext;

import org.springframework.core.env.Environment;

import org.springframework.core.type.AnnotatedTypeMetadata;

  

/**

 * redis 缓存条件类

 *

 * @author: tangbingbing

 * @date: 2024/7/22 14:31

 */

public class RedisCondition implements Condition {

  

    @Override

    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        // 从 Environment 中获取属性

        Environment env = context.getEnvironment();

        String cacheType = env.getProperty("cache.type");

  

        // 检查 cache.type 是否与 metadata 中的某个值匹配(这里简单比较字符串)

        // 注意:实际应用中可能需要更复杂的逻辑来确定 metadata 中的值

        // 这里我们假设 metadata 中没有特定值,仅根据 cache.type 判断

        if ("redis".equalsIgnoreCase(cacheType)) {

            // 使用 Redis

            return true;

        }

  

        // 如果没有明确指定,或者指定了其他值,我们可以选择默认行为

        // 这里假设默认不使用这个 Bean

        return false;

    }

  

}

4.第四步:创建缓存切换配置类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

package com.gstanzer.supervise.cache;

  

import com.ctg.itrdc.cache.pool.CtgJedisPool;

import com.ctg.itrdc.cache.pool.CtgJedisPoolConfig;

import com.ctg.itrdc.cache.vjedis.jedis.JedisPoolConfig;

import com.fasterxml.jackson.annotation.JsonAutoDetect;

import com.fasterxml.jackson.annotation.PropertyAccessor;

import com.fasterxml.jackson.databind.ObjectMapper;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Conditional;

import org.springframework.context.annotation.Configuration;

import org.springframework.data.redis.connection.RedisConnectionFactory;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.data.redis.listener.RedisMessageListenerContainer;

import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import org.springframework.data.redis.serializer.RedisSerializer;

import org.springframework.data.redis.serializer.StringRedisSerializer;

import redis.clients.jedis.HostAndPort;

  

import java.util.ArrayList;

import java.util.List;

  

/**

 * 缓存配置类

 *

 * @author: tangbingbing

 * @date: 2024/7/22 14:28

 */

@Configuration

public class CacheConfig {

  

    @Value("${access.cq.redis.host1}")

    private String reidsHost1;

  

    @Value("${access.cq.redis.host2}")

    private String reidsHost2;

  

    @Value("${access.cq.redis.port}")

    private int port;

  

    @Value("${access.cq.redis.password}")

    private String password;

  

    @Value("${access.cq.redis.group}")

    private String group;

  

    @Value("${access.cq.redis.max-total}")

    private int maxTotal;

  

    @Value("${access.cq.redis.max-idle}")

    private int maxIdle;

  

    @Value("${access.cq.redis.min-idle}")

    private int minIdle;

  

    @Value("${access.cq.redis.max-wait}")

    private int maxWait;

  

    @Value("${access.cq.redis.period}")

    private int period;

  

    @Value("${access.cq.redis.monitor-timeout}")

    private int monitorTimeout;

  

    @Bean

    @Conditional(RedisCondition.class)

    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {

        // 创建并返回RedisTemplate

        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        redisTemplate.setConnectionFactory(factory);

  

  

        RedisSerializer<String> redisSerializer = new StringRedisSerializer();

        redisTemplate.setKeySerializer(redisSerializer);

        redisTemplate.setHashKeySerializer(redisSerializer);

  

        // 设置value的序列化器

        //使用Jackson 2,将对象序列化为JSON

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //json转对象类,不设置默认的会将json转成hashmap

        ObjectMapper om = new ObjectMapper();

        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

  

        // json中会显示类型

//        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        jackson2JsonRedisSerializer.setObjectMapper(om);

        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.afterPropertiesSet();

        return redisTemplate;

    }

  

    @Bean

    @Conditional(RedisCondition.class)

    public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory) {

        // 创建并返回RedisMessageListenerContainer

        RedisMessageListenerContainer container = new RedisMessageListenerContainer();

        // 监听所有库的key过期事件

        container.setConnectionFactory(connectionFactory);

        return container;

    }

  

    @Bean

    @Conditional(CtgCacheCondition.class)

    public CtgJedisPool ctgJedisPool() {

        // 创建并返回CtgJedisPool

        List<HostAndPort> hostAndPortList = new ArrayList();

        HostAndPort host1 = new HostAndPort(reidsHost1, port);

        HostAndPort host2 = new HostAndPort(reidsHost2, port);

        hostAndPortList.add(host1);

        hostAndPortList.add(host2);

  

        GenericObjectPoolConfig poolConfig = new JedisPoolConfig();

        poolConfig.setMaxTotal(maxTotal); // 最大连接数(空闲+使用中)

        poolConfig.setMaxIdle(maxIdle); //最大空闲连接数

        poolConfig.setMinIdle(minIdle); //保持的最小空闲连接数

        poolConfig.setMaxWaitMillis(maxWait); //借出连接时最大的等待时间

  

        CtgJedisPoolConfig config = new CtgJedisPoolConfig(hostAndPortList);

        config.setDatabase(group)

                .setPassword(password)

                .setPoolConfig(poolConfig)

                .setPeriod(period)

                .setMonitorTimeout(monitorTimeout);

  

        CtgJedisPool pool = new CtgJedisPool(config);

        return pool;

    }

}

5.第五步:创建缓存服务接口

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

package com.gstanzer.supervise.cache;

  

/**

 * 缓存服务接口

 *

 * @author: tangbingbing

 * @date: 2024/7/22 14:46

 */

public interface CacheService {

  

    /**

     * 检查缓存中是否存在某个key

     *

     * @param key

     * @return

     */

    public boolean exists(final String key);

  

    /**

     * 获取缓存中对应key的value值

     *

     * @param key

     * @return

     */

    public String get(final String key);

  

    /**

     * 存入值到缓存,并设置有效期

     *

     * @param key

     * @param value

     * @param expireTime 有效期,单位s

     * @return

     */

    public boolean set(final String key, String value, int expireTime);

  

    /**

     * 存入值到缓存

     *

     * @param key

     * @param value

     * @return

     */

    public boolean set(final String key, String value);

  

    /**

     * 删除缓存对应的key值

     *

     * @param key

     * @return

     */

    public boolean del(final String key);

  

}

6.第六步:创建ctgcache实现类实现缓存服务接口

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

package com.gstanzer.supervise.cache;

  

import com.ctg.itrdc.cache.pool.CtgJedisPool;

import com.ctg.itrdc.cache.pool.ProxyJedis;

import com.gstanzer.supervise.ctgcache.CtgRedisUtil;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.context.annotation.Conditional;

import org.springframework.stereotype.Service;

  

import javax.annotation.Resource;

  

/**

 * ctgcache 缓存方法实现

 *

 * @author: tangbingbing

 * @date: 2024/7/22 14:48

 */

@Service

@Conditional(CtgCacheCondition.class)

public class CtgCacheService implements CacheService {

  

    private static Logger logger = LoggerFactory.getLogger(CtgRedisUtil.class);

  

    @Resource

    private CtgJedisPool ctgJedisPool;

  

    /**

     * 判断缓存中是否有对应的value

     *

     * @param key

     * @return

     */

    public boolean exists(final String key) {

        Boolean exists = false;

        ProxyJedis jedis = new ProxyJedis();

        try {

            jedis = ctgJedisPool.getResource();

            exists = jedis.exists(key);

            jedis.close();

        } catch (Throwable e) {

            logger.error(e.getMessage());

            jedis.close();

        } finally {

            // finally内执行,确保连接归还

            try {

                jedis.close();

            } catch (Throwable ignored) {

  

            }

        }

        return exists;

    }

  

    /**

     * 读取缓存

     *

     * @param key

     * @return

     */

    public String get(final String key) {

        String value = null;

        ProxyJedis jedis = new ProxyJedis();

        try {

            jedis = ctgJedisPool.getResource();

            value = jedis.get(key);

            jedis.close();

        } catch (Throwable e) {

            logger.error(e.getMessage());

            jedis.close();

        } finally {

            // finally内执行,确保连接归还

            try {

                jedis.close();

            } catch (Throwable ignored) {

  

            }

        }

        return value;

    }

  

    /**

     * 写入缓存设置时效时间

     *

     * @param key

     * @param value

     * @return

     */

    public boolean set(final String key, String value, int expireTime) {

        Boolean result = false;

        ProxyJedis jedis = new ProxyJedis();

        try {

            jedis = ctgJedisPool.getResource();

            jedis.setex(key, expireTime, value);

            result = true;

            jedis.close();

        } catch (Throwable e) {

            logger.error(e.getMessage());

            jedis.close();

        } finally {

            // finally内执行,确保连接归还

            try {

                jedis.close();

            } catch (Throwable ignored) {

  

            }

        }

        return result;

    }

  

    /**

     * 写入缓存

     *

     * @param key

     * @param value

     * @return

     */

    public boolean set(final String key, String value) {

        Boolean result = false;

        ProxyJedis jedis = new ProxyJedis();

        try {

            jedis = ctgJedisPool.getResource();

            jedis.set(key, value);

            result = true;

            jedis.close();

        } catch (Throwable e) {

            logger.error(e.getMessage());

            jedis.close();

        } finally {

            // finally内执行,确保连接归还

            try {

                jedis.close();

            } catch (Throwable ignored) {

  

            }

        }

        return result;

    }

  

    /**

     * 删除缓存

     *

     * @param key

     * @return

     */

    public boolean del(final String key) {

        Boolean result = false;

        ProxyJedis jedis = new ProxyJedis();

        try {

            jedis = ctgJedisPool.getResource();

            jedis.del(key);

            result = true;

            jedis.close();

        } catch (Throwable e) {

            logger.error(e.getMessage());

            jedis.close();

        } finally {

            // finally内执行,确保连接归还

            try {

                jedis.close();

            } catch (Throwable ignored) {

  

            }

        }

        return result;

    }

  

}

7.第七步:创建redis实现类实现缓存服务接口

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

package com.gstanzer.supervise.cache;

  

import com.gstanzer.supervise.redis.RedisUtils;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Conditional;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.data.redis.core.StringRedisTemplate;

import org.springframework.data.redis.core.ValueOperations;

import org.springframework.stereotype.Service;

  

import java.io.Serializable;

import java.util.concurrent.TimeUnit;

  

/**

 * reids 缓存方法实现

 *

 * @author: tangbingbing

 * @date: 2024/7/22 14:48

 */

@Service

@Conditional(RedisCondition.class)

public class RedisCacheService implements CacheService {

  

    @Autowired

    private RedisTemplate redisTemplate;

  

    @Autowired

    private StringRedisTemplate stringRedisTemplate;

  

    private static Logger logger = LoggerFactory.getLogger(RedisUtils.class);

  

    /**

     * 检查缓存中是否存在某个key

     *

     * @param key

     * @return

     */

    @Override

    public boolean exists(String key) {

        return redisTemplate.hasKey(key);

    }

  

    /**

     * 获取缓存中对应key的value值

     *

     * @param key

     * @return

     */

    @Override

    public String get(String key) {

        String result = null;

        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();

        result = operations.get(key).toString();

        return result;

    }

  

    /**

     * 存入值到缓存,并设置有效期

     *

     * @param key

     * @param value

     * @param expireTime 有效期,单位s

     * @return

     */

    @Override

    public boolean set(String key, String value, int expireTime) {

        boolean result = false;

        try {

            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();

            operations.set(key, value);

            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);

            result = true;

        } catch (Exception e) {

            e.printStackTrace();

        }

        return result;

    }

  

    /**

     * 存入值到缓存

     *

     * @param key

     * @param value

     * @return

     */

    @Override

    public boolean set(String key, String value) {

        boolean result = false;

        try {

            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();

            operations.set(key, value);

            result = true;

        } catch (Exception e) {

            e.printStackTrace();

        }

        return result;

    }

  

    /**

     * 删除缓存对应的key值

     *

     * @param key

     * @return

     */

    @Override

    public boolean del(String key) {

        Boolean result = false;

        try {

            if (exists(key)) {

                redisTemplate.delete(key);

            }

            result = true;

        } catch (Exception e) {

            e.printStackTrace();

        }

        return result;

    }

}

8.第八步:在程序中注入缓存服务接口使用

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

package com.gstanzer.supervise.controller;

  

import com.gstanzer.supervise.cache.CacheService;

import com.gstanzer.supervise.jwt.PassToken;

import com.gstanzer.supervise.swagger.ApiForBackEndInIAM;

import io.swagger.annotations.Api;

import io.swagger.annotations.ApiOperation;

import io.swagger.annotations.ApiParam;

import lombok.extern.slf4j.Slf4j;

import org.springframework.validation.annotation.Validated;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;

  

import javax.annotation.Resource;

import javax.validation.constraints.NotEmpty;

  

  

/**

 * 缓存测试 Controller

 *

 * @author: tangbingbing

 * @date: 2023/10/23 16:25

 */

@Api(tags = "缓存测试")

@Slf4j

@Validated

@RestController

@RequestMapping(value = "/redis")

public class RedisController {

  

  

    @Resource

    private CacheService cacheService;

  

    @PassToken

    @ApiForBackEndInIAM

    @ApiOperation(value = "redis测试")

    @PostMapping("/test")

    public String test(

            @RequestParam() @ApiParam(value = "redis键") @NotEmpty(message = "{validator.RedisController.test.key.NotEmpty}") String key

    ) {

        String res = "获取到redis-value为:空";

        if (cacheService.exists(key)){

            String value = cacheService.get(key);

            res = "获取到redis-value为:" + value;

        } else {

            cacheService.set(key,"test",60);

            res = "未获取到value,重新设置值有效期为60s";

        }

        return res;

    }

}

三、总结

其实整体实现是一个比较简单的过程,核心是需要了解Springboot中@Conditional注解的应用,希望对大家有所帮助。


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 :
相关文章
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计