Версия среды разработки персональных приложений SpringBoot 2.1 — интегрированный кеш Redis

Redis
Версия среды разработки персональных приложений SpringBoot 2.1 — интегрированный кеш Redis

Эта статья является подразделом фреймворка персональной разработки SpringBoot 2.1, сначала прочтите ее.Фреймворк персональной разработки версии SpringBoot 2.1Прочтите эту статью еще раз

адрес проекта:Версия SpringBoot 2.1 среды разработки персональных приложений

Адрес фронтенд проекта:ywh-vue-admin

О том, зачем использовать Redis?

Зачем использовать кеш Redis в проекте? На самом деле, я использовал кеш Redis во время стажировки, но я знаю только, как использовать Redis, как его использовать и почему я его использую, всего этого я не знаю. Цитирую предложение из Интернета о том, что эта интеграция также предназначена для Redis и Redis, а не Redis для решения практических задач, но я думаю, что только изучив сначала, я могу узнать, при каких обстоятельствах Redis можно использовать для решения проблем.

Зачем использовать редис? Цитаты из интернета

1. Устраните нагрузку на процессор и память сервера приложений. 2. При использовании Redis в проекте учитываются две основные точки зрения: производительность и параллелизм. 3. Когда мы сталкиваемся с SQL, выполнение которого занимает много времени, а результаты меняются нечасто, особенно целесообразно поместить запущенные результаты в кэш. Таким образом, последующие запросы считываются из кэша, что позволяет быстро реагировать на запросы. 4. В случае большого параллелизма все запросы напрямую обращаются к базе данных, и база данных будет иметь исключения соединения. В настоящее время вам нужно использовать Redis для выполнения операции буферизации, чтобы запрос сначала обращался к Redis, а не напрямую к базе данных. 5. Таблицы лидеров и связанные с ними вопросы. Таблица лидеров сортируется по количеству очков. Команда zadd может напрямую реализовать эту функцию, а команду zrevrange можно использовать для получения первых 100 пользователей в соответствии с их оценками, а zrank можно использовать для получения рейтинга пользователей, что является очень простым и простым в использовании. 6. Вопросы подсчета, такие как количество лайков и ретвитов, поддерживаются атомарными приращениями, getset используется для сброса счетчика, атрибуты expired используются для подтверждения того, когда ключевое слово должно быть удалено.

В моем исследовании отмечаются:

Кроме того, Redis может выполнять резервное копирование данных в режиме master-slave (ведущий-ведомый).В распределенной системе резервное копирование данных может быть хорошо гарантировано.Redis автоматически создаст резервную копию данных в основной базе данных (master) в подчиненной базе данных (slave). )., Что касается того, почему вы должны использовать Redis, помимо причин в собственном проекте, есть много других причин, по которым вы можете заранее почерпнуть знания и опыт в Интернете.

Поддержка кэширования Spring Boot

В модуль ywh-starter-cache для интеграции помещаем вещь с кешем, а в кеше внедряем в файл pom.xmlspring-boot-starter-data-redisполагаться

<!-- redis依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.1.1.RELEASE</version>
</dependency>

Структура проекта кеша делится на

  • config - поставить класс конфигурации
  • сериализатор - поставить класс сериализатора
  • utils - поставить служебные классы

Анализ на уровне источника

Почему пользователям необходимо самостоятельно создавать класс конфигурации Redis?

SpringBoot обеспечивает автоматическую настройку Redis вRedisAutoConfigurationКласс настроен с клиентскими подключениями (Lettuce и Jedis) и шаблонами операций с данными (StringRedisTemplate и RedisTemplate) по умолчанию. Следующий код имеет аннотацию @ConditionalOnMissingBean и @Bean, а аннотация @ConditionalOnMissingBean определяет, следует ли выполнять код инициализации, то есть, если пользователь После того, как компонент был создан, связанный с ним код инициализации больше не выполняется. Это приводит к выполнению метода redisTemplate по умолчанию.

public class RedisAutoConfiguration {
    public 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;
    }
}

