1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/marquis001-springboot-cache

В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

springboot-cache

Описание проекта

Множественные уровни кэширования.

Архитектура программного обеспечения

redis ehcache

Инструкции по установке

  1. Кэширование ehcache
1) Maven зависимость
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- Кэширование Ehcache -->
<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.3.0</version>
</dependency>
2) Конфигурация класса
```3) Конфигурация xml
 ehcache.xml
 <config
         xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
         xmlns='http://www.ehcache.org/v3'
         xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">
     <!-- Путь к папке для хранения данных -->
     <persistence directory="D:/ehcacheData"/>
      <!-- Шаблон кэша, для демонстрации его использования, можно не использовать шаблон и задать параметры напрямую в кэше -->
     <cache-template name="template">
         <key-type>java.lang.String</key-type>
         <value-type>java.lang.String</value-type>
         <expiry>
             <!-- Единица измерения по умолчанию - секунды, если используется секунды, можно не указывать -->
             <ttl unit="hours">1</ttl>
         </expiry>
         <resources>
             <!-- Единица измерения по умолчанию - записи, если используется записи, можно не указывать -->
             <heap>1</heap>
             <offheap unit="MB">1</offheap>
             <!-- persistent по умолчанию - false, можно не указывать -->
             <disk unit="MB">20</disk>
         </resources>
     </cache-template>
      <!-- Объект кэша, если используется шаблон, он перезапишет параметры шаблона, используя uses-template="" для ссылки на шаблон -->
     <cache alias="defaultCache" uses-template="template">
         <expiry>
             <!-- Здесь перезапишет параметры шаблона (TTL) -->
             <tti>60</tti>
         </expiry>
         <resources>
             <disk unit="MB" persistent="true">500</disk>
         </resources>
         <!-- Не исследовал эту часть, пока оставлю без внимания
         <eviction-advisor></eviction-advisor>
         -->
     </cache>
 </config>
 ```Конфигурация класса для загрузки:
 ```java
 System.out.println("[Инициализация конфигурации Ehcache<начало>]");
 // Установка параметров по умолчанию для кэша
 ```cacheManager = CacheManagerBuilder.newCacheManager(new XmlConfiguration(getClass().getResource("/ehcache.xml")));
cacheManager.init();
System.out.println("[Инициализация конфигурации Ehcache завершена]");

Конфигурация в application.yml:

spring:
  cache:
    ehcache:
      config: ehcache.xml
  1. Тестирование кода
  2. Тестирование аннотаций
@Service
public class EhCacheService {
    @Cacheable(value = "test")
    public String readCache() {
        System.out.println("Если это не выполнено, значит данные были кэшированы");
        return "1234";
    }

    @CachePut(value = "test")
    public String update() {
        // Обновление кэша, что изменит содержимое
        System.out.println("Кэш обновлен");
        return "456";
    }
}
```    @CacheEvict(value="test",allEntries = true)
    public void deleteAll() {
        System.out.println("Все кэши удалены");
    }
}

6) Код контроллера
@RestController
@RequestMapping("/ehcache")
public class EhCacheController {
    @Autowired
    public EhCacheService ehCacheService;

    @GetMapping("/read")
    public String readEhCache(){
        return ehCacheService.readCache();
    }

    @GetMapping("/deleteAll")
    public String deleteAll(){
         ehCacheService.deleteAll();
        return  "Удаление выполнено";
    }```java
    @GetMapping("/update")
     public String update(){
         ehCacheService.update();
         return "Обновление выполнено";
     }
 }
  1. Интеграция Redis
