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
Clone this wiki locally