본문 바로가기
Web/Spring

Spring boot에서 Redis Cache 사용하기

by EricJeong 2020. 5. 4.

모든 소스코드는 아래 github에서 더 편하게 보실 수 있습니다.

https://github.com/yyy9942/redis-cache-exam

 

yyy9942/redis-cache-exam

Contribute to yyy9942/redis-cache-exam development by creating an account on GitHub.

github.com

 

 

설정 시작하기

 

pom.xml에 spring-boot-starter-web, spring-boot-starter-data-redis를 추가해주세요.

<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>

 

 

application.properties에 다음 내용을 설정해주세요.

spring.redis.host=localhost
spring.redis.port=6379

spring.redis.host 옵션은 redis서버의 url 또는 ip를 설정해주시면 되고 spring.redis.port는 해당 서버의 포트를 적어주시면 됩니다.  여기서 설정한 내용은 캐시 설정을 할 때 직접 불러와서 세팅을 진행하게 됩니다.

 

 

 

@SpringBootApplication
@EnableCaching  
public class RedisCacheApplication {

	public static void main(String[] args) {
		SpringApplication.run(RedisCacheApplication.class, args);
	}

}

메인 어플리케이션 클래스에 @EnableCaching 을 선언해주세요.

해당 어노테이션을 선언하면 스프링 부트에서는 @Cacheable과 같은 캐싱 어노테이션의 사용을 인식하게 됩니다.

 

 

@Configuration
public class RedisConfig {
  
  @Value("${spring.redis.port}")
  public int port;
  
  @Value("${spring.redis.host}")
  public String host;
  
  @Autowired
  public ObjectMapper objectMapper;
  
  @Bean
  public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setKeySerializer(new StringRedisSerializer());
    redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    redisTemplate.setConnectionFactory(connectionFactory);
    return redisTemplate;
  }

  @Bean
  public RedisConnectionFactory redisConnectionFactory() {
    RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
    redisStandaloneConfiguration.setHostName(host);
    redisStandaloneConfiguration.setPort(port);
    LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration);
    return connectionFactory;
  }
}

 Redis와의 연결을 위한 설정을 위와 같이 해줍니다. RedisConnectionFactory에 사용한 LettuceConnectionFactory는 Spring boot 1.x버전대에서는 작동이 되지 않는듯합니다. 하위 버전에서는 JedisConnectionFactory를 사용해주세요.

 

@Configuration
public class CacheConfig {
  
  @Autowired
  RedisConnectionFactory redisConnectionFactory;
  
  @Autowired
  ObjectMapper objectMapper;
  
  @Autowired
  RedisConnectionFactory connectionFactory;
  
  
  @Bean
  public CacheManager redisCacheManager() {
    RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
      .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
      .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
    
    RedisCacheManager redisCacheManager = RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(connectionFactory).cacheDefaults(redisCacheConfiguration).build();
    return redisCacheManager;
  }
  
}

 Spring CacheManager타입의 RedisCacheManager를 빈으로 등록해주면 Spring에서는 캐싱을 할 때 로컬 캐시에 저장하지 않고 redis에 저장하게 됩니다. 위와 같이 redisCacheManager를 등록해주세요. 여기까지 끝났다면 스프링에서 레디스 캐시를 사용하기 위한 준비는 끝났습니다.

 

 

 

예제를 만들어 확인해보기

 

캐싱을 정확히 사용하는지 간단한 예제를 만들어 테스트 해보겠습니다. 제작할 예제는 게시판 도메인을 제작하고 이를 조회하는 로직을 만들어 캐싱을 하였을 때 DB를 실제로 조회하지 않고 캐시를 조회하는지 확인하는 예제입니다.

 

@Getter @AllArgsConstructor @NoArgsConstructor
public class Board {
  private Long id;
  private String title;
  private String contents;
}

저장할 도메인 Board를 선언합니다. getter, constructor는 lombok라이브러리로 대체하였습니다.

 

 

@Repository
public class BoardRepository {

  // DB 조회 횟수
  private static int dbCount = 0;

  public List<Board> createBySize(String size) {
    // DB 조회를 했다고 가정하여 카운트를 올린다.
    dbCount++;
    ArrayList<Board> boards = new ArrayList<Board>();
    int count = Integer.parseInt(size);


    for (int i = 0; i < count; i++) {
      boards.add(new Board(i + 0L, i + "번째 게시물", i + "번째 내용"));
    }

    return boards;
  }

  public static int getDbCount() {
    return dbCount;
  }

}

 

해당 도메인을 DB에 저장할 Repository를 제작합니다. 단 실제로 DB에 넣기보다는 DB 조회를 했다는 가정을 하기 위해 변수 dbCount를 선언하고, db조회를 하는 연산을 실행할 때마다 이를 1씩 증가시켜주겠습니다.

 

 

@Service
public class BoardService {
  
  @Autowired
  BoardRepository repository;
  
  @Cacheable(key = "#size", value = "getBoards")
  public List<Board> getBoards(String size) {
    return repository.createBySize(size);
  }
  
  public static int getDbCount() {
    return BoardRepository.getDbCount();
  }
}

 해당 도메인의 Service를 위와 같이 선언하고, @Cacheable 어노테이션을 선언해줍니다. @Cacheable은 value와 key를 같이 사용하여 캐시의 키값으로 사용합니다.

 

 

@RestController
public class BoardController {
  
  @Autowired
  BoardService service;
  
  
  @GetMapping()
  public List<Board> boards(String size) {
    List<Board> boards = service.getBoards(size);
    return boards;
  }
  
  @GetMapping("count")
  public int count() {
    return BoardService.getDbCount();
  }

}

실제로 게시판을 조회할 url과 db 카운트 횟수를 조회할 url을 선언하였습니다. 어플리케이션을 실행시켜 직접 테스트해보겠습니다.

 

 

 

dbCount를 우선 조회해보겠습니다.

아무런 게시물을 조회하지 않았기 때문에 dbCount는 0인 상태입니다. 이 상태로 게시글을 조회하는 url을 던져보겠습니다.

 

 

처음으로 조회하는 게시물은 dbCount가 올라갑니다. 이후 같은 내용을 계속 조회해보아도 count는 올라가지 않고 그대로입니다.

 

 

새로운 파라미터를 주고 조회하면 dbCount가 올라갑니다.

 

redis를 확인해 보면 해당 내용이 캐싱된 걸 확인할 수 있습니다.

 

 

Reference

https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/#reference

 

Spring Data Redis

Some commands (such as SINTER and SUNION) can only be processed on the server side when all involved keys map to the same slot. Otherwise, computation has to be done on client side. Therefore, it is useful to pin keyspaces to a single slot, which lets make

docs.spring.io

 

댓글