용로그
article thumbnail

저번 포스팅에서는 레디스라는 데이터베이스 자체에 대해서 자세히 알아보았다. 이번 포스팅에서는 스프링 부트에서 레디스를 사용하는 법을 알아보자.

 

Spring Boot에서 레디스 설정하기


스프링 부트에서 레디스를 사용하려면 build.gradle 파일에 레디스 의존성을 추가해줘야 한다.

implementation 'org.springframework.boot:spring-boot-starter-data-redis'

그리고 사용할 레디스의 호스트와 포트를 지정해준다. application.yml 파일에 지정하며, 로컬에서 레디스를 사용한다면 localhost, 다른 서버나 도커 등을 사용한다면 그에 맞는 호스트로 설정해준다. default port는 6379이다.

spring:
  redis:
    host: localhost
    port: 6379

마지막으로 애플리케이션에서 레디스와 연동하기 위해 별도의 값을 세팅하고 빈에 등록해준다. 자바의 Redis Client 라이브러리는 JedisLettuce가 있는데, Lettuce가 성능이 더 좋기 때문에 Lettuce로 RedisConnectionFactory를 통해 Redis와 연결한다. 

Spring boot 2.0부터 RedisTemplate와 StringTemplate를 자동생성 되어서 따로 빈에 등록안해도 된다고 한다.
RedisTemplate에는 serializer를 설정해주는데 설정하지 않는 다면 직접 redis-cli로 데이터 확인이 어렵다.
@Configuration
public class RedisConfig {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory(host, port);
    }
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());

        // 일반적인 key:value의 경우 시리얼라이저
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());

        // Hash를 사용할 경우 시리얼라이저
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());

        // 모든 경우
        redisTemplate.setDefaultSerializer(new StringRedisSerializer());

        return redisTemplate;
    }
}

 

레디스를 사용하는 방법은 크게 2가지로 나뉜다.

 

RedisRepository 사용하기


Repository로 사용하면 Entity를 만들어서 쉽게 사용할 수 있다.

RefreshToken

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
@RedisHash(value = "refresh_token")
public class RefreshToken {

    @Id
    private String authId;

    @Indexed
    private String token;

    private String role;

    @TimeToLive
    private long ttl;

    public RefreshToken update(String token, long ttl) {
        this.token = token;
        this.ttl = ttl;
        return this;
    }

}
  • @Id - (key) 값이 되며, refresh_token:{id} 위치에 auto-increment 된다.
  • @RedisHash - 설정한 값을 Redis의 key 값 prefix로 사용한다.
  • @Indexed - 값으로 검색을 할 시에 추가한다.
  • @TimeToLive - 만료시간을 설정(초(second) 단위)

 

RefreshTokenRepository

public interface RefreshTokenRepository extends CrudRepository<RefreshToken, String> {

    Optional<RefreshToken> findByToken(String token);

    Optional<RefreshToken> findByAuthId(String authId);
}

JpaRepository를 사용하는 것 처럼, CrudRepository 인터페이스를 상속받는다. @Id 또는 @Indexed 어노테이션을 적용한 프로퍼티들만 CrudRepository가 제공하는 findBy~ 구문을 사용할 수 있다.

 

레디스 템플릿 사용하기


RedisUtil

@Service
public class RedisUtils {

    private final RedisTemplate<String, Object> redisTemplate;

    public RedisUtils(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public void setData(String key, String value,Long expiredTime){
        redisTemplate.opsForValue().set(key, value, expiredTime, TimeUnit.MILLISECONDS);
    }

    public String getData(String key){
        return (String) redisTemplate.opsForValue().get(key);
    }

    public void deleteData(String key){
        redisTemplate.delete(key);
    }
}

레디스 템플릿은 사용하는 자료구조마다 제공하는 메서드가 다르기 때문에 객체를 만들어서 레디스의 자료구조 타입에 맞는 메소드를 사용하면 된다.

 

메서드 명 레디스 타입
opsForValue String
opsForList List
opsForSet Set
opsForZSet Sorted Set
opsForHash Hash

 

데이터를 저장할 때 만료 시간 지정할 시에는 해당 시간의 단위까지 지정해주면 된다. 위의 코드에서는 밀리 초(TimeUnit.MILLISECONDS)로 적용되어 있다.

 

레디스 캐시 사용하기


레디스는 데이터베이스로도 사용되고, Message Broker로도 사용되지만 Cache Manager의 용도로도 많이 사용된다. 레디스가 제공하는 캐싱 기능을 사용하려면 캐싱 관련 어노테이션부터 알아야 한다.

 

@EnableCaching


  • Spring Boot에게 캐싱기능이 필요하다고 전달
  • Spring Boot Starter class에 적용

 

@Cacheable


  • 리턴 값을 기준으로 데이터가 캐시에 있으면 그대로 반환, 없으면 저장 후 반환한다.
  • 보통 조회와 같은 API에 많이 사용됨
Element Description Type
cacheName 캐시 이름 (설정 메서드 리턴값이 저장되는) String[]
value cacheName의 별칭 String[]
key 동적인 키 값을 사용하는 SpEL 표현식
동일한 cache name을 사용하지만 구분될 필요가 있을 경우 사용되는 값
String
condition SpEL 표현식이 참일 경우에만 캐싱 적용
- or, and 등 조건식, 논리연산 가능
String
unless 캐싱을 막기 위해 사용되는 SpEL 표현식
condition과 반대로 참일 경우에만 캐싱이 적용되지 않음
String
cacheManager 사용 할 CacheManager 지정
(EHCacheCacheManager, RedisCacheManager 등)
String
sync
여러 스레드가 동일한 키에 대한 값을 로드하려고 할 경우, 기본 메서드의 호출을 동기화
즉, 캐시 구현체가 Thread safe 하지 않는 경우, 캐시에 동기화를 걸 수 있는 속성
boolean

 

@CachePut


