Cache Redis do Spring Boot
Neste post, vamos configurar um aplicativo de amostra Spring Boot e integrá-lo com o Cache Redis. Enquanto o Redis é um armazenamento de estrutura de dados em memória de código aberto, usado como banco de dados, cache e corretor de mensagens, esta lição demonstrará apenas a integração de cache. Vamos fazer uso da ferramenta Spring Initializr para configurar rapidamente o projeto.
Configuração do Projeto Spring Boot Redis
Vamos fazer uso da ferramenta Spring Initializr para configurar rapidamente o projeto. Usaremos 3 dependências conforme mostrado abaixo: Faça o download do projeto e descompacte-o. Utilizamos a dependência do banco de dados H2, pois estaremos usando um banco de dados incorporado que perde todos os dados assim que o aplicativo é parado.
Dependências do Maven para Cache Redis no Spring Boot
Embora já tenhamos concluído a configuração com a ferramenta, se você quiser configurá-la manualmente, usamos o sistema de construção Maven para este projeto e aqui estão as dependências que utilizamos:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- for JPA support -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- for embedded database support -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Certifique-se de usar a versão estável do Spring Boot do repositório central do Maven.
Definindo o Modelo
Para salvar um objeto no banco de dados Redis, definimos um objeto modelo Person com campos básicos:
package com.journaldev.rediscachedemo;
import javax.persistence.*;
import java.io.Serializable;
@Entity
public class User implements Serializable {
private static final long serialVersionUID = 7156526077883281623L;
@Id
@SequenceGenerator(name = "SEQ_GEN", sequenceName = "SEQ_USER", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_GEN")
private Long id;
private String name;
private long followers;
public User() {
}
public User(String name, long followers) {
this.name = name;
this.followers = followers;
}
// getters e setters padrão
@Override
public String toString() {
return String.format("User{id=%d, name='%s', followers=%d}", id, name, followers);
}
}
É um POJO padrão com getters e setters.
Configurando o Cache Redis
Com o Spring Boot e a dependência necessária já em funcionamento com o Maven, podemos configurar uma instância local do Redis com apenas três linhas no nosso arquivo application.properties como:
# Configuração do Redis
spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379
Também, use a anotação @EnableCaching
na classe principal do Spring Boot:
package com.journaldev.rediscachedemo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class Application implements CommandLineRunner {
private final Logger LOG = LoggerFactory.getLogger(getClass());
private final UserRepository userRepository;
@Autowired
public Application(UserRepository userRepository) {
this.userRepository = userRepository;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... strings) {
// Populando o banco de dados incorporado aqui
LOG.info("Saving users. Current user count is {}.", userRepository.count());
User shubham = new User("Shubham", 2000);
User pankaj = new User("Pankaj", 29000);
User lewis = new User("Lewis", 550);
userRepository.save(shubham);
userRepository.save(pankaj);
userRepository.save(lewis);
LOG.info("Done saving users. Data: {}.", userRepository.findAll());
}
}
Adicionamos um CommandLineRunner porque queremos popular alguns dados de exemplo no banco de dados H2 embutido.
Definindo o Repositório
Antes de mostrarmos como o Redis funciona, vamos apenas definir um Repositório para funcionalidades relacionadas ao JPA:
package com.journaldev.rediscachedemo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository { }
Atualmente, ele não possui chamadas de método, pois não precisamos de nenhuma.
Definindo o Controlador
Os controladores são o lugar onde o cache do Redis é chamado para ação. Na verdade, este é o melhor lugar para fazer isso, porque como um cache está diretamente associado a ele, a solicitação nem precisará entrar no código de serviço para aguardar os resultados em cache. Aqui está o esqueleto do controlador:
package com.journaldev.rediscachedemo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;
@RestController
public class UserController {
private final Logger LOG = LoggerFactory.getLogger(getClass());
private final UserRepository userRepository;
@Autowired
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
...
}
Agora, para colocar algo no cache, usamos a anotação @Cacheable
:
@Cacheable(value = "users", key = "#userId", unless = "#result.followers < 12000")
@RequestMapping(value = "/{userId}", method = RequestMethod.GET)
public User getUser(@PathVariable String userId) {
LOG.info("Getting user with ID {}.", userId);
return userRepository.findOne(Long.valueOf(userId));
}
No mapeamento acima, o método getUser
colocará uma pessoa em um cache chamado ‘usuários’, identifica essa pessoa pela chave ‘userId’ e apenas armazenará um usuário com mais de 12000 seguidores. Isso garante que o cache seja populado com usuários que são muito populares e frequentemente consultados. Além disso, adicionamos intencionalmente uma declaração de log na chamada da API. Vamos fazer algumas chamadas de API pelo Postman neste momento. Estas são as chamadas que fizemos:
localhost:8090/1
localhost:8090/1
localhost:8090/2
localhost:8090/2
Se observarmos os logs, serão eles:
... : Getting user with ID 1.
... : Getting user with ID 1.
... : Getting user with ID 2.
Percebeu algo? Fizemos quatro chamadas de API, mas apenas três declarações de log estavam presentes. Isso ocorre porque o Usuário com ID 2 tem 29000 seguidores e, portanto, seus dados foram armazenados em cache. Isso significa que, quando uma chamada de API foi feita para ele, os dados foram recuperados do cache e nenhuma chamada de banco de dados foi feita para isso!
Atualizando Cache
Os valores do cache também devem ser atualizados sempre que os valores reais de seus objetos são atualizados. Isso pode ser feito usando a anotação @CachePut:
@CachePut(value = "users", key = "#user.id")
@PutMapping("/update")
public User updatePersonByID(@RequestBody User user) {
userRepository.save(user);
return user;
}
Com isso, uma pessoa é novamente identificada por seu ID e é atualizada com os resultados.
Limpando o Cache
Se alguns dados precisam ser excluídos do banco de dados real, não faz sentido mantê-los em cache. Podemos limpar os dados do cache usando a anotação @CacheEvict
:
@CacheEvict(value = "users", allEntries=true)
@DeleteMapping("/{id}")
public void deleteUserByID(@PathVariable Long id) {
LOG.info("deleting person with id {}", id);
userRepository.delete(id);
}
No último mapeamento, apenas removemos as entradas do cache e não fizemos mais nada.
Executando a Aplicação de Cache Redis do Spring Boot
Podemos executar este aplicativo simplesmente usando um único comando:
mvn spring-boot:run
Limites de Cache do Redis
Embora o Redis seja muito rápido, ainda não tem limites para armazenar qualquer quantidade de dados em um sistema de 64 bits. Ele só pode armazenar 3GB de dados em um sistema de 32 bits. Mais memória disponível pode resultar em uma taxa de acertos maior, mas isso tenderá a parar uma vez que muito espaço de memória seja ocupado pelo Redis. Quando o tamanho do cache atinge o limite de memória, dados antigos são removidos para dar lugar a novos.
Resumo
Nesta lição, vimos o poder que o Redis Cache nos proporciona com uma interação rápida de dados e como podemos integrá-lo ao Spring Boot com uma configuração mínima e ainda poderosa. Sinta-se à vontade para deixar comentários abaixo.
Source:
https://www.digitalocean.com/community/tutorials/spring-boot-redis-cache