Skip to content

Redis Java Sample

kimhyungkook edited this page Feb 25, 2019 · 5 revisions

full code github

springboot 2 기준 / spring-redis

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
</dependency>

1. 캐쉬로 Redis 사용

첫번째로 spring 설정 yaml 파일 이다.

application.yaml

spring:
  redis:
    host: my-redis-master
    port: 6379
    password: secretpassword
  cache:
    redis:
      cache-null-values: false
      use-key-prefix: true
    type: redis        # spring.cache 를 redis 로 사용하도록 선언

bean 을 등록하는 파일은 아래처럼 따로 Config 파일을 생성하여 만드는게 좋다.

RedisConfig.java

@Configuration
@EnableCaching
public class RedisConfig {

    @Autowired
    private Environment environment;
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisConf = new RedisStandaloneConfiguration();
        redisConf.setHostName(environment.getProperty("spring.redis.host"));
        redisConf.setPort(Integer.parseInt(environment.getProperty("spring.redis.port")));
        redisConf.setPassword(RedisPassword.of(environment.getProperty("spring.redis.password")));

        JedisConnectionFactory connectionFactory = new JedisConnectionFactory(redisConf);
        return connectionFactory;
    }

    @Bean
    public RedisCacheConfiguration cacheConfiguration() {
        RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))  // 케쉬데이터 저장 시간
                .disableCachingNullValues();        // 케쉬는 null 을 허용 안함
        return cacheConfig;
    }
    @Bean
    public RedisCacheManager cacheManager() {
        RedisCacheManager rcm = RedisCacheManager.builder(redisConnectionFactory())
                .cacheDefaults(cacheConfiguration())
                .transactionAware()
                .build();
        return rcm;
    }
}

설명
@EnableCaching 를 선언하여 Spring Data cache 를 사용하도록 선언한다.

# 실제 사용법

Spring 의 cache 관련 Annotation을 사용하여 쉽게 구현이 가능하다.

Service.java

    /**
     * @Cacheable 은 key 에 해당하는 cache 값이 있으면 cache 를 조회하고,
     * key 에 해당하는 cache 값이 없으면 메서드 안쪽의 내용을 실행하여 결과값을 key 에 저장하는 역할을 한다.
     */
    @Cacheable(value = "app", key = "#userName")
    public Customer getName(String userName){
        LOGGER.info("find name from jdbc {}", userName);
        return customerRepository.findByUserName(userName);
    }

    /**
     * @CachePut cache 에 저장을 한다.
     */
    @CachePut(value = "app", key = "#customer.userName")
    @Transactional
    public Customer saveCache(Customer customer) {
        return customerRepository.save(customer);
    }

    /**
     * @CacheEvict 캐쉬를 지운다.
     * 여러건을 한번에 지우고 싶을때는 아래와 같이 사용한다.
     */
    @Caching(evict = {
            @CacheEvict(value = "app"),
            @CacheEvict(value = "app", key="#customer.userName")
    })
    public String deleteCacheList(Customer customer) {
        return "";
    }

2. 데이터 저장소로 Redis 사용

캐쉬는 휘발성 데이터이고, 저장용도로 사용하기 위해서는 redisTemplate을 사용하여 직접 key 에 입력을 시킨다.

RedisConfig.java

    /**
     * redisTemplate 을 사용하에 redis 데이터를 직접 컨트롤을 할 수가 있다.
     * redis pub/sub 을 사용할적에 메세지를 보내기 위한 Template 으로 쓰인다.
     */
    @Bean
    public RedisTemplate redisTemplate() {
        RedisTemplate redisTemplate = new RedisTemplate<>();

        // Serializer 를 등록하지 않으면 Default Serializer로 JdkSerializationRedisSerializer 를 사용하며
        // 이때 모든 값은 UniCode로 되어버린다
        // 출처: https://yonguri.tistory.com/entry/스프링부트-SpringBoot-개발환경-구성-3-Redis-설정 [Yorath's 블로그]
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory());

        return redisTemplate;
    }

