zoukankan      html  css  js  c++  java
  • 1.2_springboot2.x中redis缓存&原理介绍

    1、整合redis作为缓存

    说明这里springboot版本2.19
    Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构

    1、安装redis,使用docker安装

    docker search redis

    在这里插入图片描述

    docker pull redis 下载redis,这里已经下载过了就不演示了

    使用docker images 查看容器:

    在这里插入图片描述

    启动redis

    docker run -d -p 6379:6379 --name myredis docker.io/redis

    将虚拟机的端口和容器的端口绑定并且后台运行

    在这里插入图片描述

    使用客户端连接(host根据自己配置)

    在这里插入图片描述

    配置好进入页面

    在这里插入图片描述

    1.1.1、概念介绍

    1.jedis和lettuce介绍
    Lettuce 和 Jedis 的定位都是Redis的client

    Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接

    Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,因为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。

    springboot2之前redis的连接池为jedis,2.0以后redis的连接池改为了lettuce,lettuce能够支持redis4,需要java8及以上。lettuce是基于netty实现的与redis进行同步和异步的通信,之前看到spring-session-data-redis里的samples已经改为使用LettuceConnectionFactory

    所以下面我们看下如何来使用Lettuce来操作Redis

    RedisAutoConfiguration 自动配置类

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

    可以知道RedisAutoConfiguration完成了对JedisConnectionFactory和LettuceConnectionFactory的自动配置。

    同时RedisProperties源码中封装了对redis配置,包括jedis和lettuce

    @ConfigurationProperties(prefix = "spring.redis")
    public class RedisProperties {
        private final Jedis jedis = new Jedis();
    
    	private final Lettuce lettuce = new Lettuce();
    }
    
    

    因此我们在使用时直接通过yml配置即可使用Lettuce来连接Redis

    1.1.2、引入starter

    使用Lettuce连接Redis,maven项目,引入依赖,注意lettuce连接池的使用需要引入commons-pool2依赖包

     <!--引入redis-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-pool2</artifactId>
            </dependency>
    

    1.1.3、配置redis

    application.yml配置

    #redis 的配置
    # springboot2.x以上如此配置,由于2.x的客户端是lettuce
    # 单位要带上
    spring:
      redis:
        host: 192.168.56.101
        port: 6379
        database: 0
    
        lettuce:
          pool:
            max-active: 8
            min-idle: 0
            max-idle: 8
            max-wait: 10000ms
          shutdown-timeout: 100ms
    
    
    

    1.1.4、测试redis是否成功

    原理:RedisAutoConfiguration中有两个操作类

    stringRedisTemplate; //操作k,v都是字符串
    redisTemplate; //操作k,v 都是对象

    @Configuration
    @ConditionalOnClass(RedisOperations.class)
    @EnableConfigurationProperties(RedisProperties.class)
    @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
    public class RedisAutoConfiguration {
    
    	@Bean
    	@ConditionalOnMissingBean(name = "redisTemplate")
    	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
    			throws UnknownHostException {
    		RedisTemplate<Object, Object> template = new RedisTemplate<>();
    		template.setConnectionFactory(redisConnectionFactory);
    		return template;
    	}
    
    	@Bean
    	@ConditionalOnMissingBean
    	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
    			throws UnknownHostException {
    		StringRedisTemplate template = new StringRedisTemplate();
    		template.setConnectionFactory(redisConnectionFactory);
    		return template;
    	}
    
    }
    

    Redis:常见的五大数据类型:String、List(列表)、Set(集合) Hash(散列) 、ZSet(有序集合) stringRedisTemplate.opsForValue() [String]

    stringRedisTemplate.opsForList() [List]

    stringRedisTemplate.opsForSet() [Set]

    stringRedisTemplate.opsForHash() [Hash]

    stringRedisTemplate.opsForZSet() [ZSet]

    redis中测试保存对象(以json格式)

        @Test
        public void testRedis02(){
            Employee emp = employeeMapper.getEmpById(1);
            //默认如果保存对象,使用jdk序列化机制,序列化的数据保存在redis中
            //redisTemplate.opsForValue().set("emp-01",emp);
            /**将数据以json形式保存
             * 1、自己转为json
             * 2、redisTemplate默认的序列化规则,可以改变序列化规则,自定义配置类
             */
            EmployeeRedisTemplate.opsForValue().set("emp-01",emp);
    
        }
    

    自定义redis配置类

    @Configuration
    public class MyRedisConfig {
    
        @Bean
        public RedisTemplate<Object, Employee> EmployeeRedisTemplate(RedisConnectionFactory redisConnectionFactory)
                throws UnknownHostException {
            RedisTemplate<Object, Employee> template = new RedisTemplate<>();
            template.setConnectionFactory(redisConnectionFactory);
            Jackson2JsonRedisSerializer<Employee> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Employee>(Employee.class);
            template.setDefaultSerializer(valueSerializer());
            return template;
    
        }
    

    结果

    在这里插入图片描述

    1.1.5、测试redis缓存

    原理:CacheManager===Cache缓存组件来实际给缓存中存取数据, *

    这时候org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration失效,用org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration代替,原因是:

    提前判断是否有CacheManager.class判断成功,有了redis的RedisCacheManager

    @Configuration
    @ConditionalOnClass(RedisConnectionFactory.class)
    @AutoConfigureAfter(RedisAutoConfiguration.class)
    @ConditionalOnBean(RedisConnectionFactory.class)
    @ConditionalOnMissingBean(CacheManager.class)
    @Conditional(CacheCondition.class)
    class RedisCacheConfiguration {
        
        @Bean
    	public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory,
    			ResourceLoader resourceLoader) {
    		RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory)
    				.cacheDefaults(determineConfiguration(resourceLoader.getClassLoader()));
    		List<String> cacheNames = this.cacheProperties.getCacheNames();
    		if (!cacheNames.isEmpty()) {
    			builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
    		}
    		return this.customizerInvoker.customize(builder.build());
    	}
    }
    

    @ConditionalOnMissingBean(CacheManager.class) redis顺序在前,因此加载RedisCacheManager

    1、引入redis的start,容器中保存的是RedisCacheManager

    2、RedisCacheManager帮我们创建RedisCache来作为缓存组件,RedisCache通过redis缓存数据

    3、默认保存数据k-v都是Object类型的,默认利用序列化

    怎么以json保存?

    RedisCacheConfiguration

    @Bean
    	public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory,
    			ResourceLoader resourceLoader) {
    		RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory)
    				.cacheDefaults(determineConfiguration(resourceLoader.getClassLoader()));
    		List<String> cacheNames = this.cacheProperties.getCacheNames();
    		if (!cacheNames.isEmpty()) {
    			builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
    		}
    		return this.customizerInvoker.customize(builder.bud());
    	}
    

    ​ 1、引入了redis的starter,CacheManager变为RedisCacheManager *

    ​ 2、默认创建的RedisCacheManager操作redis缓存数据是通过cacheDefaults()

    RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory)      .cacheDefaults(determineConfiguration(resourceLoader.getClassLoader()));
    

    ​ 3、调用 this.defaultCacheConfiguration = defaultCacheConfiguration;

    public static class RedisCacheManagerBuilder {
    		private RedisCacheConfiguration defaultCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
    
    public RedisCacheManagerBuilder cacheDefaults(RedisCacheConfiguration defaultCacheConfiguration) {
    
    			Assert.notNull(defaultCacheConfiguration, "DefaultCacheConfiguration must not be null!");
    
    			this.defaultCacheConfiguration = defaultCacheConfiguration;
    
    			return this;
    		}
    

    4、再调用defaultCacheConfig()

    RedisCacheConfiguration

    注意RedisCacheConfiguration是spring-data-redis下的配置包,区别redis的自动配置包

    public static RedisCacheConfiguration defaultCacheConfig() {
    		return defaultCacheConfig(null);
    	}
    

    可以查看defaultCacheConfig方法查看默认的序列化机制

    public static RedisCacheConfiguration defaultCacheConfig(@Nullable ClassLoader classLoader) {
    
    		DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
    
    		registerDefaultConverters(conversionService);
    
    		return new RedisCacheConfiguration(Duration.ZERO, true, true, CacheKeyPrefix.simple(),
    				SerializationPair.fromSerializer(RedisSerializer.string()),
    				SerializationPair.fromSerializer(RedisSerializer.java(classLoader)), conversionService);
    	}
    
    SerializationPair.fromSerializer(RedisSerializer.string()),
    				SerializationPair.fromSerializer(RedisSerializer.java(classLoader)), conversionService);
    

    默认使用jdk序列化机制

    static RedisSerializer<Object> java(@Nullable ClassLoader classLoader) {
    		return new JdkSerializationRedisSerializer(classLoader);
    	}
    

    1.1.6自定义缓存管理器

    在redis配置类中

    @Configuration
    public class MyRedisConfig {
        // key键序列化方式
        private RedisSerializer<String> keySerializer() {
            return new StringRedisSerializer();
        }
    
        // value值序列化方式
        private GenericJackson2JsonRedisSerializer valueSerializer(){
            return new GenericJackson2JsonRedisSerializer();
        } 
    /*
        * 配置缓存管理器
        *  @Primary 具有多个缓存管理器,必须得指定一个默认的缓存管理器,springboot1.5.9要制定
        * */
        //@Primary
        @Bean
        public RedisCacheManager myRedisCacheManager(RedisConnectionFactory redisConnectionFactory) {
    
            RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                    // 设置key的序列化方式
                    .entryTtl(Duration.ofSeconds(600000)) // 60s缓存失效
                    // 设置key的序列化方式
                    .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
                    // 设置value的序列化方式
                    .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
                    // 不缓存null值
                    .disableCachingNullValues();
            RedisCacheManager redisCacheManager= RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config)
                    .transactionAware()
                    .build();
            System.out.println("自定义RedisCacheManager加载完成");
            return redisCacheManager;
    
        }
    

    配置完成

    测试:

    service

    @Service
    public class DeptService {
        @Autowired
        DeparmentMapper deparmentMapper;
    
        //@Qualifier("myRedisCacheManager")
        @Autowired
        RedisCacheManager redisCacheManager;
          //  可以从缓存中获取数据,可以对缓存进行操作
    
        public Department getDeptById(Integer id){
            Department department =deparmentMapper.getDeptByID(id);
            Cache dept = redisCacheManager.getCache("dept");
            dept.put("dept:dept1",department);
            return department;
    
        }
    

    controller

    @RestController
    public class DeptController {
        @Autowired
        DeptService deptService;
    
        @GetMapping("/dept/{id}")
        public Department getDeptById(@PathVariable("id") Integer id){
            return deptService.getDeptById(id);
        }
    
    }
    

    结果:
    在这里插入图片描述

  • 相关阅读:
    DES介绍
    jsp知识点
    浏览器地址传中文
    cookie
    null与“ ”的区别
    验证二叉查找树 · Validate Binary Search Tree
    二叉树中的最大路径和 · Binary Tree Maximum Path Sum
    最近公共祖先 · Lowest Common Ancestor
    平衡二叉树Balanced Binary Tree
    二叉树的最大/小/平衡 深度 depth of binary tree
  • 原文地址:https://www.cnblogs.com/jatpeo/p/11767478.html
Copyright © 2011-2022 走看看