IGNITE-13722 Adds correct closing of Spring Data Ignite resources - Fixes #31.

Signed-off-by: Aleksey Plekhanov <plehanov.alex@gmail.com>
diff --git a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java
index 354e35b..de8cf0b 100644
--- a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java
+++ b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java
@@ -18,15 +18,28 @@
 
 import java.util.Collection;
 import java.util.Collections;
+import org.apache.ignite.springdata.proxy.IgniteProxy;
 import org.apache.ignite.springdata20.repository.IgniteRepository;
+import org.apache.ignite.springdata20.repository.support.IgniteProxyFactory;
 import org.apache.ignite.springdata20.repository.support.IgniteRepositoryFactoryBean;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
 import org.springframework.data.repository.config.RepositoryConfigurationExtension;
 import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
+import org.springframework.data.repository.config.RepositoryConfigurationSource;
+
+import static org.springframework.beans.factory.config.ConfigurableBeanFactory.SCOPE_PROTOTYPE;
 
 /**
  * Apache Ignite specific implementation of {@link RepositoryConfigurationExtension}.
  */
 public class IgniteRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
+    /** Name of the auto-registered Ignite proxy factory bean. */
+    private static final String IGNITE_PROXY_FACTORY_BEAN_NAME = "igniteProxyFactory";
+
+    /** Name of the auto-registered Ignite proxy bean prototype. */
+    private static final String IGNITE_PROXY_BEAN_NAME = "igniteProxy";
+
     /** {@inheritDoc} */
     @Override public String getModuleName() {
         return "Apache Ignite";
@@ -46,4 +59,22 @@
     @Override protected Collection<Class<?>> getIdentifyingTypes() {
         return Collections.singleton(IgniteRepository.class);
     }
+
+    /** {@inheritDoc} */
+    @Override public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource cfg) {
+        registerIfNotAlreadyRegistered(
+            BeanDefinitionBuilder.genericBeanDefinition(IgniteProxyFactory.class).getBeanDefinition(),
+            registry,
+            IGNITE_PROXY_FACTORY_BEAN_NAME,
+            cfg);
+
+        registerIfNotAlreadyRegistered(
+            BeanDefinitionBuilder.genericBeanDefinition(IgniteProxy.class)
+                .setScope(SCOPE_PROTOTYPE)
+                .setFactoryMethodOnBean("igniteProxy", IGNITE_PROXY_FACTORY_BEAN_NAME)
+                .getBeanDefinition(),
+            registry,
+            IGNITE_PROXY_BEAN_NAME,
+            cfg);
+    }
 }
diff --git a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteProxyFactory.java b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteProxyFactory.java
new file mode 100644
index 0000000..d571cc2
--- /dev/null
+++ b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteProxyFactory.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.ignite.springdata20.repository.support;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.ignite.springdata.proxy.IgniteProxy;
+import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.config.BeanExpressionContext;
+import org.springframework.beans.factory.config.BeanExpressionResolver;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.expression.StandardBeanExpressionResolver;
+
+import static org.apache.ignite.springdata20.repository.support.IgniteRepositoryFactory.getRepositoryConfiguration;
+
+/**
+ * Represents factory for obtaining instances of {@link IgniteProxy} that provide client-independent connection to the
+ * Ignite cluster.
+ */
+public class IgniteProxyFactory implements ApplicationContextAware, DisposableBean {
+    /** Spring application expression resolver. */
+    private final BeanExpressionResolver expressionResolver = new StandardBeanExpressionResolver();
+
+    /** Repositories associated with Ignite proxy. */
+    private final Map<Class<?>, IgniteProxy> igniteProxies = new ConcurrentHashMap<>();
+
+    /** Spring application context. */
+    private ApplicationContext ctx;
+
+    /** Spring application bean expression context. */
+    private BeanExpressionContext beanExpressionCtx;
+
+    /**
+     * @param repoInterface The repository interface class for which {@link IgniteProxy} will be created.
+     * @return {@link IgniteProxy} instance.
+     */
+    public IgniteProxy igniteProxy(Class<?> repoInterface) {
+        return igniteProxies.computeIfAbsent(repoInterface, k -> createIgniteProxy(repoInterface));
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setApplicationContext(ApplicationContext ctx) throws BeansException {
+        this.ctx = ctx;
+
+        beanExpressionCtx = new BeanExpressionContext(
+            new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory()),
+            null);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void destroy() throws Exception {
+        Set<IgniteProxy> proxies = new HashSet<>(igniteProxies.values());
+
+        Exception destroyE = null;
+
+        for (IgniteProxy proxy : proxies) {
+            if (proxy instanceof AutoCloseable) {
+                try {
+                    ((AutoCloseable)proxy).close();
+                }
+                catch (Exception e) {
+                    if (destroyE == null)
+                        destroyE = e;
+                    else
+                        destroyE.addSuppressed(e);
+                }
+            }
+        }
+
+        if (destroyE != null)
+            throw destroyE;
+    }
+
+    /**
+     * Creates {@link IgniteProxy} to be used for providing access to the Ignite cluster for specified repository.
+     *
+     * @param repoInterface {@link Class} instance of the repository interface.
+     * @return Instance of {@link IgniteProxy} associated with specified repository.
+     *
+     * @see RepositoryConfig
+     */
+    private IgniteProxy createIgniteProxy(Class<?> repoInterface) {
+        RepositoryConfig repoCfg = getRepositoryConfiguration(repoInterface);
+
+        Object connCfg;
+
+        try {
+            connCfg = ctx.getBean(evaluateExpression(repoCfg.igniteInstance()));
+        }
+        catch (BeansException ex) {
+            try {
+                connCfg = ctx.getBean(evaluateExpression(repoCfg.igniteCfg()));
+            }
+            catch (BeansException ex2) {
+                try {
+                    connCfg = ctx.getBean(evaluateExpression(repoCfg.igniteSpringCfgPath()), String.class);
+                }
+                catch (BeansException ex3) {
+                    throw new IllegalArgumentException("Invalid configuration for repository " +
+                        repoInterface.getName() + ". No beans were found that provide connection configuration to the" +
+                        " Ignite cluster. Check \"igniteInstance\", \"igniteCfg\", \"igniteSpringCfgPath\" parameters" +
+                        " of " + RepositoryConfig.class.getName() + " repository annotation.");
+                }
+            }
+        }
+
+        return IgniteProxy.of(connCfg);
+    }
+
+    /**
+     * Evaluates the SpEL expression.
+     *
+     * @param spelExpression SpEL expression
+     * @return The result of evaluation of the SpEL expression.
+     */
+    private String evaluateExpression(String spelExpression) {
+        return (String)expressionResolver.evaluate(spelExpression, beanExpressionCtx);
+    }
+}
diff --git a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java
index dacb3e4..2096277 100644
--- a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java
+++ b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java
@@ -16,27 +16,15 @@
  */
 package org.apache.ignite.springdata20.repository.support;
 
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Optional;
-import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteException;
-import org.apache.ignite.Ignition;
-import org.apache.ignite.client.IgniteClient;
-import org.apache.ignite.configuration.ClientConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.springdata.proxy.IgniteCacheProxy;
 import org.apache.ignite.springdata.proxy.IgniteProxy;
-import org.apache.ignite.springdata.proxy.IgniteProxyImpl;
-import org.apache.ignite.springdata.proxy.IgniteClientProxy;
-import org.apache.ignite.springdata20.repository.IgniteRepository;
 import org.apache.ignite.springdata20.repository.config.DynamicQueryConfig;
 import org.apache.ignite.springdata20.repository.config.Query;
 import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
 import org.apache.ignite.springdata20.repository.query.IgniteQuery;
 import org.apache.ignite.springdata20.repository.query.IgniteQueryGenerator;
 import org.apache.ignite.springdata20.repository.query.IgniteRepositoryQuery;
-import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.config.BeanExpressionContext;
 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 import org.springframework.context.ApplicationContext;
@@ -62,85 +50,44 @@
  * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
 public class IgniteRepositoryFactory extends RepositoryFactorySupport {
-    /** Spring application context */
-    private final ApplicationContext ctx;
-
-    /** Spring application bean factory */
-    private final DefaultListableBeanFactory beanFactory;
-
     /** Spring application expression resolver */
     private final StandardBeanExpressionResolver resolver = new StandardBeanExpressionResolver();
 
     /** Spring application bean expression context */
     private final BeanExpressionContext beanExpressionContext;
 
-    /** Mapping of a repository to a cache. */
-    private final Map<Class<?>, String> repoToCache = new HashMap<>();
+    /** Ignite cache proxy instance associated with the current repository. */
+    private final IgniteCacheProxy<?, ?> cache;
 
-    /** Mapping of a repository to a ignite instance. */
-    private final Map<Class<?>, IgniteProxy> repoToIgnite = new HashMap<>();
+    /** Ignite proxy instance associated with the current repository. */
+    private final IgniteProxy ignite;
 
     /**
-     * Creates the factory with initialized {@link Ignite} instance.
-     *
-     * @param ctx the ctx
+     * @param ctx Spring Application context.
+     * @param repoInterface Repository interface.
      */
-    public IgniteRepositoryFactory(ApplicationContext ctx) {
-        this.ctx = ctx;
+    public IgniteRepositoryFactory(ApplicationContext ctx, Class<?> repoInterface) {
+        ignite = ctx.getBean(IgniteProxy.class, repoInterface);
 
-        beanFactory = new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory());
+        beanExpressionContext = new BeanExpressionContext(
+            new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory()),
+            null);
 
-        beanExpressionContext = new BeanExpressionContext(beanFactory, null);
-    }
+        RepositoryConfig cfg = getRepositoryConfiguration(repoInterface);
 
-    /** */
-    private IgniteProxy igniteForRepoConfig(RepositoryConfig config) {
-        try {
-            Object igniteInstanceBean = ctx.getBean(evaluateExpression(config.igniteInstance()));
+        String cacheName = evaluateExpression(cfg.cacheName());
 
-            if (igniteInstanceBean instanceof Ignite)
-                return new IgniteProxyImpl((Ignite)igniteInstanceBean);
-            else if (igniteInstanceBean instanceof IgniteClient)
-                return new IgniteClientProxy((IgniteClient)igniteInstanceBean);
+        Assert.hasText(cacheName, "Invalid configuration for repository " + repoInterface.getName() +
+            ". Set a name of an Apache Ignite cache using " + RepositoryConfig.class.getName() +
+            " annotation to map this repository to the underlying cache.");
 
-            throw new IllegalStateException("Invalid repository configuration. The Spring Bean corresponding to the" +
-                " \"igniteInstance\" property of repository configuration must be one of the following types: " +
-                Ignite.class.getName() + ", " + IgniteClient.class.getName());
-        }
-        catch (BeansException ex) {
-            try {
-                Object igniteCfgBean = ctx.getBean(evaluateExpression(config.igniteCfg()));
+       cache = cfg.autoCreateCache() ? ignite.getOrCreateCache(cacheName) : ignite.cache(cacheName);
 
-                if (igniteCfgBean instanceof IgniteConfiguration) {
-                    try {
-                        // first try to attach to existing ignite instance
-                        return new IgniteProxyImpl(Ignition.ignite(((IgniteConfiguration)igniteCfgBean).getIgniteInstanceName()));
-                    }
-                    catch (Exception ignored) {
-                        // nop
-                    }
-                    return new IgniteProxyImpl(Ignition.start((IgniteConfiguration)igniteCfgBean));
-                }
-                else if (igniteCfgBean instanceof ClientConfiguration)
-                    return new IgniteClientProxy(Ignition.startClient((ClientConfiguration)igniteCfgBean));
-
-                throw new IllegalStateException("Invalid repository configuration. The Spring Bean corresponding to" +
-                    " the \"igniteCfg\" property of repository configuration must be one of the following types: [" +
-                    IgniteConfiguration.class.getName() + ", " + ClientConfiguration.class.getName() + ']');
-
-            }
-            catch (BeansException ex2) {
-                try {
-                    String igniteSpringCfgPath = evaluateExpression(config.igniteSpringCfgPath());
-                    String path = (String)ctx.getBean(igniteSpringCfgPath);
-                    return new IgniteProxyImpl(Ignition.start(path));
-                }
-                catch (BeansException ex3) {
-                    throw new IgniteException("Failed to initialize Ignite repository factory. No beans required for" +
-                        " repository configuration were found. Check \"igniteInstance\", \"igniteCfg\"," +
-                        " \"igniteSpringCfgPath\" parameters of " + RepositoryConfig.class.getName() + "class.");
-                }
-            }
+        if (cache == null) {
+            throw new IllegalArgumentException(
+                "Cache '" + cacheName + "' not found for repository interface " + repoInterface.getName()
+                    + ". Please, add a cache configuration to ignite configuration"
+                    + " or pass autoCreateCache=true to " + RepositoryConfig.class.getName() + " annotation.");
         }
     }
 
@@ -164,28 +111,6 @@
         return IgniteRepositoryImpl.class;
     }
 
-    /** {@inheritDoc} */
-    @Override protected synchronized RepositoryMetadata getRepositoryMetadata(Class<?> repoItf) {
-        Assert.notNull(repoItf, "Repository interface must be set.");
-        Assert.isAssignable(IgniteRepository.class, repoItf, "Repository must implement IgniteRepository interface.");
-
-        RepositoryConfig annotation = repoItf.getAnnotation(RepositoryConfig.class);
-
-        Assert.notNull(annotation, "Set a name of an Apache Ignite cache using @RepositoryConfig annotation to map "
-            + "this repository to the underlying cache.");
-
-        Assert.hasText(annotation.cacheName(), "Set a name of an Apache Ignite cache using @RepositoryConfig "
-            + "annotation to map this repository to the underlying cache.");
-
-        String cacheName = evaluateExpression(annotation.cacheName());
-
-        repoToCache.put(repoItf, cacheName);
-
-        repoToIgnite.put(repoItf, igniteForRepoConfig(annotation));
-
-        return super.getRepositoryMetadata(repoItf);
-    }
-
     /**
      * Evaluate the SpEL expression
      *
@@ -196,33 +121,9 @@
         return (String)resolver.evaluate(spelExpression, beanExpressionContext);
     }
 
-    /** Control underlying cache creation to avoid cache creation by mistake */
-    private IgniteCacheProxy<?, ?> getRepositoryCache(Class<?> repoIf) {
-        IgniteProxy ignite = repoToIgnite.get(repoIf);
-
-        RepositoryConfig config = repoIf.getAnnotation(RepositoryConfig.class);
-
-        String cacheName = repoToCache.get(repoIf);
-
-        IgniteCacheProxy<?, ?> c = config.autoCreateCache() ? ignite.getOrCreateCache(cacheName) : ignite.cache(cacheName);
-
-        if (c == null) {
-            throw new IllegalStateException(
-                "Cache '" + cacheName + "' not found for repository interface " + repoIf.getName()
-                    + ". Please, add a cache configuration to ignite configuration"
-                    + " or pass autoCreateCache=true to org.apache.ignite.springdata20"
-                    + ".repository.config.RepositoryConfig annotation.");
-        }
-
-        return c;
-    }
-
     /** {@inheritDoc} */
     @Override protected Object getTargetRepository(RepositoryInformation metadata) {
-        IgniteProxy ignite = repoToIgnite.get(metadata.getRepositoryInterface());
-
-        return getTargetRepositoryViaReflection(metadata, ignite,
-            getRepositoryCache(metadata.getRepositoryInterface()));
+        return getTargetRepositoryViaReflection(metadata, ignite, cache);
     }
 
     /** {@inheritDoc} */
@@ -243,8 +144,7 @@
                     annotation.textQuery(), false, IgniteQueryGenerator.getOptions(mtd)) : null;
 
                 if (key != QueryLookupStrategy.Key.CREATE) {
-                    return new IgniteRepositoryQuery(metadata, query, mtd, factory,
-                        getRepositoryCache(metadata.getRepositoryInterface()),
+                    return new IgniteRepositoryQuery(metadata, query, mtd, factory, cache,
                         annotatedIgniteQuery ? DynamicQueryConfig.fromQueryAnnotation(annotation) : null,
                         evaluationContextProvider);
                 }
@@ -256,9 +156,8 @@
                     + ".config.Query annotation.");
             }
 