# 실제 사용법

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 레디스를 사용하는 방법중에 데이터 저장 공간으로 활용을 할 수가 있다.
     * 이렇게 생성된 데이터는 삭제를 하기 전까지는 데이터가 남아있는다.
     */
    public Customer saveNameByRedis(String userName){
        Customer c = new Customer();
        c.setUserName(userName);
        c.setFirstName(userName);
        String key = "app2::"+userName;
        redisTemplate.opsForValue().set(key, c);
        return c;
    }
    /**
     * redisTemplate.opsForValue() 를 사용하여 key 에 대한 값을 조회할 수 있다.
     * 조회는 list, set, hash, value 등이 있다.
     */
    public Customer getNameByRedis(String userName){

        String key = "app2::"+userName;
        Customer value = (Customer)redisTemplate.opsForValue().get(key);

        return value;
    }

    /**
     * redisTemplate.delete 를 사용하여 데이터를 지울수 있다
     * Set<String> keys = redisTemplate.keys(key); 를 통하여 여러 키를 조회하여 한번에 지울수도 있다.
     */
    public String deketeKeyByRedis(String userName){
        String key = "app2::"+userName;
        redisTemplate.delete(key);

        // delete multi keys
//        String key = "app2::*"+userName+"*";
//        Set<String> keys = redisTemplate.keys(key);
//        redisTemplate.delete(keys);

        return "ok";
    }


    /**
     * 여러개의 key 를 조회하여 list 로 만들어 데이터를 조회하는 예제
     */
    public List<Customer> getListByRedis(String userName){

        // like 조회
        String key = "app2::*"+userName+"*";
        Set<String> keys = redisTemplate.keys(key);
        List<Customer> value = (List<Customer>)redisTemplate.opsForValue().multiGet(keys);

        return value;
    }

3. PUB/SUB 으로 Redis 사용

redis 를 메세지 pub/sub 으로 사용하기 위해서는 MessageListener 와 publisher 를 등록해야한다.

RedisConfig.java

    /**
     * 메시지 큐를 위한 Bean을 추가
     */
    @Bean
    MessageListenerAdapter messageListener() {
        return new MessageListenerAdapter(new RedisMessageSubscriber());
    }

    /**
     * 채널의 메세지를 주고받을수있는 컨테이너 정의
     * 컨테이너는 redis 로 부터 메세지를 받고, 구독자에게 메세지를 보내는 역할
     */
    @Bean
    RedisMessageListenerContainer redisContainer() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisConnectionFactory());
        container.addMessageListener(messageListener(), topic());
        return container;
    }

    /**
     * 메세지를 게시하는 bean
     * RedisMessagePublisher 를 Autowired 하여 사용할수 있도록 선
     */
    @Bean
    RedisMessagePublisher redisPublisher() {
        return new RedisMessagePublisher(redisTemplate(), topic());
    }


    /**
     * 메세지를 주고 받을수있는 공간인 Channel 등록
     */
    @Bean
    ChannelTopic topic() {
        return new ChannelTopic("messageQueue");
    }

RedisMessagePublisher.java

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ChannelTopic topic;

    public RedisMessagePublisher(RedisTemplate redisTemplate, ChannelTopic topic) {
        this.redisTemplate = redisTemplate;
        this.topic = topic;
    }

    /**
     * convertAndSend() 메서드는 목적지( 채널 )에 메시지를 전달하는 역할을 합니다.
     * pub sub 모델의 특징 상 채널을 구독하고 있는 모든 구독자에게 메시지가 전달됩니다.
     */
    public void publish(String message) {
        redisTemplate.convertAndSend(topic.getTopic(), message);
    }

RedisMessageSubscriber.java

    public static List<String> messageList = new ArrayList<String>();

    /**
     * pattern 을 통해 채널 매칭을 위한 패턴을 정의할수 있음
     * 패턴을 정의하면 여러 채널로 부터 구독이 가능함
     */
    @Override
    public void onMessage(Message message, byte[] pattern) {
        messageList.add(message.toString());
        System.out.println("Message received: " + message.toString());

    }

# 실제 사용법

@RestController
@RequestMapping("/pubsub")
public class PubSubTestController {

    @Autowired
    RedisMessagePublisher redisMessagePublisher;

    @RequestMapping(value = "/send", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
    public void sendMessage(@RequestParam("message") String message ) throws Exception {
        redisMessagePublisher.publish(message);
    }
}

메세지를 publish 하게 되면 구독하고있는 모든 Subscriber 에게 메세지가 전달된다.
Subscriber가 메시지 받는 것을 보장하지는 않는다.

## http 로 메세지 전달받는지 확인한다.  
http http://localhost:8280/pubsub/send\?message\=hello  

콘솔창에
Message received: hello 라고 뜬다.
## redis-cli에서 messageQueue 채널을 구독하여, 메시지가 오는지 확인   
kubectl exec -it my-redis-master-0 -- redis-cli -a secretpassword
> pubsub channels            :  채널 목록을 확인  
messageQueue
> subscribe messageQueue  : messageQueue 채널을 구독  
hello