Redis-9集成Redis

Redis-9集成Redis

****************** 如有侵权请提示删除 *********************

SpringBoot集成Redis
  • SpringBoot 操作数据:spring-data jpa jdbc mongodb redis!
  • SpringData 也是和 SpringBoot 齐名的项目!
    说明: 在 SpringBoot2.x 之后,原来使用的jedis 被替换为了 lettuce?
  • jedis : 采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的,使用 jedis pool 连接池! 更像 BIO 模式
  • lettuce : 采用netty,实例可以再多个线程中进行共享,不存在线程不安全的情况!可以减少线程数据了,更像 NIO 模式

我们在学习SpringBoot自动配置的原理时,整合一个组件并进行配置一定会有一个自动配置类xxxAutoConfiguration,并且在spring.factories中也一定能找到这个类的完全限定名。Redis也不例外。

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration

@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
    public RedisAutoConfiguration() {
    }
    ...
}

那么就一定还存在一个RedisProperties类

//org.springframework.boot.autoconfigure.data.redis.RedisProperties

public class RedisProperties {
    private int database = 0;
    private String url;
    private String host = "localhost";
    private String password;
    private int port = 6379;
    private boolean ssl;
    private Duration timeout;
    private RedisProperties.Sentinel sentinel;
    private RedisProperties.Cluster cluster;
    private final RedisProperties.Jedis jedis = new RedisProperties.Jedis();
    private final RedisProperties.Lettuce lettuce = new RedisProperties.Lettuce();
}

之前我们说SpringBoot2.x后默认使用Lettuce来替换Jedis,现在我们就能来验证了。

先看Jedis:

@Configuration
@ConditionalOnClass({GenericObjectPool.class, JedisConnection.class, Jedis.class})
class JedisConnectionConfiguration extends RedisConnectionConfiguration {
    private final RedisProperties properties;
    private final ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers;
...
}

@ConditionalOnClass注解中有两个类是默认不存在的,所以Jedis是无法生效的

然后再看Lettuce:

@Configuration
@ConditionalOnClass({RedisClient.class})
class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
    private final RedisProperties properties;
    private final ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers;
    ...
 }

完美生效

源码分析:这是RedisAutoConfiguration

@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
    public RedisAutoConfiguration() {
    }

   //@ConditionalOnMissingBean  表示没有redisTemplate才有效
   // 所以,我们可以自己定义一个redisTemplate来替换这个默认的!
    @Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"}  
    )
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        // 默认的 RedisTemplate 没有过多的设置,redis 对象都是需要序列化!
         // 两个泛型都是 Object, Object 的类型,我们后使用需要强制转换 <String, Object>
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    由于String是redis中最常使用的类型,所以说单独提出来了一 个bean!
    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

整合测试一下

  1. 导入依赖
<!-- 操作redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 配置连接
配置redis
redis:
    # Redis索引0~15,默认为0
    database: 1
    # Redis服务器地址
    host: 127.0.0.1
    # Redis服务器连接端口
    port: 6379
    #Redis服务器连接密码(默认为空)
    password: 123456
    #    cluster:
    #      max-redirects: 3
    #      nodes:
    #      - 127.0.0.1:6379
    #      - 127.0.0.1:6380
    #      - 127.0.0.1:6381
    #key前缀
    key-prefix: hk-
    # 使用lettuce配置(Redis的client,线程安全的,Jedis非线程安全)
    lettuce:
      pool:
        max-active:  1000 # 连接池最大连接数(使用负值表示没有限制)
        max-idle: 500 # 连接池中的最大空闲连接
        min-idle: 100 # 连接池中的最小空闲连接
        max-wait: 60s # 连接池最大阻塞等待时间(使用负值表示没有限制)
      timeout: 60s #连接超时时间(秒)
  1. 测试
@SpringBootTest
class Redis02SpringbootApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    void contextLoads() {
        // redisTemplate 操作不同的数据类型,api和我们的指令是一样的
        // opsForValue 操作字符串 类似String
        // opsForList 操作List 类似List
        // opsForSet
        // opsForHash
        // opsForZSet
        // opsForGeo
        // opsForHyperLogLog
        // 除了进本的操作,我们常用的方法都可以直接通过redisTemplate操作,比如事务,和基本的CRUD
        // 获取redis的连接对象
        // RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        // connection.flushDb();
        // connection.flushAll();
        redisTemplate.opsForValue().set("mykey","aaaabbbcccc");
        System.out.println(redisTemplate.opsForValue().get("mykey"));
    }
}

