В этой статье мне хотелось бы показать, как использовать Redis для кэширования при работе с приложением Spring Boot.
Кэширование очень важно для веб-разработки — оно помогает быстро получить ответ на запрос.
Приступая к работе
Redis — самый популярный инструмент для кэширования. Он широко используется при разработке веб-приложений.
Что такое Redis?
Redis — это хранилище структур данных с открытым исходным кодом (лицензия BSD), используемое в качестве базы данных, кэша и посредника сообщений. Redis предоставляет структуры данных, такие как строки, хэши, списки, наборы, отсортированные наборы с запросами по диапазону, растровые изображения, гиперлоги, геопространственные индексы и потоки.
Для этой статьи я создам простую демо-версию. Она включает в себя класс Customer
. На уровне контроллера есть методы getAllCustomers()
, getCustomerById()
. Эти методы кэшируемые. Если отправлять запросы для этих методов, ожидание может занять до трех секунд, если у Redis в памяти нет связанных данных.
Сценарий примерно такой. Начнем.
Зависимости Maven
Прежде всего, нужно добавить соответствующие зависимости в файл pom.xml
.
pom.xml
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
Конфигурация Redis
Создадим конфигурационный файл для Redis
-конфигурации, как показано ниже, а также компоненты redisCacheTemplate
и CacheManager
.
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
@EnableCaching
public class RedisConfig {
@Autowired
private CacheManager cacheManager;
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Bean
public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Serializable> template = new RedisTemplate<>();
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
RedisCacheConfiguration redisCacheConfiguration = config
.serializeKeysWith(
RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
RedisCacheManager redisCacheManager = RedisCacheManager.builder(factory).cacheDefaults(redisCacheConfiguration)
.build();
return redisCacheManager;
}
}
Аннотации кэша Spring
Я воспользовался аннотациям кэша Spring. Объясню, что это такое.
@cacheable
— запускает заполнение кэша;@CacheEvict
— запускает удаление кэша;@CachePut
— обновляет кэш, не вмешиваясь в выполнение метода;@Caching
— перегруппирует несколько операций кэша, которые будут применены к методу;@CacheConfig
— использует некоторые общие настройки, связанные с кэшем, на уровне класса.
Уровень обслуживания
Я создал уровень обслуживания для клиента. Для кэширования использованы аннотации Spring. Когда вы получите всех клиентов, то получите все данные из базы данных, если у Redis нет связанных данных. Метод waitSomeSome()
написан для моделирования. При добавлении нового клиента Customer
или его обновлении, все связанные данные в Redis будут удалены.
@Service
@CacheConfig(cacheNames = "customerCache")
public class CustomerServiceImpl implements CustomerService {
@Autowired
private CustomerRepository customerRepository;
@Cacheable(cacheNames = "customers")
@Override
public List<Customer> getAll() {
waitSomeTime();
return this.customerRepository.findAll();
}
@CacheEvict(cacheNames = "customers", allEntries = true)
@Override
public Customer add(Customer customer) {
return this.customerRepository.save(customer);
}
@CacheEvict(cacheNames = "customers", allEntries = true)
@Override
public Customer update(Customer customer) {
Optional<Customer> optCustomer = this.customerRepository.findById(customer.getId());
if (!optCustomer.isPresent())
return null;
Customer repCustomer = optCustomer.get();
repCustomer.setName(customer.getName());
repCustomer.setContactName(customer.getContactName());
repCustomer.setAddress(customer.getAddress());
repCustomer.setCity(customer.getCity());
repCustomer.setPostalCode(customer.getPostalCode());
repCustomer.setCountry(customer.getCountry());
return this.customerRepository.save(repCustomer);
}
@Caching(evict = { @CacheEvict(cacheNames = "customer", key = "#id"),
@CacheEvict(cacheNames = "customers", allEntries = true) })
@Override
public void delete(long id) {
this.customerRepository.deleteById(id);
}
@Cacheable(cacheNames = "customer", key = "#id", unless = "#result == null")
@Override
public Customer getCustomerById(long id) {
waitSomeTime();
return this.customerRepository.findById(id).orElse(null);
}
private void waitSomeTime() {
System.out.println("Long Wait Begin");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Long Wait End");
}
Docker и Docker Compose
Для настройки приложения создадим файлы Dockerfile
и docker-compose.yml
. В качестве базы данных СУБД воспользуемся postgresql
. В файл docker-compose.yml добавим Redis с тэгом cache
. Docker compose — очень полезный инструмент для запуска сразу нескольких контейнеров.
Dockerfile
:
openjdk:8
ADD ./target/spring-boot-redis-cache-0.0.1-SNAPSHOT.jar /usr/src/spring-boot-redis-cache-0.0.1-SNAPSHOT.jar
WORKDIR usr/src
ENTRYPOINT ["java","-jar", "spring-boot-redis-cache-0.0.1-SNAPSHOT.jar"]
docker-compose.yml
:
version: '3'
services:
db:
image: "postgres"
ports:
- "5432:5432"
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ekoloji
cache:
image: "redis"
ports:
- "6379:6379"
environment:
- ALLOW_EMPTY_PASSWORD=yes
- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
app:
build: .
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://db/postgres
SPRING_DATASOURCE_USERNAME: postgres
SPRING_DATASOURCE_PASSWORD: ekoloji
SPRING_REDIS_HOST: cache
SPRING_REDIS_PORT: 6379
depends_on:
- db
- cache
Сборка и запуск
При создании и запуске этого приложения вам необходимо выполнить некоторые команды из командной строки, такие как mvn
и docker
. Сначала приложение упаковывается в jar
-формат. После этого создается файл docker-compose
. И, наконец, вам просто нужно up
-нуть Docker-файл.
Когда вы проследуете по этому пути, ваше приложение будет успешно запущено. Просто перейдите на http://localhost:8080 или http://localhost:8080/swagger-ui.html. По второй ссылке можно будет посмотреть эндпоинты проекта, а также протестировать их с помощью инструмента Swagger.
Создание Java jar:
$ mvn clean install -DskipTests
Создание и запуск Docker Compose:
$ docker-compose build --no-cache
$ docker-compose up --force-recreate
Демонстрация
Я подготовил демо-видео о том, как запустить и протестировать это приложение.
Заключение
Благодаря этому краткому руководству мы настроили приложение Spring Boot для взаимодействия с Redis и PostgreSQL через Docker.
Читайте также:
- Введение в потоки Redis
- Как сделать приложение-чат с Redis, WebSocket и Go
- redis-hawk: детализированное отслеживание и контроль развертывания Redis
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Erkan Güzeler: “Spring Boot + Redis + PostgreSQL Caching”