diff --git a/pom.xml b/pom.xml
index 66c365fe7..7adc8d870 100644
--- a/pom.xml
+++ b/pom.xml
@@ -60,6 +60,7 @@
redisson-all
redisson-tomcat
redisson-spring-data
+ redisson-spring-boot-starter
diff --git a/redisson-spring-boot-starter/README.md b/redisson-spring-boot-starter/README.md
new file mode 100644
index 000000000..13f4d95ae
--- /dev/null
+++ b/redisson-spring-boot-starter/README.md
@@ -0,0 +1,46 @@
+Spring Boot Starter
+===
+
+Integrates Redisson with Spring Boot library.
+
+Supports Spring Data Redis 1.3.x, 1.4.x, 1.5.x, 2.0.x
+
+Usage
+===
+
+### 1. Add `redisson-spring-boot-starter` dependency into your project:
+
+1. __For JDK 1.8+__
+
+ Maven
+ ```xml
+
+ org.redisson
+ redisson-spring-boot-starter
+ 3.8.0
+
+ ```
+ Gradle
+
+ ```java
+ compile 'org.redisson:redisson-spring-boot-starter:3.8.0'
+ ```
+
+2. __For JDK 1.6+__
+
+ Maven
+ ```xml
+
+ org.redisson
+ redisson-spring-boot-starter
+ 2.13.0
+
+ ```
+ Gradle
+
+ ```java
+ compile 'org.redisson:redisson-spring-boot-starter:2.13.0'
+ ```
+
+
+### 2. Get access to Redisson through spring bean with `RedissonClient` interface
diff --git a/redisson-spring-boot-starter/pom.xml b/redisson-spring-boot-starter/pom.xml
new file mode 100644
index 000000000..8d453ff4b
--- /dev/null
+++ b/redisson-spring-boot-starter/pom.xml
@@ -0,0 +1,129 @@
+
+ 4.0.0
+
+
+ org.redisson
+ redisson-parent
+ 2.12.6-SNAPSHOT
+ ../
+
+
+
+ 1.5.15.RELEASE
+
+
+ redisson-spring-boot-starter
+ jar
+
+ Redisson/Spring Boot Starter
+
+
+
+
+ maven-compiler-plugin
+
+
+
+ maven-javadoc-plugin
+
+
+ com.mycila
+ license-maven-plugin
+ 3.0
+
+ ${basedir}
+
+ false
+ true
+ false
+
+ src/main/java/org/redisson/
+
+
+ target/**
+
+ true
+
+ JAVADOC_STYLE
+
+ true
+ true
+ UTF-8
+
+
+
+
+ check
+
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+ org.redisson
+ redisson
+ ${project.version}
+
+
+
+ org.redisson
+ redisson-spring-data-18
+ ${project.version}
+
+
+
+ org.assertj
+ assertj-core
+ 3.10.0
+ test
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
diff --git a/redisson-spring-boot-starter/src/main/java/org/redisson/spring/starter/RedissonAutoConfiguration.java b/redisson-spring-boot-starter/src/main/java/org/redisson/spring/starter/RedissonAutoConfiguration.java
new file mode 100644
index 000000000..51d924353
--- /dev/null
+++ b/redisson-spring-boot-starter/src/main/java/org/redisson/spring/starter/RedissonAutoConfiguration.java
@@ -0,0 +1,149 @@
+/**
+ * Copyright 2018 Nikita Koksharov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.redisson.spring.starter;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.redisson.spring.data.connection.RedissonConnectionFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
+import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
+import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Sentinel;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.Resource;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.util.ReflectionUtils;
+
+/**
+ *
+ * @author Nikita Koksharov
+ *
+ */
+@Configuration
+@ConditionalOnClass(Redisson.class)
+@AutoConfigureAfter(RedisAutoConfiguration.class)
+@EnableConfigurationProperties(RedissonProperties.class)
+public class RedissonAutoConfiguration {
+
+ @Autowired
+ private RedissonProperties redissonProperties;
+
+ @Autowired
+ private RedisProperties redisProperties;
+
+ @Autowired
+ private ApplicationContext ctx;
+
+ @Bean
+ @ConditionalOnMissingBean(RedisConnectionFactory.class)
+ public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) {
+ return new RedissonConnectionFactory(redisson);
+ }
+
+ @Bean(destroyMethod = "shutdown")
+ @ConditionalOnMissingBean(RedissonClient.class)
+ public RedissonClient redisson() throws IOException {
+ Config config = null;
+ Method clusterMethod = ReflectionUtils.findMethod(RedisProperties.class, "getCluster");
+ Method timeoutMethod = ReflectionUtils.findMethod(RedisProperties.class, "getTimeout");
+ Object timeoutValue = ReflectionUtils.invokeMethod(timeoutMethod, redisProperties);
+ int timeout;
+ if (!(timeoutValue instanceof Integer)) {
+ Method millisMethod = ReflectionUtils.findMethod(timeoutValue.getClass(), "toMillis");
+ timeout = ((Long) ReflectionUtils.invokeMethod(millisMethod, timeoutValue)).intValue();
+ } else {
+ timeout = (Integer)timeoutValue;
+ }
+
+ if (redissonProperties.getConfig() != null) {
+ try {
+ InputStream is = getConfigStream();
+ config = Config.fromJSON(is);
+ } catch (IOException e) {
+ // trying next format
+ try {
+ InputStream is = getConfigStream();
+ config = Config.fromYAML(is);
+ } catch (IOException e1) {
+ throw new IllegalArgumentException("Can't parse config", e1);
+ }
+ }
+ } else if (redisProperties.getSentinel() != null) {
+ Method nodesMethod = ReflectionUtils.findMethod(Sentinel.class, "getNodes");
+ Object nodesValue = ReflectionUtils.invokeMethod(nodesMethod, redisProperties.getSentinel());
+
+ String[] nodes;
+ if (nodesValue instanceof String) {
+ nodes = ((String)nodesValue).split(",");
+ } else {
+ nodes = ((List)nodesValue).toArray(new String[((List)nodesValue).size()]);
+ }
+
+ config = new Config();
+ config.useSentinelServers()
+ .setMasterName(redisProperties.getSentinel().getMaster())
+ .addSentinelAddress(nodes)
+ .setDatabase(redisProperties.getDatabase())
+ .setConnectTimeout(timeout)
+ .setPassword(redisProperties.getPassword());
+ } else if (clusterMethod != null && ReflectionUtils.invokeMethod(clusterMethod, redisProperties) != null) {
+ Object clusterObject = ReflectionUtils.invokeMethod(clusterMethod, redisProperties);
+ Method nodesMethod = ReflectionUtils.findMethod(clusterObject.getClass(), "getNodes");
+ List nodesObject = (List) ReflectionUtils.invokeMethod(nodesMethod, clusterObject);
+
+ config = new Config();
+ config.useClusterServers()
+ .addNodeAddress(nodesObject.toArray(new String[nodesObject.size()]))
+ .setConnectTimeout(timeout)
+ .setPassword(redisProperties.getPassword());
+ } else {
+ config = new Config();
+ String prefix = "redis://";
+ Method method = ReflectionUtils.findMethod(RedisProperties.class, "isSsl");
+ if (method != null && (Boolean)ReflectionUtils.invokeMethod(method, redisProperties)) {
+ prefix = "rediss://";
+ }
+
+ config.useSingleServer()
+ .setAddress(prefix + redisProperties.getHost() + ":" + redisProperties.getPort())
+ .setConnectTimeout(timeout)
+ .setDatabase(redisProperties.getDatabase())
+ .setPassword(redisProperties.getPassword());
+ }
+
+ return Redisson.create(config);
+ }
+
+ protected InputStream getConfigStream() throws IOException {
+ Resource resource = ctx.getResource(redissonProperties.getConfig());
+ InputStream is = resource.getInputStream();
+ return is;
+ }
+
+
+}
diff --git a/redisson-spring-boot-starter/src/main/java/org/redisson/spring/starter/RedissonProperties.java b/redisson-spring-boot-starter/src/main/java/org/redisson/spring/starter/RedissonProperties.java
new file mode 100644
index 000000000..e4c35da97
--- /dev/null
+++ b/redisson-spring-boot-starter/src/main/java/org/redisson/spring/starter/RedissonProperties.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright 2018 Nikita Koksharov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.redisson.spring.starter;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ *
+ * @author Nikita Koksharov
+ *
+ */
+@ConfigurationProperties(prefix = "spring.redis.redisson")
+public class RedissonProperties {
+
+ private String config;
+
+ public String getConfig() {
+ return config;
+ }
+
+ public void setConfig(String config) {
+ this.config = config;
+ }
+
+}
diff --git a/redisson-spring-boot-starter/src/test/java/org/redisson/spring/starter/RedissonApplication.java b/redisson-spring-boot-starter/src/test/java/org/redisson/spring/starter/RedissonApplication.java
new file mode 100644
index 000000000..cb844f490
--- /dev/null
+++ b/redisson-spring-boot-starter/src/test/java/org/redisson/spring/starter/RedissonApplication.java
@@ -0,0 +1,15 @@
+package org.redisson.spring.starter;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+
+@SpringBootApplication
+@EnableCaching
+public class RedissonApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(RedissonApplication.class, args);
+ }
+
+}
diff --git a/redisson-spring-boot-starter/src/test/java/org/redisson/spring/starter/RedissonAutoConfigurationTest.java b/redisson-spring-boot-starter/src/test/java/org/redisson/spring/starter/RedissonAutoConfigurationTest.java
new file mode 100644
index 000000000..4c00f38b4
--- /dev/null
+++ b/redisson-spring-boot-starter/src/test/java/org/redisson/spring/starter/RedissonAutoConfigurationTest.java
@@ -0,0 +1,43 @@
+package org.redisson.spring.starter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.redisson.api.RMap;
+import org.redisson.api.RedissonClient;
+import org.redisson.client.codec.StringCodec;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.redis.core.BoundHashOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(
+ classes = RedissonApplication.class,
+ properties = {
+ "spring.redis.redisson.config=classpath:redisson.yaml",
+ "spring.redis.timeout=10000"
+ })
+public class RedissonAutoConfigurationTest {
+
+ @Autowired
+ private RedissonClient redisson;
+
+ @Autowired
+ private RedisTemplate template;
+
+ @Test
+ public void testApp() {
+ redisson.getKeys().flushall();
+
+ RMap m = redisson.getMap("test", StringCodec.INSTANCE);
+ m.put("1", "2");
+
+ BoundHashOperations hash = template.boundHashOps("test");
+ String t = hash.get("1");
+ assertThat(t).isEqualTo("2");
+ }
+
+}
diff --git a/redisson-spring-boot-starter/src/test/java/org/redisson/spring/starter/RedissonCacheManagerAutoConfigurationTest.java b/redisson-spring-boot-starter/src/test/java/org/redisson/spring/starter/RedissonCacheManagerAutoConfigurationTest.java
new file mode 100644
index 000000000..f30cb8bc1
--- /dev/null
+++ b/redisson-spring-boot-starter/src/test/java/org/redisson/spring/starter/RedissonCacheManagerAutoConfigurationTest.java
@@ -0,0 +1,31 @@
+package org.redisson.spring.starter;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(
+ classes = RedissonApplication.class,
+ properties = {
+ "spring.redis.redisson.config=classpath:redisson.yaml",
+ "spring.redis.timeout=10000",
+ "spring.cache.type=redis",
+ })
+public class RedissonCacheManagerAutoConfigurationTest {
+
+ @Autowired
+ private CacheManager cacheManager;
+
+ @Test
+ public void testApp() {
+ Cache cache = cacheManager.getCache("test");
+ Assert.assertNotNull(cache);
+ }
+
+}
diff --git a/redisson-spring-boot-starter/src/test/resources/redisson.yaml b/redisson-spring-boot-starter/src/test/resources/redisson.yaml
new file mode 100644
index 000000000..28466f3ba
--- /dev/null
+++ b/redisson-spring-boot-starter/src/test/resources/redisson.yaml
@@ -0,0 +1,2 @@
+singleServerConfig:
+ address: "redis://127.0.0.1:6379"
\ No newline at end of file