查看RedisTemplate 源码

public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
    private boolean enableTransactionSupport = false;
    private boolean exposeConnection = false;
    private boolean initialized = false;
    private boolean enableDefaultSerializer = true;
    @Nullable
    private RedisSerializer<?> defaultSerializer;
    @Nullable
    private ClassLoader classLoader;
    @Nullable
    private RedisSerializer keySerializer = null;
    @Nullable
    private RedisSerializer valueSerializer = null;
    @Nullable
    private RedisSerializer hashKeySerializer = null;
    @Nullable
    private RedisSerializer hashValueSerializer = null;
    private RedisSerializer<String> stringSerializer = RedisSerializer.string();
    @Nullable
    private ScriptExecutor<K> scriptExecutor;
    @Nullable
    private ValueOperations<K, V> valueOps;
    @Nullable
    private ListOperations<K, V> listOps;
    @Nullable
    private SetOperations<K, V> setOps;
    @Nullable
    private ZSetOperations<K, V> zSetOps;
    @Nullable
    private GeoOperations<K, V> geoOps;
    @Nullable
    private HyperLogLogOperations<K, V> hllOps;

    public RedisTemplate() {
    }

    public void afterPropertiesSet() {
        super.afterPropertiesSet();
        boolean defaultUsed = false;
        //默认的序列化方式是JDK序列化,我们可能会使用Json来序列化
        if (this.defaultSerializer == null) {
            this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
        }

        if (this.enableDefaultSerializer) {
            if (this.keySerializer == null) {
                this.keySerializer = this.defaultSerializer;
                defaultUsed = true;
            }

            if (this.valueSerializer == null) {
                this.valueSerializer = this.defaultSerializer;
                defaultUsed = true;
            }

            if (this.hashKeySerializer == null) {
                this.hashKeySerializer = this.defaultSerializer;
                defaultUsed = true;
            }

            if (this.hashValueSerializer == null) {
                this.hashValueSerializer = this.defaultSerializer;
                defaultUsed = true;
            }
        }

        if (this.enableDefaultSerializer && defaultUsed) {
            Assert.notNull(this.defaultSerializer, "default serializer null and not all serializers initialized");
        }

        if (this.scriptExecutor == null) {
            this.scriptExecutor = new DefaultScriptExecutor(this);
        }

        this.initialized = true;
    }

................

}

关于对象的保存:
所有的对象都需要序列化
如果不设置序列化,下面案例将报错:
org.springframework.data.redis.serializer.SerializationException: Cannot serialize;

@Test
    public void test() throws Exception{
        User user = new User();
        user.setUsername("八神庵");
        user.setPassword("123456");
        String jsonUser = new ObjectMapper().writeValueAsString(user);
        redisTemplate.opsForValue().set("user",user);
        System.out.println (redisTemplate.opsForValue().get("user"));
    }

ps:生产中不会这么用原生的方式

自定义RedisTemplate
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
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.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
    // 自己定义了一个 RedisTemplate
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // 我们为了自己开发方便,一般直接使用 <String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate<String,Object>();
        template.setConnectionFactory(factory);
        // Json序列化配置
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // String 的序列化
        StringRedisSerializer stringRedisSerializer = new  StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

所有的redis操作,其实对于java开发人员来说,十分的简单,更重要是要去理解redis的思想和每一种数据结构的用处和作用场景!

redis 常用方法接口

定义常用方法接口,封装edisTemplate原生的操作方法

/**
 * redis 常用方法接口
 */
public interface MmzCacheManager {
    boolean expire(String var1, long var2);

    long getExpire(String var1);

    boolean hasKey(String var1);

    void del(String... var1);

    Object get(String var1);

    boolean set(String var1, Object var2);

    boolean set(String var1, Object var2, long var3);
}

参考:
https://www.bilibili.com/video/BV1S54y1R7SB?from=search&seid=11830527635443950811

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值