-            return new IgniteRepositoryQuery(metadata, IgniteQueryGenerator.generateSql(mtd, metadata), mtd,
-                factory, getRepositoryCache(metadata.getRepositoryInterface()),
-                DynamicQueryConfig.fromQueryAnnotation(annotation), evaluationContextProvider);
+            return new IgniteRepositoryQuery(metadata, IgniteQueryGenerator.generateSql(mtd, metadata), mtd, factory,
+                cache, DynamicQueryConfig.fromQueryAnnotation(annotation), evaluationContextProvider);
         });
     }
 
@@ -290,4 +189,18 @@
             // insert
             qryUpperCase.matches("^\\s*INSERT\\b.*");
     }
+
+    /**
+     * @return Configuration of the specified repository.
+     * @throws IllegalArgumentException If no configuration is specified.
+     * @see RepositoryConfig
+     */
+    static RepositoryConfig getRepositoryConfiguration(Class<?> repoInterface) {
+        RepositoryConfig cfg = repoInterface.getAnnotation(RepositoryConfig.class);
+
+        Assert.notNull(cfg, "Invalid configuration for repository " + repoInterface.getName() + ". " +
+            RepositoryConfig.class.getName() + " annotation must be specified for each repository interface.");
+
+        return cfg;
+    }
 }
diff --git a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java
index 5b3d612..bce6dda 100644
--- a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java
+++ b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java
@@ -62,6 +62,6 @@
 
     /** {@inheritDoc} */
     @Override protected RepositoryFactorySupport createRepositoryFactory() {
-        return new IgniteRepositoryFactory(ctx);
+        return new IgniteRepositoryFactory(ctx, getObjectType());
     }
 }
diff --git a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java
index b089c22..9410ec2 100644
--- a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java
+++ b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java
@@ -49,7 +49,7 @@
  */
 @Conditional(ConditionFalse.class)
 public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRepository<V, K> {
-    /** Error message indicating that operation is spported only if {@link Ignite} instance is used to access the cluster. */
+    /** Error message indicating that operation is supported only if {@link Ignite} instance is used to access the cluster. */
     private static final String UNSUPPORTED_ERR_MSG = "Current operation is supported only if Ignite node instance is" +
         " used to access the Ignite cluster. See " + RepositoryConfig.class.getName() + "#igniteInstance.";
 
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java
index 6dcadb8..ec2e7ca 100644
--- a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java
+++ b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.springdata;
 
+import org.apache.ignite.Ignite;
 import org.apache.ignite.springdata.compoundkey.CityRepository;
 import org.apache.ignite.springdata.misc.IgniteClientApplicationConfiguration;
 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -32,4 +33,9 @@
 
         repo = ctx.getBean(CityRepository.class);
     }
+
+    /** {@inheritDoc} */
+    @Override protected Ignite ignite() {
+        return ctx.getBean("igniteServerNode", Ignite.class);
+    }
 }
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
index ae42434..226ee9b 100644
--- a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
+++ b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
@@ -18,13 +18,9 @@
 package org.apache.ignite.springdata;
 
 import org.apache.ignite.client.IgniteClient;
-import org.apache.ignite.configuration.ClientConfiguration;
 import org.apache.ignite.springdata.misc.IgniteClientApplicationConfiguration;
 import org.apache.ignite.springdata.misc.PersonRepository;
-import org.apache.ignite.springdata.misc.IgniteClientConfigRepository;
-import org.apache.ignite.springdata20.repository.support.IgniteRepositoryFactory;
 import org.apache.ignite.testframework.GridTestUtils;
-import org.junit.Test;
 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
 /** Tests Spring Data CRUD operation when thin client is used for accessing the Ignite cluster. */
@@ -47,16 +43,4 @@
                 " org.apache.ignite.springdata.misc.PersonRepository#textQueryByFirstNameWithProjectionNamedParameter" +
                 " method configuration or use Ignite node instance to connect to the Ignite cluster.");
     }
-
-    /**
-     * Tests repository configuration in case {@link ClientConfiguration} is used to provide access to Ignite cluster.
-     */
-    @Test
-    public void testRepositoryWithClientConfiguration() {
-        IgniteRepositoryFactory factory = new IgniteRepositoryFactory(ctx);
-
-        IgniteClientConfigRepository repo = factory.getRepository(IgniteClientConfigRepository.class);
-
-        assertTrue(repo.count() > 0);
-    }
 }
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java
index 06e0c28..3a65f29 100644
--- a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java
+++ b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java
@@ -98,7 +98,7 @@
 
     /** load data*/
     public void loadData() throws Exception {
-        Ignite ignite = ctx.getBean(Ignite.class);
+        Ignite ignite = ignite();
 
         if (ignite.cacheNames().contains(CACHE_NAME))
             ignite.destroyCache(CACHE_NAME);
@@ -124,4 +124,9 @@
         assertEquals(AFG_COUNT, repo.findByCountryCode(AFG).size());
         assertEquals(QUANDAHAR, repo.findById(QUANDAHAR_ID));
     }
