Cache Redis do Spring Boot

Spring Boot Redis Cache

Neste post, vamos configurar um exemplo de aplicativo Spring Boot e integrá-lo com o Cache do Redis. Embora o Redis seja 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. Faremos 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: Baixe o projeto e descompacte-o. Usamos 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 do Cache do Redis do Spring Boot

Embora já tenhamos concluído a configuração com a ferramenta, se você deseja 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 no maven central.

Definindo o Modelo

Para salvar um objeto no banco de dados Redis, definimos um objeto modelo Pessoa 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 do 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 em 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 pois queremos popular alguns dados de exemplo no banco de dados H2 embarcado.

Definindo o Repositório

Antes de mostrarmos como o Redis funciona, apenas vamos 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 o cache está diretamente associado a ele, a solicitação nem precisa 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 nomeado como ‘usuários’, identifica essa pessoa pela chave ‘userId’ e só 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 instruçã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 assim:

... : Getting user with ID 1.
... : Getting user with ID 1.
... : Getting user with ID 2.

Repare em algo? Fizemos quatro chamadas de API, mas apenas três registros de log estavam presentes. Isso ocorre porque o Usuário com ID 2 possui 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 retornados 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 dos objetos reais forem 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 pelo seu ID e é atualizada com os resultados.

Limpando o Cache

Se alguns dados precisarem ser excluídos do banco de dados real, não fará 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 excluímos as entradas do cache e não fizemos mais nada.

Executando a Aplicação de Cache do Spring Boot Redis

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 3 GB de dados em um sistema de 32 bits. Mais memória disponível pode resultar em uma maior taxa de acertos, mas isso tenderá a parar assim que muita memória for ocupada pelo Redis. Quando o tamanho do cache atinge o limite de memória, os dados antigos são removidos para dar lugar aos novos.

Resumo

Nesta lição, vimos o poder que o Cache do Redis nos proporciona com 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.

Baixar Projeto Spring Boot Redis Cache

Source:
https://www.digitalocean.com/community/tutorials/spring-boot-redis-cache