RedisTemplate, класс шаблона обработки данных, мы можем щелкнуть, чтобы посмотреть, в классе есть фрагмент кода

if (this.defaultSerializer == null) {
    this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
}

Если сериализация по умолчанию пуста, мы используем jdk для сериализации наших данных, а частное свойство defaultSerializer по умолчанию равно NULL, поэтому методом сериализации по умолчанию является метод jdk, но этот метод сериализации сделает данные невидимыми. Я понимаю, поэтому я необходимо создать класс конфигурации Redis, чтобы переопределить сериализацию по умолчанию.Если с моим анализом что-то не так, поправьте меня.

простое подключение

После анализа соединения осуществляются двумя способами. Первый: использовать StringRedisTemplate и RedisTemplate без изменения конфигурации по умолчанию.

Прежде чем мы напишем тест кода, нам нужно настроить файл application-redis.yml в модуле кеша и добавить redis в активный атрибут в файле application.yml под ядром, разделив запятыми, чтобы приложение-redis могло для чтения во время выполнения.yml, измените application.properties в модуле cache на файл application-redis.yml для конфигурации.

spring:
  redis:
    # Redis数据库索引(默认为0)
    database: 0
    # Redis服务器地址
    host: 127.0.0.1
    # Redis服务器连接端口
    port: 6379
    # Redis服务器连接密码(默认为空)如果没有配置密码就不要写这个属性了
    password: 123456
    #连接池
    lettuce:
      pool:
        #连接池最大连接数(使用负值表示没有限制)
        max-active: 8
        #连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: 60000
        #连接池中的最大空闲连接
        max-idle: 8
        #连接池中的最小空闲连接
        min-idle: 0
    #连接超时时间(毫秒)
    timeout: 10000

Напишите код в тестовом классе SpringBoot и запустите добавление данных.

@Autowired
private StringRedisTemplate stringRedisTemplate;

/**
 * 测试连接redis,并存入数据
 */
@Test
public void redisTest(){
    List<String> list = new ArrayList<>();
    list.add("a");
    list.add("b");
    list.add("c");
    stringRedisTemplate.opsForValue().set("abc","测试");
    stringRedisTemplate.opsForList().leftPushAll("ywh",list);

}

StringRedis测试数据

Данные, которые мы добавляем с помощью StringRedisTemplate, отображаются нормально и могут быть прочитаны нашими человеческими глазами. Затем мы используем класс RedisTemplate для подключения Redis, чтобы добавить данные, чтобы увидеть, как они выглядят. Сериализация по умолчанию JdkSerializationRedisSerializer сериализует двоичные данные. код аналогичен приведенному выше.

@Autowired
private RedisTemplate<String,Object> redisTemplate;

@Test
public void redisTest1(){
    List<String> list = new ArrayList<>();
    list.add("y");
    list.add("w");
    list.add("h");
    redisTemplate.opsForValue().set("redisTemplate","连接成功了");
    redisTemplate.opsForList().leftPushAll("redis",list);
}

RedisTemplate测试数据

Разумеется, добавленные данные не различимы человеческим глазом, поэтому давайте перезапишем конфигурацию по умолчанию и настроим собственный метод сериализации.

Переопределите конфигурацию по умолчанию для подключения

Spring предоставляет нам множество методов сериализации, все из которых находятся в пакете org.springframework.data.redis.serializer Наиболее часто используемые из них:

  • JdkSerializationRedisSerializer
  • GenericJackson2JsonRedisSerializer
  • StringRedisSerializer
  • Jackson2JsonRedisSerializer

Для этих четырех типов мы используем StringRedisSerializer только для сериализации значения ключа, значение значения создается нашим собственным классом сериализации, а наш пользовательский создается в пакете сериализатора.FastJsonRedisSerializerКласс должен реализовать интерфейс RedisSerializer, реализовать метод сериализации и метод десериализации в интерфейсе, а также использовать реализацию Alibaba Fastjson.

package com.ywh.cache.serializer;