1) Maven зависимости
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Необходимые зависимости для интеграции Redis в Spring 2.0 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
</dependency>
2) Конфигурационный класс
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
@Slf4j
public class RedisCacheConfiguration {
    /**
     * Кэш-шаблон
     * @param lettuceConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        RedisTemplate<String, Serializable> template = new RedisTemplate<>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setConnectionFactory(lettuceConnectionFactory);
        return template;
    }
}
``````markdown
    /**
     * Кэш-менеджер
     * @param lettuceConnectionFactory
     * @return
     */
    @Bean
    public CacheManager cacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
        RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder
                .fromConnectionFactory(lettuceConnectionFactory);
        @SuppressWarnings("serial")
        Set<String> cacheNames = new HashSet<String>() {
            {
                add("codeNameCache");
            }
        };
        builder.initialCacheNames(cacheNames);
        return builder.build();
    }
}
3) Конфигурационный файл
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
# Время ожидания подключения (в миллисекундах)
spring.redis.timeout=10000
# По умолчанию Redis имеет 16 сегментов, здесь указывается конкретный сегмент
spring.redis.database=0
```# Максимальное количество подключений в пуле (отрицательное значение означает отсутствие ограничений) по умолчанию 8
spring.redis.lettuce.pool.max-active=8
# Максимальное время ожидания подключения в пуле (отрицательное значение означает отсутствие ограничений) по умолчанию -1
spring.redis.lettuce.pool.max-wait=-1
# Максимальное количество пустых подключений в пуле по умолчанию 8
spring.redis.lettuce.pool.max-idle=8
# Минимальное количество пустых подключений в пуле по умолчанию 0
spring.redis.lettuce.pool.min-idle=0
4) Тестовый класс
// TODO Проверка потоковой безопасности
ExecutorService executorService = Executors.newFixedThreadPool(1000);
IntStream.range(0, 1000).forEach(i ->
       executorService.execute(() -> stringRedisTemplate.opsForValue().increment("kk", 1))
);
stringRedisTemplate.opsForValue().set("k1", "v1");
final String k1 = stringRedisTemplate.opsForValue().get("k1");
log.info("[Результат кэширования строк] - [{}]", k1);
// TODO Поддерживаемые Redis команды
String key = "battcn:user:1";
redisCacheTemplate.opsForValue().set(key, new User(1L, "u1", "pa"));
// TODO Соответствует String (строка)
final User user = (User) redisCacheTemplate.opsForValue().get(key);
log.info("[Результат кэширования объекта] - [{}]", user);
}
  1. Интеграция многоуровневого кэширования
1) Класс сообщения
@Data
public class CacheMessage implements Serializable {
    private static final long serialVersionUID = 5987219310442078193L;
    private String cacheName;
    private Object key;
    private Integer sender;
    public CacheMessage(String cacheName, Object key) {
        super();
        this.cacheName = cacheName;
        this.key = key;
    }
    public CacheMessage(String cacheName, Object key, Integer sender) {
        super();
        this.cacheName = cacheName;
        this.key = key;
        this.sender = sender;
    }
}
```2) Пользовательский класс кэширования
 @Slf4j
 public class RedisEhcacheCache extends AbstractValueAdaptingCache {
     private String name;
     private RedisTemplate<Object, Object> redisTemplate;
     private Cache<Object, Object> ehcacheCache;
     private String cachePrefix;
     private long defaultExpiration = 0;
     private Map<String, Long> expires;
     private String topic = "cache:redis:ehcache:topic";
     protected RedisEhcacheCache(boolean allowNullValues) {
         super(allowNullValues);
     }    public RedisEhcacheCache(String name, RedisTemplate<Object, Object> redisTemplate, Cache<Object, Object> ehcacheCache, RedisEhcacheProperties redisEhcacheProperties) {
        super(redisEhcacheProperties.isCacheNullValues());
        this.name = name;
        this.redisTemplate = redisTemplate;
        this.ehcacheCache = ehcacheCache;
        this.cachePrefix = redisEhcacheProperties.getCachePrefix();
        this.defaultExpiration = redisEhcacheProperties.getRedis().getDefaultExpiration();
        this.expires = redisEhcacheProperties.getRedis().getExpires();
        this.topic = redisEhcacheProperties.getRedis().getTopic();
        log.info("Пользовательский кэшировщик " + name);
    }

    @Override
    public String getName() {
        return this.name;
    }    @Override
    public Object getNativeCache() {
        return this;
    }
}
```java
    @SuppressWarnings("unchecked")
    @Override
    public <T> T get(Object key, Callable<T> valueLoader) {
        log.info("Вызов пользовательского метода GET для кэша");
        Object value = lookup(key);
        if (value != null) {
            return (T) value;
        }
        ReentrantLock lock = new ReentrantLock();
        try {
            lock.lock();
            value = lookup(key);
            if (value != null) {
                return (T) value;
            }
            value = valueLoader.call();
            Object storeValue = toStoreValue(valueLoader.call());
            put(key, storeValue);
            return (T) value;
        } catch (Exception e) {
            try {
                Class<?> c = Class.forName("org.springframework.cache.Cache$ValueRetrievalException");
                Constructor<?> constructor = c.getConstructor(Object.class, Callable.class, Throwable.class);
                RuntimeException exception = (RuntimeException) constructor.newInstance(key, valueLoader, e.getCause());
                throw exception;
            } catch (Exception e1) {
                throw new IllegalStateException(e1);
            }
        } finally {
            lock.unlock();
        }
    }
    // Чтение значения value из устойчивого слоя и сохранение его в кэше. Разрешено значение value = null
    @Override
    public void put(Object key, Object value) {
        log.info("Вызов пользовательского метода кэширования PUT для ключа " + getKey(key));
        if (!super.isAllowNullValues() && value == null) {
            this.evict(key);
            return;
        }
        long expire = getExpire();
        if (expire > 0) {
            redisTemplate.opsForValue().set(getKey(key), toStoreValue(value), expire, TimeUnit.MILLISECONDS);
        } else {
            redisTemplate.opsForValue().set(getKey(key), toStoreValue(value));
        }
    }
```        // Отправка сообщения через redis для сброса кэша других служб.
        // Недостаток оригинального метода: после помещения KV в кэш службой 1 и отправки сообщения через redis,
        // служба 1 получает это сообщение и удаляет только что помещённое KV.
        // Здесь передаётся хэш-код ehcacheCache, чтобы избежать этой проблемы.
        push(new CacheMessage(this.name, key, this.ehcacheCache.hashCode()));
        ehcacheCache.put(key, value);
    }
    // Генерация ключа name:cachePrefix:key
    private Object getKey(Object key) {
        log.info("Вызов пользовательского метода получения ключа");
        return this.name.concat(":").concat(StringUtils.isEmpty(cachePrefix) ? key.toString() : cachePrefix.concat(":").concat(key.toString()));
    }    private long getExpire() {
        log.info("Вызов пользовательского метода получения времени жизни");
        long expire = defaultExpiration;
        Long cacheNameExpire = expires.get(this.name);
        return cacheNameExpire == null ? expire : cacheNameExpire.longValue();
    }    @Override
    public ValueWrapper putIfAbsent(Object key, Object value) {
        Object cacheKey = getKey(key);
        Object prevValue = null;
        // Рассмотреть использование распределенного блокирования или замену redis.setIfAbsent на атомарную операцию
        synchronized (key) {
            prevValue = redisTemplate.opsForValue().get(cacheKey);
            if(prevValue == null) {
                long expire = getExpire();
                if(expire > 0) {
                    redisTemplate.opsForValue().set(getKey(key), toStoreValue(value), expire, TimeUnit.MILLISECONDS);
                } else {
                    redisTemplate.opsForValue().set(getKey(key), toStoreValue(value));
                }
                //
                push(new CacheMessage(this.name, key, this.ehcacheCache.hashCode()));
                //
                ehcacheCache.put(key, toStoreValue(value));
            }
        }
        return toValueWrapper(prevValue);
    }    @Override
    public void evict(Object key) {
        log.info("Вызов метода evict для пользовательского кэша");
        // Сначала удаляем данные из кэша Redis, затем из кэша Ehcache, чтобы избежать ситуации, когда в краткосрочной перспективе запросы будут перезагружать данные из Redis в Ehcache
        redisTemplate.delete(getKey(key));
        push(new CacheMessage(this.name, key, this.ehcacheCache.hashCode()));
        //
        ehcacheCache.remove(key);
    }    @Override
    public void clear() {
        // Сначала удаляем данные из кэша Redis, затем из кэша Ehcache, чтобы избежать ситуации, когда в краткосрочной перспективе запросы будут перезагружать данные из Redis в Ehcache
        Set<Object> keys = redisTemplate.keys(this.name.concat(":"));
        for (Object key : keys) {
            redisTemplate.delete(key);
        }
        push(new CacheMessage(this.name, null));
        ehcacheCache.clear();
    }

    // Получение значения из кэша по ключу, если значение отсутствует, то требуется чтение из постоянного хранилища
    @Override
    protected Object lookup(Object key) {
        Object cacheKey = getKey(key);
        Object value = ehcacheCache.get(key);
        if (value != null) {
            log.info("Получение значения из кэша Ehcache, ключ: {}", cacheKey);
            return value;
        }
        value = redisTemplate.opsForValue().get(cacheKey);
        log.info("Значение: {}", value);
        log.info("Ключ: {}", cacheKey);
        if (value != null) {
            log.info("Получение значения из кэша Redis и добавление в кэш Ehcache, ключ: {}", cacheKey);
            // Перенос данных из вторичного кэша в первичный кэш. Принцип: ключи, недавно использовавшиеся, вероятно, будут использоваться снова
            ehcacheCache.put(cacheKey, value);
        }
        return value;
    }    /**
      * При изменении кэша используем функцию подписки на сообщения Redis для уведомления других узлов о необходимости очистки локального кэша.
      * @description
      * @param message
      */
     private void push(CacheMessage message) {
         redisTemplate.convertAndSend(topic, message);
     }    /**
      * @description Очистка локального кэша
      * @param key
      */
     public void clearLocal(Object key) {
         log.info("Очистка локального кэша, этот ключ: {}", key);
         if (key == null) {
             ehcacheCache.clear();
         } else {
             ehcacheCache.remove(key);
         }
     }
     public Cache<Object, Object> getLocalCache() {
         return ehcacheCache;
     }
 }
 3) Класс-слушатель сообщений Redis
 @Slf4j
 public class CacheMessageListener implements MessageListener {
     private RedisTemplate<Object, Object> redisTemplate;
     private RedisEhcacheCacheManager redisEhcacheCacheManager;
     public CacheMessageListener(RedisTemplate<Object, Object> redisTemplate,
                                 RedisEhcacheCacheManager redisEhcacheCacheManager) {
         super();
         this.redisTemplate = redisTemplate;
         this.redisEhcacheCacheManager = redisEhcacheCacheManager;
         log.info("Отслеживание кэша");
     }
 }    @Override
     public void onMessage(Message message, byte[] pattern) {
         CacheMessage cacheMessage = (CacheMessage) redisTemplate.getValueSerializer().deserialize(message.getBody());
         log.info("Получено сообщение Redis, имя кеша: {}, ключ: {}", cacheMessage.getCacheName(), cacheMessage.getKey());
         // Очистка кеша ehcache
         redisEhcacheCacheManager.clearLocal(cacheMessage.getCacheName(), cacheMessage.getKey(), cacheMessage.getSender());
     }
 }
 4) Пользовательский класс управления кешем
 @Slf4j
 public class RedisEhcacheCacheManager implements CacheManager {
     private ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>();
     private RedisEhcacheProperties redisEhcacheProperties;
     private RedisTemplate<Object, Object> redisTemplate;
     private boolean dynamic = true;
     private Set<String> cacheNames;
 }    private org.ehcache.CacheManager ehCacheManager;
    private CacheConfiguration configuration;    public RedisEhcacheCacheManager(RedisEhcacheProperties redisEhcacheProperties,
                                    RedisTemplate<Object, Object> redisTemplate) {
        super();
        this.redisEhcacheProperties = redisEhcacheProperties;
        this.redisTemplate = redisTemplate;
        this.dynamic = redisEhcacheProperties.isDynamic();
        this.cacheNames = redisEhcacheProperties.getCacheNames();
        setAboutEhCache();
    }

    /**
     * Настройка кеша EhCache
     */
    private void setAboutEhCache(){
        long ehcacheExpire = redisEhcacheProperties.getEhcache().getExpireAfterWrite();
        this.configuration =
                CacheConfigurationBuilder
                        .newCacheConfigurationBuilder(Object.class, Object.class, ResourcePoolsBuilder.heap(redisEhcacheProperties.getEhcache().getMaxEntry()))
                        .withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(ehcacheExpire)))
                        .build();
        this.ehCacheManager = CacheManagerBuilder
                .newCacheManagerBuilder()
                .build();
        this.ehCacheManager.init();
        log.info("Настройка кеша");
    }

    /**
     * Получить кэш
     * @param name
     * @return
     */
    @Override
    public Cache getCache(String name) {
        Cache cache = cacheMap.get(name);
        if(cache != null) {
            return cache;
        }
        if(!dynamic && !cacheNames.contains(name)) {
            return cache;
        }
        cache = new RedisEhcacheCache(name, redisTemplate, getEhcache(name), redisEhcacheProperties);
        Cache oldCache = cacheMap.putIfAbsent(name, cache);
        log.debug("Создан экземпляр кэша, имя кэша : {}", name);
        return oldCache == null ? cache : oldCache;
    }

    /**
     * Получение кэша Ehcache
     * @param name
     * @return
     */
    public org.ehcache.Cache<Object, Object> getEhcache(String name){
        org.ehcache.Cache<Object, Object> res = ehCacheManager.getCache(name, Object.class, Object.class);
        if(res != null){
            return res;
        }
        return ehCacheManager.createCache(name, configuration);
    }    @Override
    public Collection<String> getCacheNames() {
        return this.cacheNames;
    }

    public void clearLocal(String cacheName, Object key, Integer sender) {
        Cache cache = cacheMap.get(cacheName);
        if (cache == null) {
            return;
        }
        RedisEhcacheCache redisEhcacheCache = (RedisEhcacheCache) cache;
        // Если это сообщение от самого отправителя, ключ не удаляется
        if (redisEhcacheCache.getLocalCache().hashCode() != sender) {
            redisEhcacheCache.clearLocal(key);
        }
    }
}
5) Класс конфигурации кэша CacheRedisEhcacheAutoConfiguration
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
// Переключение между вторичным кэшем и первичным: true - включить вторичный кэш, false - отключить вторичный кэш
@ConditionalOnProperty(name = "cache.use2L", havingValue = "true", matchIfMissing = false)
@EnableConfigurationProperties(RedisEhcacheProperties.class)
@Slf4j
public class CacheRedisEhcacheAutoConfiguration {