+
+    /** */
+    protected Ignite ignite() {
+        return ctx.getBean(Ignite.class);
+    }
 }
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java
new file mode 100644
index 0000000..4187e28
--- /dev/null
+++ b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.ignite.springdata;
+
+import java.io.Serializable;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.ClientConfiguration;
+import org.apache.ignite.configuration.ClientConnectorConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.springdata20.repository.IgniteRepository;
+import org.apache.ignite.springdata20.repository.config.EnableIgniteRepositories;
+import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.context.annotation.Configuration;
+
+import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause;
+import static org.springframework.context.annotation.FilterType.ASSIGNABLE_TYPE;
+
+/** Tests Spring Data repository cluster connection configurations. */
+public class IgniteSpringDataConnectionConfigurationTest extends GridCommonAbstractTest {
+    /** */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+    /** */
+    private static final String CACHE_NAME = "PersonCache";
+
+    /** */
+    private static final int CLI_CONN_PORT = 10810;
+
+    /** */
+    private static final String CLI_NAME = "cli-node";
+
+    /** */
+    private static final String SRV_NAME = "srv-node";
+
+    /** */
+    private static final String LOCAL_HOST = "127.0.0.1";
+
+    /** Tests repository configuration in case {@link IgniteConfiguration} is used to access the Ignite cluster. */
+    @Test
+    public void testRepositoryWithIgniteConfiguration() {
+        checkRepositoryConfiguration(IgniteConfigurationApplication.class, IgniteConfigRepository.class);
+
+        assertClientNodeIsStopped();
+    }
+
+    /** Tests repository configuration in case {@link ClientConfiguration} is used to access the Ignite cluster. */
+    @Test
+    public void testRepositoryWithClientConfiguration() {
+        checkRepositoryConfiguration(ClientConfigurationApplication.class, IgniteClientConfigRepository.class);
+    }
+
+    /**
+     * Tests repository configuration in case {@link IgniteConfiguration} that refers to existing Ignite node instance
+     * used to access the Ignite cluster.
+     */
+    @Test
+    public void testRepositoryWithExistingIgniteInstance() throws Exception {
+        try (Ignite ignored = startGrid(getIgniteConfiguration(CLI_NAME, true))) {
+            checkRepositoryConfiguration(IgniteConfigurationApplication.class, IgniteConfigRepository.class);
+
+            assertNotNull(Ignition.ignite(CLI_NAME));
+        }
+    }
+
+    /** Tests repository configuration in case specified cache name is invalid. */
+    @Test
+    public void testRepositoryWithInvalidCacheNameConfiguration() {
+        try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
+            ctx.register(InvalidCacheNameApplication.class);
+
+            assertThrowsAnyCause(log,
+                () -> {
+                    ctx.refresh();
+
+                    return null;
+                },
+                IllegalArgumentException.class,
+                "Cache 'invalidCache' not found for repository interface" +
+                    " org.apache.ignite.springdata.IgniteSpringDataConnectionConfigurationTest$InvalidCacheNameRepository." +
+                    " Please, add a cache configuration to ignite configuration or pass autoCreateCache=true to" +
+                    " org.apache.ignite.springdata20.repository.config.RepositoryConfig annotation.");
+        }
+
+        assertClientNodeIsStopped();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        grid(SRV_NAME).cache(CACHE_NAME).clear();
+    }
+
+    /** */
+    private void assertClientNodeIsStopped() {
+        assertFalse(Ignition.allGrids().stream().map(Ignite::name).anyMatch(CLI_NAME::equals));
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        startGrid(getIgniteConfiguration(SRV_NAME, false));
+    }
+
+    /**
+     * Checks that repository created based on specified Spring application configuration is properly initialized and
+     * got access to the Ignite cluster.
+     */
+    private void checkRepositoryConfiguration(
+        Class<?> cfgCls,
+        Class<? extends IgniteRepository<Object, Serializable>> repoCls
+    ) {
+        try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
+            ctx.register(cfgCls);
+            ctx.refresh();
+
+            IgniteRepository<Object, Serializable> repo = ctx.getBean(repoCls);
+
+            IgniteCache<Object, Serializable> cache = grid(SRV_NAME).cache(CACHE_NAME);
+
+            assertEquals(0, repo.count());
+            assertEquals(0, cache.size());
+
+            int key = 0;
+
+            repo.save(key, "1");
+
+            assertEquals(1, repo.count());
+            assertNotNull(cache.get(key));
+        }
+    }
+
+    /**
+     * Spring Application configuration for repository testing in case {@link IgniteConfiguration} is used
+     * for accessing the cluster.
+     */
+    @Configuration
+    @EnableIgniteRepositories(
+        considerNestedRepositories = true,
+        includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = InvalidCacheNameRepository.class))
+    public static class InvalidCacheNameApplication {
+        /** Ignite configuration bean. */
+        @Bean
+        public IgniteConfiguration igniteConfiguration() {
+            return getIgniteConfiguration(CLI_NAME, true);
+        }
+    }
+
+    /**
+     * Spring Application configuration for repository testing in case {@link IgniteConfiguration} is used
+     * for accessing the cluster.
+     */
+    @Configuration
+    @EnableIgniteRepositories(
+        considerNestedRepositories = true,
+        includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = IgniteConfigRepository.class))
+    public static class IgniteConfigurationApplication {
+        /** Ignite configuration bean. */
+        @Bean
+        public IgniteConfiguration igniteConfiguration() {
+            return getIgniteConfiguration(CLI_NAME, true);
+        }
+    }
+
+    /**
+     * Spring Application configuration for repository testing in case {@link ClientConfiguration} is used
+     * for accessing the cluster.
+     */
+    @Configuration
+    @EnableIgniteRepositories(
+        considerNestedRepositories = true,
+        includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = IgniteClientConfigRepository.class))
+    public static class ClientConfigurationApplication {
+        /** Ignite client configuration bean. */
+        @Bean
+        public ClientConfiguration clientConfiguration() {
+            return new ClientConfiguration().setAddresses(LOCAL_HOST + ':' + CLI_CONN_PORT);
+        }
+    }
+
+    /** Repository for testing configuration approach through {@link IgniteConfiguration}. */
+    @RepositoryConfig(cacheName = "PersonCache", igniteCfg = "igniteConfiguration")
+    public interface IgniteConfigRepository extends IgniteRepository<Object, Serializable> {
+        // No-op.
+    }
+
+    /** Repository for testing repository configuration approach through {@link ClientConfiguration}. */
+    @RepositoryConfig(cacheName = "PersonCache", igniteCfg = "clientConfiguration")
+    public interface IgniteClientConfigRepository extends IgniteRepository<Object, Serializable> {
+        // No-op.
+    }
+
+    /** Repository for testing application behavior in case invalid cache is specified in the repository configuration. */
+    @RepositoryConfig(cacheName = "invalidCache", igniteCfg = "igniteConfiguration")
+    public interface InvalidCacheNameRepository extends IgniteRepository<Object, Serializable> {
+        // No-op.
+    }
+
+    /** */
+    private static IgniteConfiguration getIgniteConfiguration(String name, boolean clientMode) {
+        return new IgniteConfiguration()
+            .setIgniteInstanceName(name)
+            .setClientMode(clientMode)
+            .setLocalHost(LOCAL_HOST)
+            .setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(IP_FINDER))
+            .setClientConnectorConfiguration(new ClientConnectorConfiguration().setPort(CLI_CONN_PORT))
+            .setCacheConfiguration(new CacheConfiguration<>(CACHE_NAME));
+    }
+}
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
index 2122231..7b69075 100644
--- a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
+++ b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
@@ -72,6 +72,12 @@
         return Ignition.start(igniteConfiguration(IGNITE_INSTANCE_ONE, CLI_CONN_PORT));
     }
 