/**
 * CreateTime: 2018-12-19 16:51
 * ClassName: FastJsonRedisSerializer
 * Package: com.ywh.cache.serializer
 * Describe:
 * 自定义的序列化类
 * @author YWH
 */
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
    private ObjectMapper objectMapper = new ObjectMapper();
 
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
 
    private Class<T> clazz;
 
    public FastJsonRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }
 
    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }
 
    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);
 
        return JSON.parseObject(str, clazz);
    }
    public void setObjectMapper(ObjectMapper objectMapper) {
        Assert.notNull(objectMapper, "'objectMapper' must not be null");
        this.objectMapper = objectMapper;
    }
 
    protected JavaType getJavaType(Class<?> clazz) {
        return TypeFactory.defaultInstance().constructType(clazz);
    }
}

После создания пользовательского класса сериализации перезапишите конфигурацию по умолчанию, а затем создайте ее в пакете конфигурации.RedisCacheConfigclass, после настройки класса конфигурации Redis, мы снова запустим тестовый класс и обнаружим, что значение больше не искажено.

package com.ywh.cache.config;
 
/**
 * CreateTime: 2018-12-18 23:34
 * ClassName: RedisCacheConfig
 * Package: com.ywh.cache.config
 * Describe:
 * Redis缓存配置   @EnableCaching 开启声明式缓存支持. 之后就可以使用 @Cacheable/@CachePut/@CacheEvict 注解缓存数据.
 * @author YWH
 */
@Configuration
@EnableCaching
public class RedisCacheConfig {
 
 
    private RedisConnectionFactory redisConnectionFactory;
 
    @Autowired
    public void setRedisConnectionFactory(RedisConnectionFactory redisConnectionFactory){
        this.redisConnectionFactory = redisConnectionFactory;
    }
 
    /**
     * 覆盖默认的配置
     * @return RedisTemplate
     */
    @Bean
    public RedisTemplate<String,Object> redisTemplate(){
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
 
 
        // 设置value的序列化规则和key的序列化规则
        template.setKeySerializer(stringRedisSerializer);
        template.setValueSerializer(fastJsonRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setHashValueSerializer(fastJsonRedisSerializer);
        template.setDefaultSerializer(fastJsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
 
    /**
     * 解决注解方式存放到redis中的值是乱码的情况
     * @param factory 连接工厂
     * @return CacheManager
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
 
        // 配置注解方式的序列化
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        RedisCacheConfiguration redisCacheConfiguration =
                config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer))
                        //配置注解默认的过期时间
                        .entryTtl(Duration.ofDays(1));
        // 加入白名单   https://github.com/alibaba/fastjson/wiki/enable_autotype
        ParserConfig.getGlobalInstance().addAccept("com.ywh");
        ParserConfig.getGlobalInstance().addAccept("com.baomidou");
        return RedisCacheManager.builder(factory).cacheDefaults(redisCacheConfiguration).build();
    }
}

Класс инструментов Redis

Redis может работать с пятью типами и может быть расширен сам по себе.Мы помещаем класс инструмента в модуль кеша, чтобы создать пакет utils, создаемRedisUtilTool, добавьте аннотацию @Component к классу и передайте его Spring для управления, мы можем получить его напрямую с помощью @AtuoWired в других методах.

package com.ywh.cache.utils;
/**
 * CreateTime: 2018-12-19 17:45
 * ClassName: RedisUtil
 * Package: com.ywh.cache.utils
 * Describe:
 * Redis工具类
 *
 * @author YWH
 */
@Component
public class RedisUtil {
 
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
 
    //---------------------- common --------------------------
 
    /**
     * 指定缓存失效时间
     * @param key key值
     * @param time 缓存时间
     * @return true设置成功,time <=0 设置失败
     */
    public void expire(String key, long time){
        if(time > 0){
            redisTemplate.expire(key,time,TimeUnit.SECONDS);
        }else{
            throw MyExceptionUtil.mxe("设置的时间不能为0或者小于0!!");
        }
    }
 
    /**
     * 判断key是否存在
     * @param key
     * @return true 存在  false  不存在
     */
    public Boolean existsKey(String key){
        return redisTemplate.hasKey(key);
    }
 
    。。。。省略代码,具体代码可前往github查看
 
}