  • 캐시에 데이터를 저장할 때만 사용한다.
  • @Cacheable과 다르게 캐시에 저장된 데이터를 사용하지 않는다.
  • 보통 수정과 같은 API에 많이 사용됨
Element Description Type
cacheName 입력할 캐시 이름 String[]
value cacheNamed의 별칭 String[]
key 동적인 키 값을 사용하는 SpEL 표현식
동일한 cache name을 사용하지만 구분될 필요가 있을 경우 사용되는 값
String
cacheManager 사용 할 CacheManager 지정
(EHCacheCacheManager, RedisCacheManager 등)
String
condition SpEL 표현식이 참일 경우에만 캐싱 적용
- or, and 등 조건식, 논리연산 가능
String
unless 캐싱을 막기 위해 사용되는 SpEL 표현식
condition과 반대로 참일 경우에만 캐싱이 적용되지 않음
String

 

@CacheEvict


  • 메서드가 호출될 때 캐시에 있는 데이터가 삭제된다.
  • 보통 삭제와 같은 API에 많이 사용됨
Element Description Type
cacheName 제거할 캐시 이름 String[]
value cacheName의 별칭 String[]
key 동적인 키 값을 사용하는 SpEL 표현식
동일한 cache name을 사용하지만 구분될 필요가 있을 경우 사용되는 값
String
allEntries 캐시 내의 모든 리소스를 삭제할지의 여부 boolean
condition SpEL 표현식이 참일 경우에만 삭제 진행
- or, and 등 조건식, 논리연산 가능
String
cacheManager 사용 할 CacheManager 지정
(EHCacheCacheManager, RedisCacheManager 등)
String
beforeInvocation true - 메서드 수행 이전 캐시 리소스 삭제
false - 메서드 수행 후 캐시 리소스 삭제
boolean

 

Spring Boot에 캐싱 사용 알려주기


@SpringBootApplication
@EnableCaching
public class SpringBootRedisSimpleStarterApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootRedisSimpleStarterApplication.class, args);
    }
}

 

레디스 캐시 관련 Config


spring:
  cache:
    type: redis
  • 스프링에서 캐시 사용을 레디스로 설정하겠다는 뜻이다.
@Configuration
@EnableCaching
public class RedisCacheConfig {

    @Bean
    public CacheManager rcm(RedisConnectionFactory cf) {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                .entryTtl(Duration.ofMinutes(3L));

        return RedisCacheManager
                .RedisCacheManagerBuilder
                .fromConnectionFactory(cf)
                .cacheDefaults(redisCacheConfiguration)
                .build();
    }
}
  • Data를 가져오고 보낼 때, 우리가 만든 도메인 모델을 Serialize 해 주기 위해 설정이 필요하다.
  • 여기서 생성한 rcm 메서드를 앞으로 사용 할 레디스 어노테이션에 명시 해 주어야 한다.
  • entryTtl 옵션으로 캐시 유효 시간을 3분으로 제한한다.

API에 캐싱 적용하기 - Example


@RequestMapping("/log")
@RestController
@RequiredArgsConstructor
public class LogController {

    private final LogService logService;

    @GetMapping
    public ResponseEntity<List<LogResponse>> getAll() {
        List<LogResponse> logs = logService.searchAll();
        return ResponseEntity.ok(logs);
    }

    @DeleteMapping
    public void deleteAll() {
        logService.removeAll();
    }
}
@Cacheable(cacheNames = "searchAll", key = "#root.target + #root.methodName", sync = true, cacheManager = "rcm")
public List<LogResponse> searchAll() {
    return logFacade.findAllOrderByDateAtDesc()
            .stream()
            .map(LogResponse::new)
            .collect(Collectors.toList());
}

@CacheEvict(cacheNames = "searchAll", allEntries = true, beforeInvocation = true, cacheManager = "rcm")
@Transactional
public void removeAll() {
    logFacade.removeAll();
}

 

public class Ref {	
    final String Spring boot Redis 사용하기 = "https://westmino.tistory.com/157";
    final String [Spring Boot] Redis 사용하기 = "https://velog.io/@yoojkim/Spring-Boot-Redis-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0";
    final String Jedis 보다 Lettuce 를 쓰자 = "https://jojoldu.tistory.com/418";
    final String Spring Cache, 제대로 사용하기 = "https://gngsn.tistory.com/157";
    final String Spring boot에서 Redis Cache 사용하기 = "https://deveric.tistory.com/98";
    final String SpringBoot에서 Redis 캐시를 사용하기 = "https://www.wool-dev.com/backend-engineering/spring/springboot-redis-cache#%EC%82%AC%EC%9A%A9-%ED%95%A0-redis-%EA%B0%84%EB%8B%A8-%EC%84%A4%EB%AA%85";
    final String [JAVA Spring Boot] Rest API + 레디스 캐시 (Redis Cache) 적용 및 샘플 예제 = "https://kim-oriental.tistory.com/28";
}
profile

용로그

@용로그

벨덩보단 용덩 github.com/wonyongChoi05