+    /** */
+    @Bean
+    public Ignite igniteSecondServerNode() {
+        return Ignition.start(igniteConfiguration(IGNITE_INSTANCE_TWO, 10801));
+    }
+
     /** Ignite client instance bean with default name. */
     @Bean
     public IgniteClient igniteInstance() {
@@ -82,18 +88,10 @@
     /** Ignite client instance bean with non-default name. */
     @Bean
     public IgniteClient igniteInstanceTWO() {
-        Ignition.start(igniteConfiguration(IGNITE_INSTANCE_TWO, 10801));
-
         return Ignition.startClient(new ClientConfiguration().setAddresses("127.0.0.1:10801"));
     }
 
-    /** Ignite client configuraition bean. */
-    @Bean
-    public ClientConfiguration clientConfiguration() {
-        return new ClientConfiguration().setAddresses("127.0.0.1:" + CLI_CONN_PORT);
-    }
-
-    /** Ingite configuration for server node. */
+    /**  */
     private static IgniteConfiguration igniteConfiguration(String igniteInstanceName, int cliConnPort) {
         return new IgniteConfiguration()
             .setIgniteInstanceName(igniteInstanceName)
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientConfigRepository.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientConfigRepository.java
deleted file mode 100644
index ccbfa08..0000000
--- a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientConfigRepository.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.ignite.springdata.misc;
-
-import java.io.Serializable;
-import org.apache.ignite.configuration.ClientConfiguration;
-import org.apache.ignite.springdata20.repository.IgniteRepository;
-import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
-
-/** Repository for testing repository configurion approach through {@link ClientConfiguration}. */
-@RepositoryConfig(cacheName = "PersonCache", igniteCfg = "clientConfiguration")
-public interface IgniteClientConfigRepository extends IgniteRepository<Object, Serializable> {
-    // No-op.
-}
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData2TestSuite.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData2TestSuite.java
index 6c26078..88879e2 100644
--- a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData2TestSuite.java
+++ b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData2TestSuite.java
@@ -21,6 +21,7 @@
 import org.apache.ignite.springdata.IgniteClientSpringDataCrudSelfTest;
 import org.apache.ignite.springdata.IgniteClientSpringDataQueriesSelfTest;
 import org.apache.ignite.springdata.IgniteSpringDataCompoundKeyTest;
+import org.apache.ignite.springdata.IgniteSpringDataConnectionConfigurationTest;
 import org.apache.ignite.springdata.IgniteSpringDataCrudSelfExpressionTest;
 import org.apache.ignite.springdata.IgniteSpringDataCrudSelfTest;
 import org.apache.ignite.springdata.IgniteSpringDataQueriesSelfTest;
@@ -36,6 +37,7 @@
     IgniteSpringDataQueriesSelfTest.class,
     IgniteSpringDataCrudSelfExpressionTest.class,
     IgniteSpringDataCompoundKeyTest.class,
+    IgniteSpringDataConnectionConfigurationTest.class,
     IgniteClientSpringDataCrudSelfTest.class,
     IgniteClientSpringDataQueriesSelfTest.class,
     IgniteClientSpringDataCompoundKeyTest.class
diff --git a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/EnableIgniteRepositories.java b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/EnableIgniteRepositories.java
index ad465c3..560ee2e 100644
--- a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/EnableIgniteRepositories.java
+++ b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/EnableIgniteRepositories.java
@@ -22,7 +22,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-
 import org.apache.ignite.springdata22.repository.support.IgniteRepositoryFactoryBean;
 import org.apache.ignite.springdata22.repository.support.IgniteRepositoryImpl;
 import org.springframework.beans.factory.FactoryBean;
diff --git a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java
index 4989196..cf6db05 100644
--- a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java
+++ b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java
@@ -18,15 +18,28 @@
 
 import java.util.Collection;
 import java.util.Collections;
+import org.apache.ignite.springdata.proxy.IgniteProxy;
 import org.apache.ignite.springdata22.repository.IgniteRepository;
+import org.apache.ignite.springdata22.repository.support.IgniteProxyFactory;
 import org.apache.ignite.springdata22.repository.support.IgniteRepositoryFactoryBean;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
 import org.springframework.data.repository.config.RepositoryConfigurationExtension;
 import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
+import org.springframework.data.repository.config.RepositoryConfigurationSource;
+
+import static org.springframework.beans.factory.config.ConfigurableBeanFactory.SCOPE_PROTOTYPE;
 
 /**
  * Apache Ignite specific implementation of {@link RepositoryConfigurationExtension}.
  */
 public class IgniteRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
+    /** Name of the auto-registered Ignite proxy factory bean. */
+    private static final String IGNITE_PROXY_FACTORY_BEAN_NAME = "igniteProxyFactory";
+
+    /** Name of the auto-registered Ignite proxy bean prototype. */
+    private static final String IGNITE_PROXY_BEAN_NAME = "igniteProxy";
+
     /** {@inheritDoc} */
     @Override public String getModuleName() {
         return "Apache Ignite";
@@ -46,4 +59,22 @@
     @Override protected Collection<Class<?>> getIdentifyingTypes() {
         return Collections.singleton(IgniteRepository.class);
     }
+
+    /** {@inheritDoc} */
+    @Override public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource cfg) {
+        registerIfNotAlreadyRegistered(
+            () -> BeanDefinitionBuilder.genericBeanDefinition(IgniteProxyFactory.class).getBeanDefinition(),
+            registry,
+            IGNITE_PROXY_FACTORY_BEAN_NAME,
+            cfg);
+
+        registerIfNotAlreadyRegistered(
+            () -> BeanDefinitionBuilder.genericBeanDefinition(IgniteProxy.class)
+                .setScope(SCOPE_PROTOTYPE)
+                .setFactoryMethodOnBean("igniteProxy", IGNITE_PROXY_FACTORY_BEAN_NAME)
+                .getBeanDefinition(),
+            registry,
+            IGNITE_PROXY_BEAN_NAME,
+            cfg);
+    }
 }
diff --git a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteProxyFactory.java b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteProxyFactory.java
new file mode 100644
index 0000000..ac56e00
--- /dev/null
+++ b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteProxyFactory.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.ignite.springdata22.repository.support;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.ignite.springdata.proxy.IgniteProxy;
+import org.apache.ignite.springdata22.repository.config.RepositoryConfig;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.config.BeanExpressionContext;
+import org.springframework.beans.factory.config.BeanExpressionResolver;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.expression.StandardBeanExpressionResolver;
+
+import static org.apache.ignite.springdata22.repository.support.IgniteRepositoryFactory.getRepositoryConfiguration;
+
+/**
+ * Represents factory for obtaining instances of {@link IgniteProxy} that provide client-independent connection to the
+ * Ignite cluster.
+ */
+public class IgniteProxyFactory implements ApplicationContextAware, DisposableBean {
+    /** Spring application expression resolver. */
+    private final BeanExpressionResolver expressionResolver = new StandardBeanExpressionResolver();
+
+    /** Repositories associated with Ignite proxy. */
+    private final Map<Class<?>, IgniteProxy> igniteProxies = new ConcurrentHashMap<>();
+
+    /** Spring application context. */
+    private ApplicationContext ctx;
+
+    /** Spring application bean expression context. */
+    private BeanExpressionContext beanExpressionCtx;
+
+    /**
+     * @param repoInterface The repository interface class for which {@link IgniteProxy} will be created.
+     * @return {@link IgniteProxy} instance.
+     */
+    public IgniteProxy igniteProxy(Class<?> repoInterface) {
+        return igniteProxies.computeIfAbsent(repoInterface, k -> createIgniteProxy(repoInterface));
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setApplicationContext(ApplicationContext ctx) throws BeansException {
+        this.ctx = ctx;
+
+        beanExpressionCtx = new BeanExpressionContext(
+            new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory()),
+            null);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void destroy() throws Exception {
+        Set<IgniteProxy> proxies = new HashSet<>(igniteProxies.values());
+
+        Exception destroyE = null;
+
+        for (IgniteProxy proxy : proxies) {
+            if (proxy instanceof AutoCloseable) {
+                try {
+                    ((AutoCloseable)proxy).close();
+                }
+                catch (Exception e) {
+                    if (destroyE == null)
+                        destroyE = e;
+                    else
+                        destroyE.addSuppressed(e);
+                }
+            }
+        }
+
+        if (destroyE != null)
+            throw destroyE;
+    }
+
+    /**
+     * Creates {@link IgniteProxy} to be used for providing access to the Ignite cluster for specified repository.
+     *
+     * @param repoInterface {@link Class} instance of the repository interface.
+     * @return Instance of {@link IgniteProxy} associated with specified repository.
+     *
+     * @see RepositoryConfig
+     */
+    private IgniteProxy createIgniteProxy(Class<?> repoInterface) {
+        RepositoryConfig repoCfg = getRepositoryConfiguration(repoInterface);
+
+        Object connCfg;
+
+        try {
+            connCfg = ctx.getBean(evaluateExpression(repoCfg.igniteInstance()));
+        }
+        catch (BeansException ex) {
+            try {
+                connCfg = ctx.getBean(evaluateExpression(repoCfg.igniteCfg()));
+            }
+            catch (BeansException ex2) {
+                try {
+                    connCfg = ctx.getBean(evaluateExpression(repoCfg.igniteSpringCfgPath()), String.class);
+                }
+                catch (BeansException ex3) {
+                    throw new IllegalArgumentException("Invalid configuration for repository " +
+                        repoInterface.getName() + ". No beans were found that provide connection configuration to the" +
+                        " Ignite cluster. Check \"igniteInstance\", \"igniteCfg\", \"igniteSpringCfgPath\" parameters" +
+                        " of " + RepositoryConfig.class.getName() + " repository annotation.");
+                }
+            }
+        }
+
+        return IgniteProxy.of(connCfg);
+    }
+
+    /**
+     * Evaluates the SpEL expression.
+     *
+     * @param spelExpression SpEL expression
+     * @return The result of evaluation of the SpEL expression.
+     */
+    private String evaluateExpression(String spelExpression) {
+        return (String)expressionResolver.evaluate(spelExpression, beanExpressionCtx);
+    }
+}
diff --git a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactory.java b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactory.java
index a9c7ad2..4494c14 100644
--- a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactory.java
+++ b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactory.java
@@ -16,27 +16,15 @@
  */
 package org.apache.ignite.springdata22.repository.support;
 
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Optional;
-import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteException;
-import org.apache.ignite.Ignition;
-import org.apache.ignite.client.IgniteClient;
-import org.apache.ignite.configuration.ClientConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.springdata.proxy.IgniteCacheProxy;
 import org.apache.ignite.springdata.proxy.IgniteProxy;
-import org.apache.ignite.springdata.proxy.IgniteProxyImpl;
-import org.apache.ignite.springdata.proxy.IgniteClientProxy;
-import org.apache.ignite.springdata22.repository.IgniteRepository;
 import org.apache.ignite.springdata22.repository.config.DynamicQueryConfig;
 import org.apache.ignite.springdata22.repository.config.Query;
 import org.apache.ignite.springdata22.repository.config.RepositoryConfig;
 import org.apache.ignite.springdata22.repository.query.IgniteQuery;
 import org.apache.ignite.springdata22.repository.query.IgniteQueryGenerator;
 import org.apache.ignite.springdata22.repository.query.IgniteRepositoryQuery;
-import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.config.BeanExpressionContext;
 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 import org.springframework.context.ApplicationContext;
@@ -62,85 +50,44 @@
  * @author Manuel Núñez (manuel.nunez@hawkore.com)
  */
 public class IgniteRepositoryFactory extends RepositoryFactorySupport {
-    /** Spring application context */
-    private final ApplicationContext ctx;
-
-    /** Spring application bean factory */
-    private final DefaultListableBeanFactory beanFactory;
-
     /** Spring application expression resolver */
     private final StandardBeanExpressionResolver resolver = new StandardBeanExpressionResolver();
 
     /** Spring application bean expression context */
     private final BeanExpressionContext beanExpressionContext;
 
-    /** Mapping of a repository to a cache. */
-    private final Map<Class<?>, String> repoToCache = new HashMap<>();
+    /** Ignite cache proxy instance associated with the current repository. */
+    private final IgniteCacheProxy<?, ?> cache;
 
-    /** Mapping of a repository to a ignite instance. */
-    private final Map<Class<?>, IgniteProxy> repoToIgnite = new HashMap<>();
+    /** Ignite proxy instance associated with the current repository. */
+    private final IgniteProxy ignite;
 
     /**
-     * Creates the factory with initialized {@link Ignite} instance.
-     *
-     * @param ctx the ctx
+     * @param ctx Spring Application context.
+     * @param repoInterface Repository interface.
      */
-    public IgniteRepositoryFactory(ApplicationContext ctx) {
-        this.ctx = ctx;
+    public IgniteRepositoryFactory(ApplicationContext ctx, Class<?> repoInterface) {
+        ignite = ctx.getBean(IgniteProxy.class, repoInterface);
 
-        beanFactory = new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory());
+        beanExpressionContext = new BeanExpressionContext(
+            new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory()),
+            null);
 
-        beanExpressionContext = new BeanExpressionContext(beanFactory, null);
-    }
+        RepositoryConfig cfg = getRepositoryConfiguration(repoInterface);
 
-    /** */
-    private IgniteProxy igniteForRepoConfig(RepositoryConfig config) {
-        try {
-            Object igniteInstanceBean = ctx.getBean(evaluateExpression(config.igniteInstance()));
+        String cacheName = evaluateExpression(cfg.cacheName());
 
-            if (igniteInstanceBean instanceof Ignite)
-                return new IgniteProxyImpl((Ignite)igniteInstanceBean);
-            else if (igniteInstanceBean instanceof IgniteClient)
-                return new IgniteClientProxy((IgniteClient)igniteInstanceBean);
+        Assert.hasText(cacheName, "Invalid configuration for repository " + repoInterface.getName() +
+            ". Set a name of an Apache Ignite cache using " + RepositoryConfig.class.getName() +
+            " annotation to map this repository to the underlying cache.");
 
-            throw new IllegalStateException("Invalid repository configuration. The Spring Bean corresponding to the" +
-                " \"igniteInstance\" property of repository configuration must be one of the following types: " +
-                Ignite.class.getName() + ", " + IgniteClient.class.getName());
-        }
-        catch (BeansException ex) {
-            try {
-                Object igniteCfgBean = ctx.getBean(evaluateExpression(config.igniteCfg()));
+       cache = cfg.autoCreateCache() ? ignite.getOrCreateCache(cacheName) : ignite.cache(cacheName);
 
-                if (igniteCfgBean instanceof IgniteConfiguration) {
-                    try {
-                        // first try to attach to existing ignite instance
-                        return new IgniteProxyImpl(Ignition.ignite(((IgniteConfiguration)igniteCfgBean).getIgniteInstanceName()));
-                    }
-                    catch (Exception ignored) {
-                        // nop
-                    }
-                    return new IgniteProxyImpl(Ignition.start((IgniteConfiguration)igniteCfgBean));
-                }
-                else if (igniteCfgBean instanceof ClientConfiguration)
-                    return new IgniteClientProxy(Ignition.startClient((ClientConfiguration)igniteCfgBean));
-
-                throw new IllegalStateException("Invalid repository configuration. The Spring Bean corresponding to" +
-                    " the \"igniteCfg\" property of repository configuration must be one of the following types: [" +
-                    IgniteConfiguration.class.getName() + ", " + ClientConfiguration.class.getName() + ']');
-
-            }
-            catch (BeansException ex2) {
-                try {
-                    String igniteSpringCfgPath = evaluateExpression(config.igniteSpringCfgPath());
-                    String path = (String)ctx.getBean(igniteSpringCfgPath);
-                    return new IgniteProxyImpl(Ignition.start(path));
-                }
-                catch (BeansException ex3) {
-                    throw new IgniteException("Failed to initialize Ignite repository factory. No beans required for" +
-                        " repository configuration were found. Check \"igniteInstance\", \"igniteCfg\"," +
-                        " \"igniteSpringCfgPath\" parameters of " + RepositoryConfig.class.getName() + "class.");
-                }
-            }
+        if (cache == null) {
+            throw new IllegalArgumentException(
+                "Cache '" + cacheName + "' not found for repository interface " + repoInterface.getName()
+                    + ". Please, add a cache configuration to ignite configuration"
+                    + " or pass autoCreateCache=true to " + RepositoryConfig.class.getName() + " annotation.");
         }
     }
 
@@ -164,28 +111,6 @@
         return IgniteRepositoryImpl.class;
     }
 
-    /** {@inheritDoc} */
-    @Override protected synchronized RepositoryMetadata getRepositoryMetadata(Class<?> repoItf) {
-        Assert.notNull(repoItf, "Repository interface must be set.");
-        Assert.isAssignable(IgniteRepository.class, repoItf, "Repository must implement IgniteRepository interface.");
-
-        RepositoryConfig annotation = repoItf.getAnnotation(RepositoryConfig.class);
-
-        Assert.notNull(annotation, "Set a name of an Apache Ignite cache using @RepositoryConfig annotation to map "
-            + "this repository to the underlying cache.");
-
-        Assert.hasText(annotation.cacheName(), "Set a name of an Apache Ignite cache using @RepositoryConfig "
-            + "annotation to map this repository to the underlying cache.");
-
-        String cacheName = evaluateExpression(annotation.cacheName());
-
-        repoToCache.put(repoItf, cacheName);
-
-        repoToIgnite.put(repoItf, igniteForRepoConfig(annotation));
-
-        return super.getRepositoryMetadata(repoItf);
-    }
-
     /**
      * Evaluate the SpEL expression
      *
@@ -196,33 +121,9 @@
         return (String)resolver.evaluate(spelExpression, beanExpressionContext);
     }
 
-    /** Control underlying cache creation to avoid cache creation by mistake */
-    private IgniteCacheProxy<?, ?> getRepositoryCache(Class<?> repoIf) {
-        IgniteProxy ignite = repoToIgnite.get(repoIf);
-
-        RepositoryConfig config = repoIf.getAnnotation(RepositoryConfig.class);
-
-        String cacheName = repoToCache.get(repoIf);
-
-        IgniteCacheProxy<?, ?> c = config.autoCreateCache() ? ignite.getOrCreateCache(cacheName) : ignite.cache(cacheName);
-
-        if (c == null) {
-            throw new IllegalStateException(
-                "Cache '" + cacheName + "' not found for repository interface " + repoIf.getName()
-                    + ". Please, add a cache configuration to ignite configuration"
-                    + " or pass autoCreateCache=true to org.apache.ignite.springdata22"
-                    + ".repository.config.RepositoryConfig annotation.");
-        }
-
-        return c;
-    }
-
     /** {@inheritDoc} */
     @Override protected Object getTargetRepository(RepositoryInformation metadata) {
-        IgniteProxy ignite = repoToIgnite.get(metadata.getRepositoryInterface());
-
-        return getTargetRepositoryViaReflection(metadata, ignite,
-            getRepositoryCache(metadata.getRepositoryInterface()));
+        return getTargetRepositoryViaReflection(metadata, ignite, cache);
     }
 
     /** {@inheritDoc} */
@@ -243,8 +144,7 @@
                     annotation.textQuery(), false, IgniteQueryGenerator.getOptions(mtd)) : null;
 
                 if (key != QueryLookupStrategy.Key.CREATE) {
-                    return new IgniteRepositoryQuery(metadata, query, mtd, factory,
-                        getRepositoryCache(metadata.getRepositoryInterface()),
+                    return new IgniteRepositoryQuery(metadata, query, mtd, factory, cache,
                         annotatedIgniteQuery ? DynamicQueryConfig.fromQueryAnnotation(annotation) : null,
                         evaluationContextProvider);
                 }
@@ -256,9 +156,8 @@
                     + ".config.Query annotation.");
             }
 
