From afcca18ba0516d3e247833ba19db83e793d5ab2d Mon Sep 17 00:00:00 2001 From: crusader Date: Wed, 27 Sep 2017 15:58:21 +0900 Subject: [PATCH] Redis --- docker/conf/cache.properties | 3 + docker/conf/redis.properties | 4 + pom.xml | 27 +++++ .../commons/model/PublishMessage.java | 71 ++++++++++++ .../commons/service/MessagePublisher.java | 9 ++ .../service/NoAuthProbeService.java | 6 ++ .../redis/service/RedisMessagePublisher.java | 102 ++++++++++++++++++ .../com/loafle/overflow/spring/AppConfig.java | 43 +++++--- .../overflow/spring/CacheConfiguration.java | 26 +++++ .../overflow/spring/RedisConfiguration.java | 56 ++++++++++ src/main/resources/local/cache.properties | 3 + src/main/resources/local/redis.properties | 4 + .../loafle/overflow/spring/AppConfigTest.java | 52 ++++++--- src/test/resources/cache.properties | 3 + src/test/resources/redis.properties | 4 + 15 files changed, 386 insertions(+), 27 deletions(-) create mode 100644 docker/conf/cache.properties create mode 100644 docker/conf/redis.properties create mode 100644 src/main/java/com/loafle/overflow/commons/model/PublishMessage.java create mode 100644 src/main/java/com/loafle/overflow/commons/service/MessagePublisher.java create mode 100644 src/main/java/com/loafle/overflow/redis/service/RedisMessagePublisher.java create mode 100644 src/main/java/com/loafle/overflow/spring/CacheConfiguration.java create mode 100644 src/main/java/com/loafle/overflow/spring/RedisConfiguration.java create mode 100644 src/main/resources/local/cache.properties create mode 100644 src/main/resources/local/redis.properties create mode 100644 src/test/resources/cache.properties create mode 100644 src/test/resources/redis.properties diff --git a/docker/conf/cache.properties b/docker/conf/cache.properties new file mode 100644 index 0000000..fda34c0 --- /dev/null +++ b/docker/conf/cache.properties @@ -0,0 +1,3 @@ +# Caffeine +cache.cache-names:memberListByDomain,memberListByProbeKey +cache.caffeine.spec: initialCapacity=100,maximumSize=500,expireAfterAccess=5m,recordStats \ No newline at end of file diff --git a/docker/conf/redis.properties b/docker/conf/redis.properties new file mode 100644 index 0000000..bebb8a1 --- /dev/null +++ b/docker/conf/redis.properties @@ -0,0 +1,4 @@ +# Redis +redis.host=192.168.1.50 +redis.port=6379 +redis.channels=/web,/probe,/auth \ No newline at end of file diff --git a/pom.xml b/pom.xml index f3c8ce7..a87c19c 100644 --- a/pom.xml +++ b/pom.xml @@ -18,9 +18,12 @@ 1.2.0 + 2.9.0 + 2.5.6 3.2.0 4.3.9.RELEASE 1.11.4.RELEASE + 1.8.7.RELEASE 4.2.3.RELEASE 5.2.10.Final 1.4.7 @@ -59,6 +62,14 @@ ${spring.data.jpa.version} + + + org.springframework.data + spring-data-redis + ${spring.data.redis.version} + + + org.springframework @@ -124,6 +135,22 @@ 1.5 + + + redis.clients + jedis + ${jedis.version} + + + + + com.github.ben-manes.caffeine + caffeine + ${caffeine.version} + + + + com.loafle overflow_api_server diff --git a/src/main/java/com/loafle/overflow/commons/model/PublishMessage.java b/src/main/java/com/loafle/overflow/commons/model/PublishMessage.java new file mode 100644 index 0000000..1f7d06c --- /dev/null +++ b/src/main/java/com/loafle/overflow/commons/model/PublishMessage.java @@ -0,0 +1,71 @@ +package com.loafle.overflow.commons.model; + +import java.util.ArrayList; +import java.util.List; + +public class PublishMessage { + private List targets; + private PublishMessageBody message; + + public void setTargets(List targets) { + this.targets = targets; + } + + public void addTarget(String target) { + if (null == targets) { + targets = new ArrayList<>(); + } + targets.add(target); + } + + public List getTargets() { + return targets; + } + + public void setMessage(PublishMessageBody message) { + this.message = message; + } + + public PublishMessageBody getMessage() { + return message; + } + + public static class PublishMessageBody { + private String method; + private List params; + + public PublishMessageBody() { + + } + public PublishMessageBody(String method) { + this.method = method; + } + public PublishMessageBody(String method, List params) { + this(method); + this.params = params; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public List getParams() { + return params; + } + + public void setParams(List params) { + this.params = params; + } + + public void addParams(String param) { + if (null == this.params) { + this.params = new ArrayList<>(); + } + this.params.add(param); + } + } +} diff --git a/src/main/java/com/loafle/overflow/commons/service/MessagePublisher.java b/src/main/java/com/loafle/overflow/commons/service/MessagePublisher.java new file mode 100644 index 0000000..f5200e7 --- /dev/null +++ b/src/main/java/com/loafle/overflow/commons/service/MessagePublisher.java @@ -0,0 +1,9 @@ +package com.loafle.overflow.commons.service; + +import com.loafle.overflow.module.domain.model.Domain; + +public interface MessagePublisher { + void publishToMember(final String channel, final String memberID, final String method, final Object... params); + void publishToDomain(final String channel, final Domain domain, final String method, final Object... params); + void publishToDomainByProbeKey(final String channel, final String probeKey, final String method, final Object... params); +} diff --git a/src/main/java/com/loafle/overflow/module/noauthprobe/service/NoAuthProbeService.java b/src/main/java/com/loafle/overflow/module/noauthprobe/service/NoAuthProbeService.java index 5e05d20..d130ac0 100644 --- a/src/main/java/com/loafle/overflow/module/noauthprobe/service/NoAuthProbeService.java +++ b/src/main/java/com/loafle/overflow/module/noauthprobe/service/NoAuthProbeService.java @@ -10,6 +10,7 @@ import com.loafle.overflow.module.noauthprobe.dao.NoAuthProbeDAO; import com.loafle.overflow.module.noauthprobe.model.NoAuthProbe; import com.loafle.overflow.module.probe.model.Probe; import com.loafle.overflow.module.probe.service.ProbeService; +import com.loafle.overflow.commons.service.MessagePublisher; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.type.TypeReference; import org.springframework.beans.factory.annotation.Autowired; @@ -40,6 +41,9 @@ public class NoAuthProbeService { @Autowired private ObjectMapper objectMapper; + @Autowired + private MessagePublisher messagePublisher; + public NoAuthProbe regist(NoAuthProbe noAuthProbe) { noAuthProbe.setTempProbeKey(UUID.randomUUID().toString()); @@ -48,6 +52,8 @@ public class NoAuthProbeService { ApiKey apiKey = apiKeyService.readByApiKey(noAuthProbe.getApiKey()); noAuthProbe.setDomain(apiKey.getDomain()); + messagePublisher.publishToDomain("/app", apiKey.getDomain(), "NoAuthProbeService.regist", noAuthProbe); + return this.noAuthProbeDAO.save(noAuthProbe); } diff --git a/src/main/java/com/loafle/overflow/redis/service/RedisMessagePublisher.java b/src/main/java/com/loafle/overflow/redis/service/RedisMessagePublisher.java new file mode 100644 index 0000000..5cb71bc --- /dev/null +++ b/src/main/java/com/loafle/overflow/redis/service/RedisMessagePublisher.java @@ -0,0 +1,102 @@ +package com.loafle.overflow.redis.service; + +import com.loafle.overflow.commons.model.PublishMessage; +import com.loafle.overflow.commons.service.MessagePublisher; +import com.loafle.overflow.module.domain.model.Domain; +import com.loafle.overflow.module.member.model.Member; +import com.loafle.overflow.module.member.service.MemberService; +import org.codehaus.jackson.map.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.listener.ChannelTopic; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Service +public class RedisMessagePublisher implements MessagePublisher { + + @Autowired + private RedisTemplate redisTemplate; + @Autowired + private ObjectMapper objectMapper; + @Autowired + private MemberService memberService; + + private Map topics; + + public RedisMessagePublisher() { + } + + public RedisMessagePublisher(final RedisTemplate redisTemplate, final Map topics) { + this.redisTemplate = redisTemplate; + this.topics = topics; + } + + public void publishToMember(final String channel, final String memberID, final String method, final Object... params) { + PublishMessage message = new PublishMessage(); + message.addTarget(memberID); + this.publish(channel, message, method, params); + } + public void publishToDomain(final String channel, final Domain domain, final String method, final Object... params) { + PublishMessage message = new PublishMessage(); + message.setTargets(getMemberListByDomain(domain)); + this.publish(channel, message, method, params); + + } + public void publishToDomainByProbeKey(final String channel, final String probeKey, final String method, final Object... params) { + PublishMessage message = new PublishMessage(); + message.setTargets(getMemberListByProbeKey(probeKey)); + this.publish(channel, message, method, params); + } + + @Cacheable("memberListByDomain") + protected List getMemberListByDomain(final Domain domain) { + return this.getMemberList(memberService.readAllByDomain(domain)); + } + + @Cacheable("memberListByProbeKey") + protected List getMemberListByProbeKey(final String probeKey) { + return this.getMemberList(memberService.readAllByProbeKey(probeKey)); + } + + protected List getMemberList(final List members) { + List results = new ArrayList<>(members.size()); + for (Member member: members) { + results.add(member.getEmail()); + } + + return results; + } + + + protected void publish(final String channel, PublishMessage message, final String method, Object... params) { + ChannelTopic topic = this.topics.get(channel); + message.setMessage(new PublishMessage.PublishMessageBody(method, this.getMessageBody(params))); + + redisTemplate.convertAndSend(topic.getTopic(), message); + } + + protected List getMessageBody(final Object... params) { + List results = new ArrayList<>(params.length); + try { + for (Object param : params) { + results.add(objectMapper.writeValueAsString(param)); + } + } catch (IOException e) { + e.printStackTrace(); + } + return results; + } + +// public void publishToMember(final String message) { +// redisTemplate.convertAndSend(topic.getTopic(), message); +// } +// public void publishToDomain(final String message) { +// redisTemplate.convertAndSend(topic.getTopic(), message); +// } +} diff --git a/src/main/java/com/loafle/overflow/spring/AppConfig.java b/src/main/java/com/loafle/overflow/spring/AppConfig.java index 9f67551..afe1b33 100644 --- a/src/main/java/com/loafle/overflow/spring/AppConfig.java +++ b/src/main/java/com/loafle/overflow/spring/AppConfig.java @@ -2,30 +2,43 @@ package com.loafle.overflow.spring; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.map.ObjectMapper; -import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.context.annotation.*; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; /** * Created by insanity on 17. 6. 13. */ @Configuration @ComponentScan(basePackages = {"com.loafle.overflow"}, excludeFilters = @ComponentScan.Filter({Configuration.class})) -@Import({JdbcConfiguration.class, MailConfiguration.class}) -@PropertySource({"classpath:database.properties","classpath:mail.properties"}) +@Import({ + JdbcConfiguration.class, + MailConfiguration.class, + RedisConfiguration.class, + CacheConfiguration.class +}) +@PropertySource({ + "classpath:database.properties", + "classpath:mail.properties", + "classpath:redis.properties", + "classpath:cache.properties" +}) public class AppConfig { +// @Bean +// public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() { +// PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); +//// ppc.setLocation(new ClassPathResource("database.properties")); +// ppc.setLocations(new Resource[] { +// new ClassPathResource("database.properties"), +// new ClassPathResource("mail.properties"), +// new ClassPathResource("redis.properties") +// }); +// ppc.setIgnoreUnresolvablePlaceholders(true); +// +// return ppc; +// } @Bean - public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() { - PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); -// ppc.setLocation(new ClassPathResource("database.properties")); - ppc.setLocations(new Resource[] { - new ClassPathResource("database.properties"), - new ClassPathResource("mail.properties") - }); - ppc.setIgnoreUnresolvablePlaceholders(true); - - return ppc; + public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { + return new PropertySourcesPlaceholderConfigurer(); } @Bean diff --git a/src/main/java/com/loafle/overflow/spring/CacheConfiguration.java b/src/main/java/com/loafle/overflow/spring/CacheConfiguration.java new file mode 100644 index 0000000..bc68c9d --- /dev/null +++ b/src/main/java/com/loafle/overflow/spring/CacheConfiguration.java @@ -0,0 +1,26 @@ +package com.loafle.overflow.spring; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.caffeine.CaffeineCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@EnableCaching +@Configuration +public class CacheConfiguration { + @Value("#{'${cache.cache-names}'.split(',')}") + private String[] cacheNames; + @Value("${cache.caffeine.spec}") + private String spec; + + @Bean + public CacheManager cacheManager() { + //A EhCache based Cache manager + CaffeineCacheManager cacheManager = new CaffeineCacheManager(cacheNames); + cacheManager.setAllowNullValues(false); + cacheManager.setCacheSpecification(spec); + return cacheManager; + } +} diff --git a/src/main/java/com/loafle/overflow/spring/RedisConfiguration.java b/src/main/java/com/loafle/overflow/spring/RedisConfiguration.java new file mode 100644 index 0000000..0607cc0 --- /dev/null +++ b/src/main/java/com/loafle/overflow/spring/RedisConfiguration.java @@ -0,0 +1,56 @@ +package com.loafle.overflow.spring; + +import com.loafle.overflow.commons.service.MessagePublisher; +import com.loafle.overflow.redis.service.RedisMessagePublisher; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.listener.ChannelTopic; +import org.springframework.data.redis.serializer.GenericToStringSerializer; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Configuration +public class RedisConfiguration { + @Value("${redis.host}") + private String host; + @Value("${redis.port}") + private int port; + @Value("#{'${redis.channels}'.split(',')}") + private List channels; + + @Bean + JedisConnectionFactory jedisConnectionFactory() { + JedisConnectionFactory jedisConFactory = new JedisConnectionFactory(); + jedisConFactory.setHostName(host); + jedisConFactory.setPort(port); + return jedisConFactory; + } + + @Bean + public RedisTemplate redisTemplate() { + final RedisTemplate template = new RedisTemplate(); + template.setConnectionFactory(jedisConnectionFactory()); + template.setValueSerializer(new GenericToStringSerializer(Object.class)); + return template; + } + + @Bean + MessagePublisher messagePublisher() { + return new RedisMessagePublisher(redisTemplate(), topics()); + } + + @Bean + Map topics() { + Map topicMap = new HashMap<>(this.channels.size()); + for (String channel: this.channels) { + topicMap.put(channel, new ChannelTopic(channel)); + } + return topicMap; + } + +} diff --git a/src/main/resources/local/cache.properties b/src/main/resources/local/cache.properties new file mode 100644 index 0000000..fda34c0 --- /dev/null +++ b/src/main/resources/local/cache.properties @@ -0,0 +1,3 @@ +# Caffeine +cache.cache-names:memberListByDomain,memberListByProbeKey +cache.caffeine.spec: initialCapacity=100,maximumSize=500,expireAfterAccess=5m,recordStats \ No newline at end of file diff --git a/src/main/resources/local/redis.properties b/src/main/resources/local/redis.properties new file mode 100644 index 0000000..bebb8a1 --- /dev/null +++ b/src/main/resources/local/redis.properties @@ -0,0 +1,4 @@ +# Redis +redis.host=192.168.1.50 +redis.port=6379 +redis.channels=/web,/probe,/auth \ No newline at end of file diff --git a/src/test/java/com/loafle/overflow/spring/AppConfigTest.java b/src/test/java/com/loafle/overflow/spring/AppConfigTest.java index d3b9ff8..2d6a13e 100644 --- a/src/test/java/com/loafle/overflow/spring/AppConfigTest.java +++ b/src/test/java/com/loafle/overflow/spring/AppConfigTest.java @@ -1,7 +1,10 @@ package com.loafle.overflow.spring; +import org.codehaus.jackson.map.DeserializationConfig; +import org.codehaus.jackson.map.ObjectMapper; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.context.annotation.*; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.jdbc.core.JdbcTemplate; @@ -14,21 +17,46 @@ import static org.junit.Assert.*; */ @Configuration @ComponentScan(basePackages = {"com.loafle.overflow"}, excludeFilters = @ComponentScan.Filter({Configuration.class})) -@Import({JdbcConfiguration.class, MailConfiguration.class}) -@TestPropertySource({"classpath:database.properties","classpath:mail.properties"}) +@Import({ + JdbcConfiguration.class, + MailConfiguration.class, + RedisConfiguration.class, + CacheConfiguration.class +}) +@TestPropertySource({ + "classpath:database.properties", + "classpath:mail.properties", + "classpath:redis.properties", + "classpath:cache.properties" +}) + public class AppConfigTest { +// @Bean +// public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() { +// PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); +//// ppc.setLocation(new ClassPathResource("database.properties")); +// ppc.setLocations(new Resource[] { +// new ClassPathResource("database.properties"), +// new ClassPathResource("mail.properties"), +// new ClassPathResource("redis.properties") +// }); +// ppc.setIgnoreUnresolvablePlaceholders(true); +// +// return ppc; +// } @Bean - public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() { - PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); -// ppc.setLocation(new ClassPathResource("database.properties")); - ppc.setLocations(new Resource[] { - new ClassPathResource("database.properties"), - new ClassPathResource("mail.properties") - }); - ppc.setIgnoreUnresolvablePlaceholders(true); - - return ppc; + public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { + return new PropertySourcesPlaceholderConfigurer(); } + @Bean + public ObjectMapper getObjectMapper() { + + ObjectMapper objectMapper = new ObjectMapper(); + + objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + return objectMapper; + } } \ No newline at end of file diff --git a/src/test/resources/cache.properties b/src/test/resources/cache.properties new file mode 100644 index 0000000..fda34c0 --- /dev/null +++ b/src/test/resources/cache.properties @@ -0,0 +1,3 @@ +# Caffeine +cache.cache-names:memberListByDomain,memberListByProbeKey +cache.caffeine.spec: initialCapacity=100,maximumSize=500,expireAfterAccess=5m,recordStats \ No newline at end of file diff --git a/src/test/resources/redis.properties b/src/test/resources/redis.properties new file mode 100644 index 0000000..bebb8a1 --- /dev/null +++ b/src/test/resources/redis.properties @@ -0,0 +1,4 @@ +# Redis +redis.host=192.168.1.50 +redis.port=6379 +redis.channels=/web,/probe,/auth \ No newline at end of file