    @Autowired
    private RedisEhcacheProperties redisEhcacheProperties;```markdown
    /**
      * Кэш-менеджер
      *
      * @param lettuceConnectionFactory
      * @return
      */
     @Bean
     public RedisEhcacheCacheManager cacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
         return new RedisEhcacheCacheManager(redisEhcacheProperties, redisCacheTemplate(lettuceConnectionFactory));
     }
     /**
      * Отслеживание RedisMessage
      * @param redisTemplate
      * @param redisEhcacheCacheManager
      * @return
      */
     @Bean
     @ConditionalOnBean(RedisEhcacheCacheManager.class)
     public RedisMessageListenerContainer redisMessageListenerContainer(RedisTemplate<Object, Object> redisTemplate,
                                                                         RedisEhcacheCacheManager redisEhcacheCacheManager) {
         RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
         redisMessageListenerContainer.setConnectionFactory(redisTemplate.getConnectionFactory());
         CacheMessageListener cacheMessageListener = new CacheMessageListener(redisTemplate, redisEhcacheCacheManager);
         // Добавление слушателя кэша
         log.info("3. Добавление слушателя кэша в Redis");
         redisMessageListenerContainer.addMessageListener(cacheMessageListener, new ChannelTopic(redisEhcacheProperties.getRedis().getTopic()));
         return redisMessageListenerContainer;
     }
 }
 6) Конфигурация Redis RedisCacheConfig
 @Configuration
 @EnableCaching // Включение аннотаций
 @ConditionalOnProperty(name = "cache.use2L", havingValue = "false", matchIfMissing = true)
 @EnableConfigurationProperties(RedisEhcacheProperties.class)
 @Slf4j
 public class RedisCacheConfig {
     /**
      * Кэш-шаблон
      *
      * @param lettuceConnectionFactory
      * @return
      */
     @Bean
     public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
         RedisTemplate<String, Serializable> template = new RedisTemplate<>();
         template.setKeySerializer(new StringRedisSerializer());
         template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
         template.setConnectionFactory(lettuceConnectionFactory);
         return template;
     }
 }
```    public CacheManager cacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
         RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder
                 .fromConnectionFactory(lettuceConnectionFactory);
         return builder.build();
     }
 }
 7)Конфигурационный файл EhCache
 <?xml version="1.0" encoding="UTF-8"?>
 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
          updateCheck="false" name="ec">    <diskStore path="java.io.tmpdir"/> <!-- Директория для хранения кэша (по умолчанию используется системная директория для временных файлов), также может быть "D:/cache" или "java.io.tmpdir" -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
    />    <! -- -->
     <cache name="j2CacheRedis"
            maxElementsInMemory="1000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="140"
            overflowToDisk="false"
            memoryStoreEvictionPolicy="LRU"/>