-            return new IgniteRepositoryQuery(metadata, IgniteQueryGenerator.generateSql(mtd, metadata), mtd,
-                factory, getRepositoryCache(metadata.getRepositoryInterface()),
-                DynamicQueryConfig.fromQueryAnnotation(annotation), evaluationContextProvider);
+            return new IgniteRepositoryQuery(metadata, IgniteQueryGenerator.generateSql(mtd, metadata), mtd, factory,
+                cache, DynamicQueryConfig.fromQueryAnnotation(annotation), evaluationContextProvider);
         });
     }
 
@@ -290,4 +189,18 @@
             // insert
             qryUpperCase.matches("^\\s*INSERT\\b.*");
     }
+
+    /**
+     * @return Configuration of the specified repository.
+     * @throws IllegalArgumentException If no configuration is specified.
+     * @see RepositoryConfig
+     */
+    static RepositoryConfig getRepositoryConfiguration(Class<?> repoInterface) {
+        RepositoryConfig cfg = repoInterface.getAnnotation(RepositoryConfig.class);
+
+        Assert.notNull(cfg, "Invalid configuration for repository " + repoInterface.getName() + ". " +
+            RepositoryConfig.class.getName() + " annotation must be specified for each repository interface.");
+
+        return cfg;
+    }
 }
diff --git a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactoryBean.java b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactoryBean.java
index ece9f31..9d6794d 100644
--- a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactoryBean.java
+++ b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactoryBean.java
@@ -62,6 +62,6 @@
 
     /** {@inheritDoc} */
     @Override protected RepositoryFactorySupport createRepositoryFactory() {
-        return new IgniteRepositoryFactory(ctx);
+        return new IgniteRepositoryFactory(ctx, getObjectType());
     }
 }
diff --git a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryImpl.java b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryImpl.java
index de0573b..d91da58 100644
--- a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryImpl.java
+++ b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryImpl.java
@@ -49,7 +49,7 @@
  */
 @Conditional(ConditionFalse.class)
 public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRepository<V, K> {
-    /** Error message indicating that operation is spported only if {@link Ignite} instance is used to access the cluster. */
+    /** Error message indicating that operation is supported only if {@link Ignite} instance is used to access the cluster. */
     private static final String UNSUPPORTED_ERR_MSG = "Current operation is supported only if Ignite node instance is" +
         " used to access the Ignite cluster. See " + RepositoryConfig.class.getName() + "#igniteInstance.";
 
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java
index 6dcadb8..ec2e7ca 100644
--- a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java
+++ b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.springdata;
 
+import org.apache.ignite.Ignite;
 import org.apache.ignite.springdata.compoundkey.CityRepository;
 import org.apache.ignite.springdata.misc.IgniteClientApplicationConfiguration;
 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -32,4 +33,9 @@
 
         repo = ctx.getBean(CityRepository.class);
     }
+
+    /** {@inheritDoc} */
+    @Override protected Ignite ignite() {
+        return ctx.getBean("igniteServerNode", Ignite.class);
+    }
 }
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
index d1597d9..226ee9b 100644
--- a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
+++ b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
@@ -18,13 +18,9 @@
 package org.apache.ignite.springdata;
 
 import org.apache.ignite.client.IgniteClient;
-import org.apache.ignite.configuration.ClientConfiguration;
 import org.apache.ignite.springdata.misc.IgniteClientApplicationConfiguration;
-import org.apache.ignite.springdata.misc.IgniteClientConfigRepository;
 import org.apache.ignite.springdata.misc.PersonRepository;
-import org.apache.ignite.springdata22.repository.support.IgniteRepositoryFactory;
 import org.apache.ignite.testframework.GridTestUtils;
-import org.junit.Test;
 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
 /** Tests Spring Data CRUD operation when thin client is used for accessing the Ignite cluster. */
@@ -47,16 +43,4 @@
                 " org.apache.ignite.springdata.misc.PersonRepository#textQueryByFirstNameWithProjectionNamedParameter" +
                 " method configuration or use Ignite node instance to connect to the Ignite cluster.");
     }
-
-    /**
-     * Tests repository configuration in case {@link ClientConfiguration} is used to provide access to Ignite cluster.
-     */
-    @Test
-    public void testRepositoryWithClientConfiguration() {
-        IgniteRepositoryFactory factory = new IgniteRepositoryFactory(ctx);
-
-        IgniteClientConfigRepository repo = factory.getRepository(IgniteClientConfigRepository.class);
-
-        assertTrue(repo.count() > 0);
-    }
 }
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java
index 06e0c28..3a65f29 100644
--- a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java
+++ b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java
@@ -98,7 +98,7 @@
 
     /** load data*/
     public void loadData() throws Exception {
-        Ignite ignite = ctx.getBean(Ignite.class);
+        Ignite ignite = ignite();
 
         if (ignite.cacheNames().contains(CACHE_NAME))
             ignite.destroyCache(CACHE_NAME);
@@ -124,4 +124,9 @@
         assertEquals(AFG_COUNT, repo.findByCountryCode(AFG).size());
         assertEquals(QUANDAHAR, repo.findById(QUANDAHAR_ID));
     }
+
+    /** */
+    protected Ignite ignite() {
+        return ctx.getBean(Ignite.class);
+    }
 }
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java
new file mode 100644
index 0000000..68c421a
--- /dev/null
+++ b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.ignite.springdata;
+
+import java.io.Serializable;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.ClientConfiguration;
+import org.apache.ignite.configuration.ClientConnectorConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.springdata22.repository.IgniteRepository;
+import org.apache.ignite.springdata22.repository.config.EnableIgniteRepositories;
+import org.apache.ignite.springdata22.repository.config.RepositoryConfig;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.context.annotation.Configuration;
+
+import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause;
+import static org.springframework.context.annotation.FilterType.ASSIGNABLE_TYPE;
+
+/** Tests Spring Data repository cluster connection configurations. */
+public class IgniteSpringDataConnectionConfigurationTest extends GridCommonAbstractTest {
+    /** */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+    /** */
+    private static final String CACHE_NAME = "PersonCache";
+
+    /** */
+    private static final int CLI_CONN_PORT = 10810;
+
+    /** */
+    private static final String CLI_NAME = "cli-node";
+
+    /** */
+    private static final String SRV_NAME = "srv-node";
+
+    /** */
+    private static final String LOCAL_HOST = "127.0.0.1";
+
+    /** Tests repository configuration in case {@link IgniteConfiguration} is used to access the Ignite cluster. */
+    @Test
+    public void testRepositoryWithIgniteConfiguration() {
+        checkRepositoryConfiguration(IgniteConfigurationApplication.class, IgniteConfigRepository.class);
+
+        assertClientNodeIsStopped();
+    }
+
+    /** Tests repository configuration in case {@link ClientConfiguration} is used to access the Ignite cluster. */
+    @Test
+    public void testRepositoryWithClientConfiguration() {
+        checkRepositoryConfiguration(ClientConfigurationApplication.class, IgniteClientConfigRepository.class);
+    }
+
+    /**
+     * Tests repository configuration in case {@link IgniteConfiguration} that refers to existing Ignite node instance
+     * used to access the Ignite cluster.
+     */
+    @Test
+    public void testRepositoryWithExistingIgniteInstance() throws Exception {
+        try (Ignite ignored = startGrid(getIgniteConfiguration(CLI_NAME, true))) {
+            checkRepositoryConfiguration(IgniteConfigurationApplication.class, IgniteConfigRepository.class);
+
+            assertNotNull(Ignition.ignite(CLI_NAME));
+        }
+    }
+
+    /** Tests repository configuration in case specified cache name is invalid. */
+    @Test
+    public void testRepositoryWithInvalidCacheNameConfiguration() {
+        try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
+            ctx.register(InvalidCacheNameApplication.class);
+
+            assertThrowsAnyCause(log,
+                () -> {
+                    ctx.refresh();
+
+                    return null;
+                },
+                IllegalArgumentException.class,
+                "Cache 'invalidCache' not found for repository interface" +
+                    " org.apache.ignite.springdata.IgniteSpringDataConnectionConfigurationTest$InvalidCacheNameRepository." +
+                    " Please, add a cache configuration to ignite configuration or pass autoCreateCache=true to" +
+                    " org.apache.ignite.springdata22.repository.config.RepositoryConfig annotation.");
+        }
+
+        assertClientNodeIsStopped();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        grid(SRV_NAME).cache(CACHE_NAME).clear();
+    }
+
+    /** */
+    private void assertClientNodeIsStopped() {
+        assertFalse(Ignition.allGrids().stream().map(Ignite::name).anyMatch(CLI_NAME::equals));
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        startGrid(getIgniteConfiguration(SRV_NAME, false));
+    }
+
+    /**
+     * Checks that repository created based on specified Spring application configuration is properly initialized and
+     * got access to the Ignite cluster.
+     */
+    private void checkRepositoryConfiguration(
+        Class<?> cfgCls,
+        Class<? extends IgniteRepository<Object, Serializable>> repoCls
+    ) {
+        try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
+            ctx.register(cfgCls);
+            ctx.refresh();
+
+            IgniteRepository<Object, Serializable> repo = ctx.getBean(repoCls);
+
+            IgniteCache<Object, Serializable> cache = grid(SRV_NAME).cache(CACHE_NAME);
+
+            assertEquals(0, repo.count());
+            assertEquals(0, cache.size());
+
+            int key = 0;
+
+            repo.save(key, "1");
+
+            assertEquals(1, repo.count());
+            assertNotNull(cache.get(key));
+        }
+    }
+
+    /**
+     * Spring Application configuration for repository testing in case {@link IgniteConfiguration} is used
+     * for accessing the cluster.
+     */
+    @Configuration
+    @EnableIgniteRepositories(
+        considerNestedRepositories = true,
+        includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = InvalidCacheNameRepository.class))
+    public static class InvalidCacheNameApplication {
+        /** Ignite configuration bean. */
+        @Bean
+        public IgniteConfiguration igniteConfiguration() {
+            return getIgniteConfiguration(CLI_NAME, true);
+        }
+    }
+
+    /**
+     * Spring Application configuration for repository testing in case {@link IgniteConfiguration} is used
+     * for accessing the cluster.
+     */
+    @Configuration
+    @EnableIgniteRepositories(
+        considerNestedRepositories = true,
+        includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = IgniteConfigRepository.class))
+    public static class IgniteConfigurationApplication {
+        /** Ignite configuration bean. */
+        @Bean
+        public IgniteConfiguration igniteConfiguration() {
+            return getIgniteConfiguration(CLI_NAME, true);
+        }
+    }
+
+    /**
+     * Spring Application configuration for repository testing in case {@link ClientConfiguration} is used
+     * for accessing the cluster.
+     */
+    @Configuration
+    @EnableIgniteRepositories(
+        considerNestedRepositories = true,
+        includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = IgniteClientConfigRepository.class))
+    public static class ClientConfigurationApplication {
+        /** Ignite client configuration bean. */
+        @Bean
+        public ClientConfiguration clientConfiguration() {
+            return new ClientConfiguration().setAddresses(LOCAL_HOST + ':' + CLI_CONN_PORT);
+        }
+    }
+
+    /** Repository for testing configuration approach through {@link IgniteConfiguration}. */
+    @RepositoryConfig(cacheName = "PersonCache", igniteCfg = "igniteConfiguration")
+    public interface IgniteConfigRepository extends IgniteRepository<Object, Serializable> {
+        // No-op.
+    }
+
+    /** Repository for testing repository configuration approach through {@link ClientConfiguration}. */
+    @RepositoryConfig(cacheName = "PersonCache", igniteCfg = "clientConfiguration")
+    public interface IgniteClientConfigRepository extends IgniteRepository<Object, Serializable> {
+        // No-op.
+    }
+
+    /** Repository for testing application behavior in case invalid cache is specified in the repository configuration. */
+    @RepositoryConfig(cacheName = "invalidCache", igniteCfg = "igniteConfiguration")
+    public interface InvalidCacheNameRepository extends IgniteRepository<Object, Serializable> {
+        // No-op.
+    }
+
+    /** */
+    private static IgniteConfiguration getIgniteConfiguration(String name, boolean clientMode) {
+        return new IgniteConfiguration()
+            .setIgniteInstanceName(name)
+            .setClientMode(clientMode)
+            .setLocalHost(LOCAL_HOST)
+            .setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(IP_FINDER))
+            .setClientConnectorConfiguration(new ClientConnectorConfiguration().setPort(CLI_CONN_PORT))
+            .setCacheConfiguration(new CacheConfiguration<>(CACHE_NAME));
+    }
+}
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
index c5d159a..ad255d0 100644
--- a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
+++ b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
@@ -72,6 +72,12 @@
         return Ignition.start(igniteConfiguration(IGNITE_INSTANCE_ONE, CLI_CONN_PORT));
     }
 
