This is the first of multiple posts on incorporating GemFire into your Java application architecture. This post explores why Spring (including its ecosystem) is an excellent environment for incorporating GemFire into your Java application architecture. Upcoming posts will go deeper into best practices, tools and techniques detailing how to do so.
If you’re a Java developer, it’s likely you’re using the Spring Framework. Various market studies validate Spring’s market dominance and continued exponential growth. A key part of Spring’s allure is the extensive ground it covers, which includes support for incorporating a number of data stores, including Pivotal GemFire, an in-memory data grid (IMDG).
With the coming-of-age of IMDGs like GemFire, application developers are eager to determine how best to use these technologies and extract value from their data. GemFire’s capabilities can add huge value to your applications. Before diving into the details, you may have some questions around the approaches, best practices, and frameworks that can help you get there.
Enter the Spring Framework.
The Spring Framework’s Solid Core
Spring’s benefits span across the initial development to the ongoing lifecycle management of code. By taking care of much of the overhead, Spring frees up developers to focus on application logic. It’s impossible (nor is it necessary to) try to cover all of Spring’s benefits here. Fortunately, the explosive popularity of Spring has brought with it a large body of information, both online and in books, that cover each of it’s many aspects in detail. Here’s a high altitude view of some standout features.
Dependency injection, also called Inversion of Control (IoC), supports loose coupling between objects. This allows developers to test objects by passing in mock objects for the dependencies. Similarly, adding a class to a project is possible because the class is isolated and self-contained. The lifecycle management of these objects can occur separately because they are loosely coupled.
Aspect-Oriented Programming (AOP) picks up where object-oriented programming reaches its limit. AOP accommodates ‘cross-cutting’ concerns, like Transaction Management, Security, Logging, etc.. These concerns span across tiers of an application, i.e. things that don’t fit neatly into the modular structure of object-oriented programming.
Efficient Handling of Boilerplate Code removes an annoying productivity killer — the overhead incurred by having to insert the same repetitive code in various places. Spring templates provide the boilerplate code and error-handling needed to use many APIs, such as JDBC, JMS, transactions, etc. The concept of convention over configuration simplifies the high degree of variability in the setup of your environment.
And that’s just for starters. Pivotal’s Spring site is a good resource for a more comprehensive view.
The Spring Ecosystem Provides Huge Leverage
Spring’s modularity allows you to pick and choose from an expansive ecosystem of projects for accelerating various aspects of your application development. When combined, these projects provide benefits that go beyond the sum of their parts. The core, indispensable set of projects you will most likely end up using for incorporating GemFire in your application architecture will include Spring Boot, Spring Data (GemFire), and Spring Cloud DataFlow. The other projects should not be overlooked for the problems they solve; the projects described here are just a least common denominator rather than a complete list.
Spring Boot makes it easy to jump start your application setup and configuration by managing low-level infrastructure concerns. The result? You can get started with a fully featured Spring application with just a few lines of code. Spring Boot is opinionated out of the box, but gets out of the way quickly by allowing you to override the defaults as your requirements start to diverge.
Spring Boot is a complete, end-to-end application framework extending and building on the core Spring Framework by orchestrating the extensive capabilities into a cohesive, turn-key enterprise-ready solution for many application concerns. The areas that Spring Boot covers range from simple data access all the way to complex transaction management, analysis, security, management/monitoring (metrics), and more, handling an entire spectrum of transactional and analytical use cases. Spring Boot’s dependency management can be plugged into your build system of choice (i.e. either Maven or Gradle) to provide a comprehensive, curated and tested set of dependencies.
Developers often get bogged down by covering a number of non-functional features. Spring Boot covers these non-functional requirements for a large class of projects (e.g. embedded servers, security, health checks, externalized configuration).
Spring Boot makes sensible choices for configuring resources based on what it finds in your classpath. If your Maven POM includes JPA dependencies and a PostgreSQL driver, then Spring Boot will set up a persistence unit based on PostgreSQL. If you’ve added a web dependency, then you get Spring MVC and a web container configured with sensible defaults. Spring Boot makes extensive use of defaults. If you want persistence, but don’t specify anything else, then Spring Boot configures Hibernate as a JPA provider with an HSQLDB database. If you’re bootstrapping a web application, but don’t specify anything else, then Spring Boot configures a view resolver for the Thymeleaf template system. For the most part, changing defaults involves simply changing the classpath.
Spring Data adds portability to your code by providing a standard approach to accessing databases, regardless of which database. In the absence of a standard approach, the uniqueness and idiosyncrasies of each database leads to code changes in various places if you want to switch database.
Spring Data makes database changes much easier. In going from a JPA implementation targeting MySQL to GemFire, for example, you only need to change a few annotations. Not a single line of Java code has to change, just the annotations. This provides major risk reduction by allowing you to easily change the target database.
So how does Spring Data handle back-end diversity? That’s covered by something called Spring Data Repositories. The Repository sits in between the client logic and the database. Repositories provide separate and proprietary interface layers that go to each of the supported back-end databases. The GemFire Repository is provided out-of-the-box with Spring Data GemFire (SDG).
In addition to portability, Spring Data removes the irritation of having to deal with each database’s idiosyncrasies and unique access pattern. As a developer, you experience a common interface and common mindset for communicating with all these technologies. For example, when you’re debugging your code, you don’t have to think about each of the back-end databases and how they work.
Traditional Object-Relational-Mapping layers, like Hibernate or JPA, leave substantial gaps. For instance, these ORMs don’t support features related to accessing data from IMDGs like GemFire. Rather than adopting a one size fits all solution, Spring Data adopts an approach that retains the diversity and unique advantages of each database.
Spring Data is an umbrella project containing many sub-projects that are specific to a database. Spring Data provides a familiar and consistent, Spring-based programming model for data access while still retaining the special traits of the underlying database. Spring Data supports a wide range of database technologies, including Pivotal GemFire, which can be included in your applications by using Pivotal’s SDG — covered in more detail in a separate section below.
Regardless of database, there are a set of core functions (like CRUD operations) that you will most likely use. Spring Data adds a simple interface, and a set of query methods or finders. If, for example, you want to implement Oracle via JPA, using Spring Data you can implement a finder (ex: find by last name and first name). The code for these finders is very simple and much of what is needed will be automatically created by the implementation for the database repository.
All of the native queries of all of the supported databases are supported. So Spring Data does not homogenize everything to a common set of functions. As the developer, you have the ability to choose the type of queries you want, like an OQL Query against GemFire, or issue queries against a traditional SQL92 database, Mongo DB, etc.
Spring Cloud DataFlow
Modern applications are built as collections of microservices, which raises questions about how the movement of data across these microservices can be defined and managed. This orchestration of data is made possible by Spring Cloud DataFlow (SCDF). GemFire can serve as either a source or a sink for SCDF.
SCDF is a cloud native data framework that defines best practices and unifies stream and batch processing for data microservices, across the cloud or on-prem. It allows developers to create, orchestrate and refactor data pipelines with a single programming model for common use cases like data ingestion, real time analytics, and data import/export.
Typically, developers of web or mobile applications tend to follow a set of practices that align with modern software development patterns. On the other hand, when we look at data heavy personas such as data engineers and data scientists, their usual development methods are more traditional, as they’re not equipped with tools and techniques to enable continuous delivery. SCDF bridges this gap by providing a development and operational model for reimagining data-centric use cases. These data centric use cases can be composed of loosely coupled microservices with the flexibility to evolve in isolation, thus paving the path for continuous delivery — a key step in the enterprise data transformation journey.
SCDF spawned and subsumes an ecosystem of projects that embrace the microservices approach with loosely coupled services. Spring Cloud Stream allows developers to quickly develop event-driven microservices. Spring Cloud Task supports data architectures that require some form of ETL/ELT pipelines, like machine learning where the model training is always run on offline data pipelines, as it can take hours to days to complete.
Spring Data GemFire Is Your Best Starting Point
SDG allows developers to build highly scalable, Spring-powered applications using Pivotal GemFire as a distributed data management platform. SDG brings the full power of the Spring Framework to your GemFire applications.
The traditional approach to including GemFire in Java applications has been to use XML files, either Spring XML or GemFire’s native cache.xml. There are several considerations that go into choosing between these two XML formats. But there is an alternate approach — using Java configuration. Adopting the Java configuration approach, supported by SDG, offers type safety and productivity benefits that make it a better choice. The Java configuration approach focuses on integrating the Spring Framework’s powerful, non-invasive programming model and concepts with Pivotal GemFire, simplifying configuration, development and providing high-level abstractions.
SDG provides configuration support for bootstrapping, configuring, initializing and accessing GemFire Caches, Cache Regions, Cache Servers and related Distributed System components. SDG enables the integration between GemFire APIs and the various data access features available in Spring, such as transaction management and exception translation.
Entities can be mapped, persisted and queried using the Spring Data Repository abstraction. The goal of the Spring Data Repository abstraction is to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores.
SDG provides annotations for a broad range of tasks including an annotation based configuration model, entity mapping, OQL Query extensions and execution, function definition and execution, plus a whole lot more.
As with many other high-level abstractions provided by the Spring projects, SDG provides a template that simplifies GemFire data access — a convenience class or helper class based on the Template Design Pattern for accessing data from GemFire. The class provides several one-line methods for common Cache Region operations but also the ability to execute code against the native GemFire API.
Future blog posts will dive deeper into the best practices for including GemFire in your Java applications. We will explore the alternatives more comprehensively and clarify the best use of each approach. Stay tuned.