Some additional thoughts on the subject...
One of the many advantages in using Spring Templates for data store-specific access (e.g. GemfireTemplate) is that they shield developers from underlying data store API changes around which the Templates typically wrap. If the data store vendor makes API interface breaking changes (which has been the case for GemFire) then the Template can provide a layer of abstraction/adaption to the underlying API without changes to the user application.
In addition, the Template can leverage other Spring Infrastructure Management like Transactions that would typically not be inherently built into the underly data store APIs itself. Templates can also provide a facade and layer of convenience for several distinct APIs in the underlying data store product.
For instance, GemfireTemplate encapsulates operations to 'get' and 'put' data along with 'querying' the data of interest.
To do the former in GemFire, you would need to do the following...
Region<String, SomeValue> example = gemfireCache.getRegion("/Example");
example.put("someKey", new SomeValue(..));
...
SomeValue someValue = example.get("someKey");
While to query the data in '/Example', you would...
Region<String, SomeValue> example = gemfireCache.getRegion("/Example");
QueryService queryService = example.getQueryService();
Query query = queryService.newQuery("SELECT * FROM /Example WHERE ...");
Object result = query.execute(<any args for query parameters>);
if (result instanceof SelectResults) {
SelectResults<SomeValue> someValues = (SelectResults) result;
// process the query results
}
else {
// figure out what happened
}
Now, contrast that with the Spring Template to get/put data
gemfireTemplate.put("someKey", new SomeValue(..));
...
SomeValue someValule = gemfireTemplate.get("someKey");
And querying...
SelectResults<SomeValue> results = gemfireTemplate.find("SELECT * FROM /Example WHERE ...", args);
// process the query results
If an Exception happens, or the results could not be collected, then GemFires' Exceptions/Errors are uniformly mapped to the core Spring Framework DAO Exception hierarchy, yet another advantage, which makes switching underly data stores easier, along with the consistent transaction handling.
Finally, while both Thomas Darimont and Master Slave nicely summed up the advantages of the using the Spring Data Repository abstraction, this is not a new concept.
Before the expressive power and convenience of Spring Data's Repository abstraction, application developers would use the DAO pattern to abstract out the CRUD and other data access operations (e.g. Querying) from their application services-tier.
However, what Spring Data gives you is the power to do this by simply declaring the contract (a Java interface) for the permitted data access operations and Spring Data (including the provider specific implementations, like Spring Data GemFire) takes cares of the rest, plugging in a "default" data store specific implementation, which is highly customizable.
Obviously, I am biased, but to express a Query using the name of a interface method, using the parameters of the method as SQL/OQL/etc query arguments, is just wicked cool, and powerful.
If the queries are not to complex or specific, this could be easily migrated from 1 data store to another, even between a relation and Key/Value store (like GemFire given the similarities between SQL and OQL, for instance).
Hope this helps. Cheers!