+    /** */
+    @Bean
+    public Ignite igniteSecondServerNode() {
+        return Ignition.start(igniteConfiguration(IGNITE_INSTANCE_TWO, 10801));
+    }
+
     /** Ignite client instance bean with default name. */
     @Bean
     public IgniteClient igniteInstance() {
@@ -82,18 +88,10 @@
     /** Ignite client instance bean with non-default name. */
     @Bean
     public IgniteClient igniteInstanceTWO() {
-        Ignition.start(igniteConfiguration(IGNITE_INSTANCE_TWO, 10801));
-
         return Ignition.startClient(new ClientConfiguration().setAddresses("127.0.0.1:10801"));
     }
 
-    /** Ignite client configuraition bean. */
-    @Bean
-    public ClientConfiguration clientConfiguration() {
-        return new ClientConfiguration().setAddresses("127.0.0.1:" + CLI_CONN_PORT);
-    }
-
-    /** Ingite configuration for server node. */
+    /** */
     private static IgniteConfiguration igniteConfiguration(String igniteInstanceName, int cliConnPort) {
         return new IgniteConfiguration()
             .setIgniteInstanceName(igniteInstanceName)
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientConfigRepository.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientConfigRepository.java
deleted file mode 100644
index 23a9d8e..0000000
--- a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientConfigRepository.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.ignite.springdata.misc;
-
-import java.io.Serializable;
-import org.apache.ignite.configuration.ClientConfiguration;
-import org.apache.ignite.springdata22.repository.IgniteRepository;
-import org.apache.ignite.springdata22.repository.config.RepositoryConfig;
-
-/** Repository for testing repository configurion approach through {@link ClientConfiguration}. */
-@RepositoryConfig(cacheName = "PersonCache", igniteCfg = "clientConfiguration")
-public interface IgniteClientConfigRepository extends IgniteRepository<Object, Serializable> {
-    // No-op.
-}
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData22TestSuite.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData22TestSuite.java
index 4363f74..899118b 100644
--- a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData22TestSuite.java
+++ b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData22TestSuite.java
@@ -21,6 +21,7 @@
 import org.apache.ignite.springdata.IgniteClientSpringDataCrudSelfTest;
 import org.apache.ignite.springdata.IgniteClientSpringDataQueriesSelfTest;
 import org.apache.ignite.springdata.IgniteSpringDataCompoundKeyTest;
+import org.apache.ignite.springdata.IgniteSpringDataConnectionConfigurationTest;
 import org.apache.ignite.springdata.IgniteSpringDataCrudSelfExpressionTest;
 import org.apache.ignite.springdata.IgniteSpringDataCrudSelfTest;
 import org.apache.ignite.springdata.IgniteSpringDataQueriesSelfTest;
@@ -36,6 +37,7 @@
     IgniteSpringDataQueriesSelfTest.class,
     IgniteSpringDataCrudSelfExpressionTest.class,
     IgniteSpringDataCompoundKeyTest.class,
+    IgniteSpringDataConnectionConfigurationTest.class,
     IgniteClientSpringDataCrudSelfTest.class,
     IgniteClientSpringDataQueriesSelfTest.class,
     IgniteClientSpringDataCompoundKeyTest.class
diff --git a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/ClosableIgniteClientProxy.java b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/ClosableIgniteClientProxy.java
new file mode 100644
index 0000000..73e1681
--- /dev/null
+++ b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/ClosableIgniteClientProxy.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.ignite.springdata.proxy;
+
+import org.apache.ignite.client.IgniteClient;
+
+/** Extends {@link IgniteClientProxy} with the ability to close underlying thin client instance. */
+public class ClosableIgniteClientProxy extends IgniteClientProxy implements AutoCloseable {
+    /**
+     * @param cli Ignite client instance.
+     */
+    public ClosableIgniteClientProxy(IgniteClient cli) {
+        super(cli);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void close() throws Exception {
+        cli.close();
+    }
+}
diff --git a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/ClosableIgniteProxyImpl.java b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/ClosableIgniteProxyImpl.java
new file mode 100644
index 0000000..79807e4
--- /dev/null
+++ b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/ClosableIgniteProxyImpl.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.ignite.springdata.proxy;
+
+import org.apache.ignite.Ignite;
+
+/** Extends {@link IgniteProxyImpl} with the ability to close underlying Ignite instance. */
+public class ClosableIgniteProxyImpl extends IgniteProxyImpl implements AutoCloseable {
+    /**
+     * @param ignite Ignite instance.
+     */
+    public ClosableIgniteProxyImpl(Ignite ignite) {
+        super(ignite);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void close() throws Exception {
+        ignite.close();
+    }
+}
diff --git a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteCacheProxy.java b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteCacheProxy.java
index ac29eb4..3c5c4d2 100644
--- a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteCacheProxy.java
+++ b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteCacheProxy.java
@@ -26,7 +26,7 @@
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.client.ClientCache;
 
-/** Reperesents Ignite cache operations required by Spring Data. */
+/** Represents Ignite cache operations required by Spring Data. */
 public interface IgniteCacheProxy<K, V> extends Iterable<Cache.Entry<K, V>> {
     /**
      * Gets an entry from the cache.
diff --git a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteClientProxy.java b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteClientProxy.java
index ae50823..00dc42e 100644
--- a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteClientProxy.java
+++ b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteClientProxy.java
@@ -17,12 +17,13 @@
 
 package org.apache.ignite.springdata.proxy;
 
+import java.util.Objects;
 import org.apache.ignite.client.IgniteClient;
 
 /** Implementation of {@link IgniteProxy} that provides access to Ignite cluster through {@link IgniteClient} instance. */
 public class IgniteClientProxy implements IgniteProxy {
     /** {@link IgniteClient} instance to which operations are delegated.  */
-    private final IgniteClient cli;
+    protected final IgniteClient cli;
 
     /** */
     public IgniteClientProxy(IgniteClient cli) {
@@ -38,4 +39,20 @@
     @Override public <K, V> IgniteCacheProxy<K, V> cache(String name) {
         return new IgniteCacheClientProxy<>(cli.cache(name));
     }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object other) {
+        if (this == other)
+            return true;
+
+        if (other == null || getClass() != other.getClass())
+            return false;
+
+        return Objects.equals(cli, ((IgniteClientProxy)other).cli);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        return cli.hashCode();
+    }
 }
diff --git a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxy.java b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxy.java
index e798274..62e0d5c 100644
--- a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxy.java
+++ b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxy.java
@@ -17,7 +17,13 @@
 
 package org.apache.ignite.springdata.proxy;
 
-/** Reperesents Ignite cluster operations required by Spring Data. */
+import org.apache.ignite.Ignite;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.client.IgniteClient;
+import org.apache.ignite.configuration.ClientConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+
+/** Represents Ignite cluster operations required by Spring Data. */
 public interface IgniteProxy {
     /**
      * Gets existing cache with the given name or creates new one.
@@ -34,4 +40,32 @@
      * @return Cache proxy that provides access to cache with specified name or {@code null} if it doesn't exist.
      */
     public <K, V> IgniteCacheProxy<K, V> cache(String name);
+
+    /**
+     * @param connObj Object that will be used to obtain underlying Ignite client instance to access the Ignite cluster.
+     * @return Ignite proxy instance.
+     */
+    public static IgniteProxy of(Object connObj) {
+        if (connObj instanceof Ignite)
+            return new IgniteProxyImpl((Ignite)connObj);
+        else if (connObj instanceof IgniteConfiguration) {
+            try {
+                return new IgniteProxyImpl(Ignition.ignite(((IgniteConfiguration)connObj).getIgniteInstanceName()));
+            }
+            catch (Exception ignored) {
+                // No-op.
+            }
+
+            return new ClosableIgniteProxyImpl(Ignition.start((IgniteConfiguration)connObj));
+        }
+        else if (connObj instanceof String)
+            return new ClosableIgniteProxyImpl(Ignition.start((String)connObj));
+        else if (connObj instanceof IgniteClient)
+            return new IgniteClientProxy((IgniteClient)connObj);
+        else if (connObj instanceof ClientConfiguration)
+            return new ClosableIgniteClientProxy(Ignition.startClient((ClientConfiguration)connObj));
+
+        throw new IllegalArgumentException(
+            "Object of type " + connObj.getClass().getName() + " can not be used to connect to the Ignite cluster.");
+    }
 }
diff --git a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxyImpl.java b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxyImpl.java
index 96b46a7..85acceb 100644
--- a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxyImpl.java
+++ b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxyImpl.java
@@ -17,12 +17,14 @@
 
 package org.apache.ignite.springdata.proxy;
 
+import java.util.Objects;
 import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
 
 /** Implementation of {@link IgniteProxy} that provides access to Ignite cluster through {@link Ignite} instance. */
 public class IgniteProxyImpl implements IgniteProxy {
     /** {@link Ignite} instance to which operations are delegated. */
-    private final Ignite ignite;
+    protected final Ignite ignite;
 
     /** */
     public IgniteProxyImpl(Ignite ignite) {
@@ -36,11 +38,29 @@
 
     /** {@inheritDoc} */
     @Override public <K, V> IgniteCacheProxy<K, V> cache(String name) {
-        return new IgniteCacheProxyImpl<>(ignite.cache(name));
+        IgniteCache<K, V> cache = ignite.cache(name);
+
+        return cache == null ? null : new IgniteCacheProxyImpl<>(cache);
     }
 
     /** @return {@link Ignite} instance to which operations are delegated. */
     public Ignite delegate() {
         return ignite;
     }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object other) {
+        if (this == other)
+            return true;
+
+        if (other == null || getClass() != other.getClass())
+            return false;
+
+        return Objects.equals(ignite, ((IgniteProxyImpl)other).ignite);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        return ignite.hashCode();
+    }
 }
diff --git a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/config/IgniteRepositoryConfigurationExtension.java b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/config/IgniteRepositoryConfigurationExtension.java
index 630690a..6f21b59 100644
--- a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/config/IgniteRepositoryConfigurationExtension.java
+++ b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/config/IgniteRepositoryConfigurationExtension.java
@@ -19,14 +19,21 @@
 import java.util.Collection;
 import java.util.Collections;
 import org.apache.ignite.springdata.repository.IgniteRepository;
+import org.apache.ignite.springdata.repository.support.IgniteProxyFactory;
 import org.apache.ignite.springdata.repository.support.IgniteRepositoryFactoryBean;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
 import org.springframework.data.repository.config.RepositoryConfigurationExtension;
 import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
+import org.springframework.data.repository.config.RepositoryConfigurationSource;
 
 /**
  * Apache Ignite specific implementation of {@link RepositoryConfigurationExtension}.
  */
 public class IgniteRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
+    /** Name of the auto-registered Ignite proxy factory bean. */
+    private static final String IGNITE_PROXY_FACTORY_BEAN_NAME = "igniteProxyFactory";
+
     /** {@inheritDoc} */
     @Override public String getModuleName() {
         return "Apache Ignite";
@@ -46,4 +53,13 @@
     @Override protected Collection<Class<?>> getIdentifyingTypes() {
         return Collections.<Class<?>>singleton(IgniteRepository.class);
     }
+
+    /** {@inheritDoc} */
+    @Override public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource cfg) {
+        registerIfNotAlreadyRegistered(
+            BeanDefinitionBuilder.genericBeanDefinition(IgniteProxyFactory.class).getBeanDefinition(),
+            registry,
+            IGNITE_PROXY_FACTORY_BEAN_NAME,
+            cfg);
+    }
 }
diff --git a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteProxyFactory.java b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteProxyFactory.java
new file mode 100644
index 0000000..3585287
--- /dev/null
+++ b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteProxyFactory.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.ignite.springdata.repository.support;
+
+import org.apache.ignite.springdata.proxy.IgniteProxy;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.AbstractFactoryBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+/**
+ * Represents factory for obtaining instance of {@link IgniteProxy} that provide client-independent connection to the
+ * Ignite cluster.
+ */
+public class IgniteProxyFactory extends AbstractFactoryBean<IgniteProxy> implements ApplicationContextAware {
+    /** Name of the bean that stores Ignite client instance to access the Ignite cluster. */
+    private static final String IGNITE_INSTANCE_BEAN_NAME = "igniteInstance";
+
+    /** Name of the bean that stores the configuration to instantiate the Ignite client. */
+    private static final String IGNITE_CONFIG_BEAN_NAME = "igniteCfg";
+
+    /** Name of the bean that stores the Spring configuration path to instantiate the Ignite client. */
+    private static final String IGNITE_SPRING_CONFIG_PATH_BEAN_NAME= "igniteSpringCfgPath";
+
+    /** Spring application context. */
+    private ApplicationContext ctx;
+
+    /** {@inheritDoc} */
+    @Override public void setApplicationContext(ApplicationContext ctx) throws BeansException {
+        this.ctx = ctx;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void destroy() throws Exception {
+        Object igniteProxy = getObject();
+
+        if (igniteProxy instanceof AutoCloseable)
+            ((AutoCloseable)igniteProxy).close();
+    }
+
+    /** {@inheritDoc} */
+    @Override public Class<?> getObjectType() {
+        return IgniteProxy.class;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteProxy createInstance() {
+        Object connCfg;
+
+        try {
+            connCfg = ctx.getBean(IGNITE_INSTANCE_BEAN_NAME);
+        }
+        catch (BeansException ex) {
+            try {
+                connCfg = ctx.getBean(IGNITE_CONFIG_BEAN_NAME);
+            }
+            catch (BeansException ex2) {
+                try {
+                    connCfg = ctx.getBean(IGNITE_SPRING_CONFIG_PATH_BEAN_NAME, String.class);
+                }
+                catch (BeansException ex3) {
+                    throw new IllegalArgumentException("No beans were found that provide connection configuration to" +
+                        " the Ignite cluster. One of the beans with the following names is required : \"" +
+                        IGNITE_INSTANCE_BEAN_NAME + "\", \"" + IGNITE_CONFIG_BEAN_NAME + "\" or \"" +
+                        IGNITE_SPRING_CONFIG_PATH_BEAN_NAME + "\".");
+                }
+            }
+        }
+
+        return IgniteProxy.of(connCfg);
+    }
+}
diff --git a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactory.java b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactory.java
index 5fc0ba2..8649733 100644
--- a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactory.java
+++ b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactory.java
@@ -18,17 +18,8 @@
 
 import java.io.Serializable;
 import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-import org.apache.ignite.Ignite;
-import org.apache.ignite.Ignition;
-import org.apache.ignite.client.IgniteClient;
-import org.apache.ignite.configuration.ClientConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.springdata.proxy.IgniteCacheProxy;
 import org.apache.ignite.springdata.proxy.IgniteProxy;
-import org.apache.ignite.springdata.proxy.IgniteProxyImpl;
-import org.apache.ignite.springdata.proxy.IgniteClientProxy;
-import org.apache.ignite.springdata.repository.IgniteRepository;
 import org.apache.ignite.springdata.repository.config.Query;
 import org.apache.ignite.springdata.repository.config.RepositoryConfig;
 import org.apache.ignite.springdata.repository.query.IgniteQuery;
@@ -51,52 +42,28 @@
  * Crucial for spring-data functionality class. Create proxies for repositories.
  */
 public class IgniteRepositoryFactory extends RepositoryFactorySupport {
-    /** Ignite instance */
-    private IgniteProxy ignite;
-
-    /** Mapping of a repository to a cache. */
-    private final Map<Class<?>, String> repoToCache = new HashMap<>();
+    /** Ignite cache proxy instance associated with the current repository. */
+    private final IgniteCacheProxy<?, ?> cache;
 
     /**
-     * Creates the factory with initialized {@link Ignite} instance.
+     * Creates the factory with initialized {@link IgniteProxy} instance.
      *
-     * @param ignite
+     * @param ignite Ignite proxy instance.
+     * @param repoInterface Repository interface.
      */
-    public IgniteRepositoryFactory(Ignite ignite) {
-        this.ignite = new IgniteProxyImpl(ignite);
-    }
+    public IgniteRepositoryFactory(IgniteProxy ignite, Class<?> repoInterface) {
+        RepositoryConfig cfg = repoInterface.getAnnotation(RepositoryConfig.class);
 
-    /** Creates the factory with initialized {@link IgniteClient} instance. */
-    public IgniteRepositoryFactory(IgniteClient cli) {
-        ignite = new IgniteClientProxy(cli);
-    }
+        Assert.notNull(cfg, "Invalid repository configuration [name=" + repoInterface.getName() + "]. " +
+            RepositoryConfig.class.getName() + " annotation must be specified for each repository interface.");
 
-    /**
-     * Initializes the factory with provided {@link IgniteConfiguration} that is used to start up an underlying
-     * {@link Ignite} instance.
-     *
-     * @param cfg Ignite configuration.
-     */
-    public IgniteRepositoryFactory(IgniteConfiguration cfg) {
-        this.ignite = new IgniteProxyImpl(Ignition.start(cfg));
-    }
+        String cacheName = cfg.cacheName();
 
-    /**
-     * Initializes the factory with provided {@link ClientConfiguration} that is used to start up an underlying
-     * {@link IgniteClient} instance.
-     */
-    public IgniteRepositoryFactory(ClientConfiguration cfg) {
-        this.ignite = new IgniteClientProxy(Ignition.startClient(cfg));
-    }
+        Assert.hasText(cacheName, "Invalid repository configuration [name=" + repoInterface.getName() + "]." +
+            " Set a name of an Apache Ignite cache using " + RepositoryConfig.class.getName() +
+            " annotation to map this repository to the underlying cache.");
 
-    /**
-     * Initializes the factory with provided a configuration under {@code springCfgPath} that is used to start up
-     * an underlying {@link Ignite} instance.
-     *
-     * @param springCfgPath A path to Ignite configuration.
-     */
-    public IgniteRepositoryFactory(String springCfgPath) {
-        this.ignite = new IgniteProxyImpl(Ignition.start(springCfgPath));
+        cache = ignite.getOrCreateCache(cacheName);
     }
 
     /** {@inheritDoc} */
@@ -118,27 +85,8 @@
     }
 
     /** {@inheritDoc} */
-    @Override protected RepositoryMetadata getRepositoryMetadata(Class<?> repoItf) {
-        Assert.notNull(repoItf, "Repository interface must be set.");
-        Assert.isAssignable(IgniteRepository.class, repoItf, "Repository must implement IgniteRepository interface.");
-
-        RepositoryConfig annotation = repoItf.getAnnotation(RepositoryConfig.class);
-
-        Assert.notNull(annotation, "Set a name of an Apache Ignite cache using @RepositoryConfig annotation to map " +
-            "this repository to the underlying cache.");
-
-        Assert.hasText(annotation.cacheName(), "Set a name of an Apache Ignite cache using @RepositoryConfig " +
-            "annotation to map this repository to the underlying cache.");
-
-        repoToCache.put(repoItf, annotation.cacheName());
-
-        return super.getRepositoryMetadata(repoItf);
-    }
-
-    /** {@inheritDoc} */
     @Override protected Object getTargetRepository(RepositoryInformation metadata) {
-        return getTargetRepositoryViaReflection(metadata,
-            ignite.getOrCreateCache(repoToCache.get(metadata.getRepositoryInterface())));
+        return getTargetRepositoryViaReflection(metadata, cache);
     }
 
     /** {@inheritDoc} */
@@ -157,7 +105,7 @@
                     if (key != Key.CREATE && StringUtils.hasText(qryStr))
                         return new IgniteRepositoryQuery(metadata,
                             new IgniteQuery(qryStr, isFieldQuery(qryStr), IgniteQueryGenerator.getOptions(mtd)),
-                            mtd, factory, ignite.getOrCreateCache(repoToCache.get(metadata.getRepositoryInterface())));
+                            mtd, factory, cache);
                 }
 
                 if (key == QueryLookupStrategy.Key.USE_DECLARED_QUERY)
@@ -165,7 +113,7 @@
                         "a query string via org.apache.ignite.springdata.repository.config.Query annotation.");
 
                 return new IgniteRepositoryQuery(metadata, IgniteQueryGenerator.generateSql(mtd, metadata), mtd,
-                    factory, ignite.getOrCreateCache(repoToCache.get(metadata.getRepositoryInterface())));
+                    factory, cache);
             }
         };
     }