<! --
  name: Уникальный идентификатор кеша
  maxElementsInMemory: Максимальное количество объектов кеша в памяти
  maxElementsOnDisk: Максимальное количество объектов кеша на диске, если значение равно 0, то ограничение отсутствует
  eternal: Определяет, являются ли элементы вечными, если установлено значение true, то параметр timeout не применяется
  overflowToDisk: Если количество элементов в памяти достигает maxElementsInMemory, то элементы будут записаны на диск
  timeToIdleSeconds: Время до истечения срока действия элемента, если элемент не является вечным. Необязательный параметр, значение по умолчанию равно 0, что означает бесконечное время до истечения срока действия
  timeToLiveSeconds: Время до истечения срока действия элемента, если элемент не является вечным. Значение по умолчанию равно 0, что означает бесконечное время до истечения срока действия
  diskPersistent: Сохранение данных кеша при перезагрузке виртуальной машины
  diskExpiryThreadIntervalSeconds: Интервал времени выполнения потока проверки истечения срока действия на диске, значение по умолчанию равно 120 секундам
  diskSpoolBufferSizeMB: Размер буфера кеша на диске. Значение по умолчанию равно 30 МБ. Каждый кеш должен иметь свой собственный буфер
 ```  memoryStoreEvictionPolicy: Политика очистки памяти при достижении ограничения maxElementsInMemory. Значение по умолчанию равно LRU (Least Recently Used). Можно установить значение FIFO (First In First Out) или LFU (Least Frequently Used)
</ehcache>
8) Файл конфигурации свойств
spring.redis.hostName=127.0.0.1
spring.redis.port=6379
spring.redis.timeOut=1000
spring.redis.maxIdle=10
spring.redis.maxWaitMillis=15000
spring.redis.testOnBorrow=true
spring.redis.testWhileIdle=false
```## Настройка redis-starter```spring.cache.cache-names=cache1,cache2,cache3
spring.redis.timeout=10000
#Пользовательские настройки. expire задан в миллисекундах
cache.multi.cacheNames=cache1,cache2,cache3
cache.multi.ehcache.expireAfterWrite=5000
cache.multi.ehcache.maxEntry=1000
cache.multi.redis.defaultExpiration=60000
cache.multi.redis.expires.cache1=50000
cache.multi.redis.expires.cache2=70000
cache.multi.redis.expires.cache3=70000
#Включение двухуровневого кэширования
cache.use2L=true

9) Тестирование
@Component
@Slf4j
public class CacheTestService {
   //cacheManager = "cacheManager" можно не указывать
   @Cacheable(value = "gerritCache", key = "#root.targetClass + '_' + #root.methodName + '_' + #root.args[0]", cacheManager = "cacheManager")
   public String get(long id) {
       log.info("Получение данных из базы данных");
       return "test";
   }
}

public class CacheTestServiceTest extends SpringbootCacheApplicationTests {
   @Autowired
   private CacheTestService cacheTestService;
   @Test
   public void get0() throws Exception {
       cacheTestService.get(123L);
   }
}

Описание:
Если параметр cache.use2L=true установлен в true,
то будет включен кэширование Ehcache. Если параметр установлен в false, то будет использоваться только кэширование Redis.

Инструкции по использованию

  1. xxxx
  2. xxxx
  3. xxxx

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Множественное использование кэша. Развернуть Свернуть
Отмена

Обновления

Пока нет обновлений

Участники

все

Язык

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/marquis001-springboot-cache.git
git@api.gitlife.ru:oschina-mirror/marquis001-springboot-cache.git
oschina-mirror
marquis001-springboot-cache
marquis001-springboot-cache
master