diff --git a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactoryBean.java b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactoryBean.java
index 71200c2..3028cea 100644
--- a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactoryBean.java
+++ b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactoryBean.java
@@ -19,14 +19,12 @@
 
 import java.io.Serializable;
 import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteException;
 import org.apache.ignite.client.IgniteClient;
 import org.apache.ignite.configuration.ClientConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.springdata.proxy.IgniteProxy;
 import org.apache.ignite.springdata.repository.IgniteRepository;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.repository.Repository;
 import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
 import org.springframework.data.repository.core.support.RepositoryFactorySupport;
@@ -47,9 +45,10 @@
  * @param <ID> Domain object key, super expects {@link Serializable}.
  */
 public class IgniteRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable>
-    extends RepositoryFactoryBeanSupport<T, S, ID> implements ApplicationContextAware {
-    /** Application context. */
-    private ApplicationContext ctx;
+    extends RepositoryFactoryBeanSupport<T, S, ID> {
+    /** Ignite proxy. */
+    @Autowired
+    private IgniteProxy ignite;
 
     /**
      * @param repositoryInterface Repository interface.
@@ -59,50 +58,8 @@
     }
 
     /** {@inheritDoc} */
-    @Override public void setApplicationContext(ApplicationContext context) throws BeansException {
-        this.ctx = context;
-    }
-
-    /** {@inheritDoc} */
     @Override protected RepositoryFactorySupport createRepositoryFactory() {
-        try {
-            Object igniteInstanceBean = ctx.getBean("igniteInstance");
-
-            if (igniteInstanceBean instanceof Ignite)
-                return new IgniteRepositoryFactory((Ignite)igniteInstanceBean);
-            else if (igniteInstanceBean instanceof IgniteClient)
-                return new IgniteRepositoryFactory((IgniteClient)igniteInstanceBean);
-
-            throw new IllegalStateException("Invalid repository configuration. The Spring Bean corresponding to the" +
-                " \"igniteInstance\" property of repository configuration must be one of the following types: " +
-                Ignite.class.getName() + ", " + IgniteClient.class.getName());
-        }
-        catch (BeansException ex) {
-            try {
-                Object igniteCfgBean = ctx.getBean("igniteCfg");
-
-                if (igniteCfgBean instanceof IgniteConfiguration)
-                    return new IgniteRepositoryFactory((IgniteConfiguration)igniteCfgBean);
-                else if (igniteCfgBean instanceof ClientConfiguration)
-                    return new IgniteRepositoryFactory((ClientConfiguration)igniteCfgBean);
-
-                throw new IllegalStateException("Invalid repository configuration. The Spring Bean corresponding to" +
-                    " the \"igniteCfg\" property of repository configuration must be one of the following types: [" +
-                    IgniteConfiguration.class.getName() + ", " + ClientConfiguration.class.getName() + ']');
-            }
-            catch (BeansException ex2) {
-                try {
-                    String path = (String)ctx.getBean("igniteSpringCfgPath");
-
-                    return new IgniteRepositoryFactory(path);
-                }
-                catch (BeansException ex3) {
-                    throw new IgniteException("Failed to initialize Ignite repository factory. One of the following" +
-                        " beans must be defined in application configuration: \"igniteInstance\", \"igniteCfg\"," +
-                        " \"igniteSpringCfgPath\".");
-                }
-            }
-        }
+        return new IgniteRepositoryFactory(ignite, getObjectType());
     }
 }
 
diff --git a/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java b/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
index a887ad8..751eb09 100644
--- a/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
+++ b/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
@@ -17,18 +17,11 @@
 
 package org.apache.ignite.springdata;
 
-import org.apache.ignite.configuration.ClientConfiguration;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.springdata.misc.IgniteClientApplicationConfiguration;
 import org.apache.ignite.springdata.misc.PersonRepository;
 import org.apache.ignite.springdata.misc.PersonRepositoryWithCompoundKey;
-import org.apache.ignite.springdata.repository.config.EnableIgniteRepositories;
-import org.junit.Test;
 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import static org.apache.ignite.springdata.compoundkey.CompoundKeyApplicationConfiguration.CLI_CONN_PORT;
 
 /** Tests Spring Data CRUD operation when thin client is used for accessing the Ignite cluster. */
 public class IgniteClientSpringDataCrudSelfTest extends IgniteSpringDataCrudSelfTest {
@@ -43,28 +36,4 @@
         repoWithCompoundKey = ctx.getBean(PersonRepositoryWithCompoundKey.class);
         ignite = ctx.getBean(IgniteEx.class);
     }
-
-    /**
-     * Tests repository configuration in case {@link ClientConfiguration} is used to provide access to Ignite cluster.
-     */
-    @Test
-    public void testRepositoryWithClientConfiguration() {
-        ctx = new AnnotationConfigApplicationContext();
-
-        ctx.register(TestApplicationConfiguration.class);
-        ctx.refresh();
-
-        assertTrue(ctx.getBean(PersonRepository.class).count() > 0);
-    }
-
-    /** */
-    @Configuration
-    @EnableIgniteRepositories("org.apache.ignite.springdata.misc")
-    static class TestApplicationConfiguration {
-        /** Ignite client configuration bean. */
-        @Bean
-        public ClientConfiguration igniteCfg() {
-           return new ClientConfiguration().setAddresses("127.0.0.1:" + CLI_CONN_PORT);
-        }
-    }
 }
diff --git a/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java b/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java
new file mode 100644
index 0000000..aa3d6a7
--- /dev/null
+++ b/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.ignite.springdata;
+
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.ClientConfiguration;
+import org.apache.ignite.configuration.ClientConnectorConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.springdata.misc.Person;
+import org.apache.ignite.springdata.misc.PersonRepository;
+import org.apache.ignite.springdata.repository.IgniteRepository;
+import org.apache.ignite.springdata.repository.config.EnableIgniteRepositories;
+import org.apache.ignite.springdata.repository.config.RepositoryConfig;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.context.annotation.Configuration;
+
+import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause;
+import static org.springframework.context.annotation.FilterType.ASSIGNABLE_TYPE;
+
+/** Tests Spring Data repository cluster connection configurations. */
+public class IgniteSpringDataConnectionConfigurationTest extends GridCommonAbstractTest {
+    /** */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+    /** */
+    private static final String CACHE_NAME = "PersonCache";
+
+    /** */
+    private static final int CLI_CONN_PORT = 10810;
+
+    /** */
+    private static final String CLI_NAME = "cli-node";
+
+    /** */
+    private static final String SRV_NAME = "srv-node";
+
+    /** */
+    private static final String LOCAL_HOST = "127.0.0.1";
+
+    /** Tests repository configuration in case {@link IgniteConfiguration} is used to access the Ignite cluster. */
+    @Test
+    public void testRepositoryWithIgniteConfiguration() {
+        checkRepositoryConfiguration(IgniteConfigurationApplication.class);
+
+        assertClientNodeIsStopped();
+    }
+
+    /** Tests repository configuration in case {@link ClientConfiguration} is used to access the Ignite cluster. */
+    @Test
+    public void testRepositoryWithClientConfiguration() {
+        checkRepositoryConfiguration(ClientConfigurationApplication.class);
+    }
+
+    /**
+     * Tests repository configuration in case {@link IgniteConfiguration} that refers to existing Ignite node instance
+     * is used to access the Ignite cluster.
+     */
+    @Test
+    public void testRepositoryWithExistingIgniteInstance() throws Exception {
+        try (Ignite ignored = startGrid(getIgniteConfiguration(CLI_NAME, true))) {
+            checkRepositoryConfiguration(IgniteConfigurationApplication.class);
+
+            assertNotNull(Ignition.ignite(CLI_NAME));
+        }
+    }
+
+    /** Tests repository configuration in case specified cache name is invalid. */
+    @Test
+    public void testRepositoryWithInvalidCacheNameConfiguration() {
+        try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
+            ctx.register(InvalidCacheNameApplication.class);
+
+            assertThrowsAnyCause(log,
+                () -> {
+                    ctx.refresh();
+
+                    return null;
+                },
+                IllegalArgumentException.class,
+                "Invalid repository configuration [name=" + InvalidCacheRepository.class.getName() + "]. Set a" +
+                    " name of an Apache Ignite cache using org.apache.ignite.springdata.repository.config.RepositoryConfig" +
+                    " annotation to map this repository to the underlying cache.");
+        }
+
+        assertClientNodeIsStopped();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        grid(SRV_NAME).cache(CACHE_NAME).clear();
+    }
+
+    /** */
+    private void assertClientNodeIsStopped() {
+        assertFalse(Ignition.allGrids().stream().map(Ignite::name).anyMatch(CLI_NAME::equals));
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        startGrid(getIgniteConfiguration(SRV_NAME, false));
+    }
+
+    /**
+     * Checks that repository created based on specified Spring application configuration is properly initialized and
+     * got access to the Ignite cluster.
+     */
+    private void checkRepositoryConfiguration(Class<?> cfgCls) {
+        try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
+            ctx.register(cfgCls);
+            ctx.refresh();
+
+            PersonRepository repo = ctx.getBean(PersonRepository.class);
+
+            IgniteCache<Integer, Person> cache = grid(SRV_NAME).cache(CACHE_NAME);
+
+            assertEquals(0, repo.count());
+            assertEquals(0, cache.size());
+
+            int key = 0;
+
+            repo.save(key, new Person("Domenico", "Scarlatti"));
+
+            assertEquals(1, repo.count());
+            assertNotNull(cache.get(key));
+        }
+    }
+
+    /**
+     * Spring Application configuration for repository testing in case {@link IgniteConfiguration} is used
+     * for accessing the cluster.
+     */
+    @Configuration
+    @EnableIgniteRepositories(includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = PersonRepository.class))
+    public static class IgniteConfigurationApplication {
+        /** Ignite configuration bean. */
+        @Bean
+        public IgniteConfiguration igniteCfg() {
+            return getIgniteConfiguration(CLI_NAME, true);
+        }
+    }
+
+    /**
+     * Spring Application configuration for repository testing in case {@link IgniteConfiguration} is used
+     * for accessing the cluster.
+     */
+    @Configuration
+    @EnableIgniteRepositories(
+        considerNestedRepositories = true,
+        includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = InvalidCacheRepository.class))
+    public static class InvalidCacheNameApplication {
+        /** Ignite configuration bean. */
+        @Bean
+        public IgniteConfiguration igniteCfg() {
+            return getIgniteConfiguration(CLI_NAME, true);
+        }
+    }
+
+    /**
+     * Spring Application configuration for repository testing in case {@link ClientConfiguration} is used
+     * for accessing the cluster.
+     */
+    @Configuration
+    @EnableIgniteRepositories(includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = PersonRepository.class))
+    public static class ClientConfigurationApplication {
+        /** Ignite client configuration bean. */
+        @Bean
+        public ClientConfiguration igniteCfg() {
+            return new ClientConfiguration().setAddresses(LOCAL_HOST + ':' + CLI_CONN_PORT);
+        }
+    }
+
+    /** Repository for testing application behavior in case the cache name is not specified in the repository configuration. */
+    @RepositoryConfig
+    interface InvalidCacheRepository extends IgniteRepository<Person, Integer> {
+        // No-op.
+    }
+
+    /** */
+    private static IgniteConfiguration getIgniteConfiguration(String name, boolean clientMode) {
+        return new IgniteConfiguration()
+            .setIgniteInstanceName(name)
+            .setClientMode(clientMode)
+            .setLocalHost(LOCAL_HOST)
+            .setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(IP_FINDER))
+            .setClientConnectorConfiguration(new ClientConnectorConfiguration().setPort(CLI_CONN_PORT))
+            .setCacheConfiguration(new CacheConfiguration<>(CACHE_NAME));
+    }
+}
diff --git a/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java b/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
index 66379f7..5044aef 100644
--- a/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
+++ b/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
@@ -25,6 +25,8 @@
 import org.apache.ignite.configuration.ClientConnectorConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.springdata.repository.config.EnableIgniteRepositories;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -40,6 +42,7 @@
     public IgniteEx igniteServerNode() {
         IgniteConfiguration cfg = new IgniteConfiguration()
             .setClientConnectorConfiguration(new ClientConnectorConfiguration().setPort(CLI_CONN_PORT))
+            .setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(new TcpDiscoveryVmIpFinder(true)))
             .setCacheConfiguration(new CacheConfiguration<Integer, Person>("PersonCache")
                 .setIndexedTypes(Integer.class, Person.class));
 
diff --git a/modules/spring-data-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringDataTestSuite.java b/modules/spring-data-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringDataTestSuite.java
index cb6e34c..4a47568 100644
--- a/modules/spring-data-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringDataTestSuite.java
+++ b/modules/spring-data-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringDataTestSuite.java
@@ -21,6 +21,7 @@
 import org.apache.ignite.springdata.IgniteClientSpringDataCrudSelfTest;
 import org.apache.ignite.springdata.IgniteClientSpringDataQueriesSelfTest;
 import org.apache.ignite.springdata.IgniteSpringDataCompoundKeyTest;
+import org.apache.ignite.springdata.IgniteSpringDataConnectionConfigurationTest;
 import org.apache.ignite.springdata.IgniteSpringDataCrudSelfTest;
 import org.apache.ignite.springdata.IgniteSpringDataQueriesSelfTest;
 import org.junit.runner.RunWith;
@@ -34,6 +35,7 @@
     IgniteSpringDataCrudSelfTest.class,
     IgniteSpringDataQueriesSelfTest.class,
     IgniteSpringDataCompoundKeyTest.class,
+    IgniteSpringDataConnectionConfigurationTest.class,
     IgniteClientSpringDataCrudSelfTest.class,
     IgniteClientSpringDataQueriesSelfTest.class,
     IgniteClientSpringDataCompoundKeyTest.class