This topic explains how to build a Spring Boot application configured with Spring Session for VMware Tanzu GemFire to transparently leverage VMware Tanzu GemFire to manage a web application’s javax.servlet.http.HttpSession
.
In this sample, the Tanzu GemFire Client-Server topology is employed using a pair of Spring Boot applications, one to configure and run a Tanzu GemFire Server and another to configure and run the cache client, a Spring MVC-based web application making use of the HttpSession
.
Before using Spring Session, you must ensure that the required dependencies are included. If you are using Maven, include the following dependencies
in your pom.xml
:
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-3.0-gemfire-10.0</artifactId>
<version> 1.0.0</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
After adding the required dependencies and repository declarations, we can create the Spring configuration for our Tanzu GemFire client using Spring Boot. The Spring configuration is responsible for creating a Servlet Filter
that replaces the Web container’s HttpSession
with an implementation backed by Spring Session, which is then stored and managed in Tanzu GemFire.
We start with a Spring Boot application to configure and bootstrap the Tanzu GemFire Server:
@SpringBootApplication //SEE COMMENT 1
@CacheServerApplication(name = "SpringSessionDataGemFireBootSampleServer", logLevel = "error") //SEE COMMENT 2
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = 20) //SEE COMMENT 3
public class GemFireServer {
public static void main(String[] args) {
new SpringApplicationBuilder(GemFireServer.class)
.web(WebApplicationType.NONE)
.build()
.run(args);
}
}
Comments:
We annotate the Tanzu GemFire Server configuration class, GemFireServer
, with @SpringBootApplication
to indicate that this is a Spring Boot application leveraging all of Spring Boot’s features.
We use the Spring Data for Tanzu GemFire configuration annotation @CacheServerApplication
to simplify the creation of a peer cache instance containing a CacheServer
for cache clients to connect.
(Optional) We use the @EnableGemFireHttpSession
annotation to create the necessary server-side Region
(by default, ClusteredSpringSessions
) to store the HttpSessions
state. This step is optional because the Session Region
can be created manually.
We create a Spring Boot Web application to expose our Web service with Spring Web MVC, running as an Tanzu GemFire cache client connected to our Spring Boot, Tanzu GemFire Server. The Web application will use Spring Session backed by Tanzu GemFire to manage HttpSession
state in a clustered (distributed) and replicated manner.
@SpringBootApplication //SEE COMMENT 1
@Controller //SEE COMMENT 2
public class Application {
static final String INDEX_TEMPLATE_VIEW_NAME = "index";
static final String PING_RESPONSE = "PONG";
static final String REQUEST_COUNT_ATTRIBUTE_NAME = "requestCount";
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@ClientCacheApplication(name = "SpringSessionDataGemFireBootSampleClient", logLevel = "error",
readTimeout = 15000, retryAttempts = 1, subscriptionEnabled = true) //SEE COMMENT 3
@EnableGemFireHttpSession(poolName = "DEFAULT") //SEE COMMENT 4
static class ClientCacheConfiguration extends ClientServerIntegrationTestsSupport {
@Bean
ClientCacheConfigurer gemfireServerReadyConfigurer( //SEE COMMENT 5
@Value("${spring.data.gemfire.cache.server.port:40404}") int cacheServerPort) {
return (beanName, clientCacheFactoryBean) -> waitForServerToStart("localhost", cacheServerPort);
}
}
@Configuration
static class SpringWebMvcConfiguration { //SEE COMMENT 6
@Bean
public WebMvcConfigurer webMvcConfig() {
return new WebMvcConfigurer() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName(INDEX_TEMPLATE_VIEW_NAME);
}
};
}
}
@ExceptionHandler
@ResponseBody
public String errorHandler(Throwable error) {
StringWriter writer = new StringWriter();
error.printStackTrace(new PrintWriter(writer));
return writer.toString();
}
@RequestMapping(method = RequestMethod.GET, path = "/ping")
@ResponseBody
public String ping() {
return PING_RESPONSE;
}
@RequestMapping(method = RequestMethod.POST, path = "/session")
public String session(HttpSession session, ModelMap modelMap,
@RequestParam(name = "attributeName", required = false) String name,
@RequestParam(name = "attributeValue", required = false) String value) { //SEE COMMENT 7
modelMap.addAttribute("sessionAttributes",
attributes(setAttribute(updateRequestCount(session), name, value)));
return INDEX_TEMPLATE_VIEW_NAME;
}
}
Comments:
We declare our Web application to be a Spring Boot application by annotating our application class with @SpringBootApplication
.
@Controller
is a Spring Web MVC annotation enabling our MVC handler mapping methods (i.e. methods annotated with @RequestMapping
) to process HTTP requests, for example <7>.
We declare our Web application to be an Tanzu GemFire cache client by annotating our application class with @ClientCacheApplication
. Additionally, we adjust a few basic, “DEFAULT” Pool
settings, for example readTimeout
.
We declare that the Web application will use Spring Session backed by Tanzu GemFire by annotating the ClientCacheConfiguration
class with @EnableGemFireHttpSession
. This will create the necessary client-side Region
(by default, “ClusteredSpringSessions” as a PROXY
Region
) corresponding to the same server-side Region
by name. All HttpSession
state will be sent from the cache client Web application to the server through Region
data access operations. The client-side Region
uses the “DEFAULT” Pool
.
We wait to ensure the Tanzu GemFire Server is up and running before we proceed. This is used for automated integration testing purposes.
We adjust the Spring Web MVC configuration to set the home page.
We declare the /sessions
HTTP request handler method to set an HTTP Session attribute and increment a count for the number of HTTP requests.
Many other useful utility methods exist. Refer to the actual source code for full details.
Note: In typical Tanzu GemFire production deployments, where the cluster includes potentially hundreds or thousands of servers (data nodes), it is more common for clients to connect to one or more Tanzu GemFire Locators running in the same cluster. A Locator passes meta-data to clients about the servers available in the cluster, the individual server load, and which servers have the client's data of interest, which is particularly important for direct, single-hop data access and latency-sensitive applications. For more information, see Standard Client-Server Deployment in the Tanzu GemFire product documentation.
For more information about configuring Spring Data for VMware Tanzu GemFire, see Spring Data for VMware Tanzu GemFire Reference Guide in the Spring product documentation.
HttpSession
ManagementThe @EnableGemFireHttpSession
annotation enables developers to configure certain aspects of both Spring Session and Tanzu GemFire out-of-the-box using the following attributes:
clientRegionShortcut
: Configures the data management policy on the client using the ClientRegionShortcut
(see VMware GemFire Java API Reference). Defaults to PROXY
. Only applicable on the client.
indexableSessionAttributes
: Identifies the HttpSession
attributes by name that should be indexed for queries. Only Session attributes explicitly identified by name will be indexed.
maxInactiveIntervalInSeconds
:Controls HttpSession
Idle Expiration Timeout (TTI; defaults to 30 minutes).
poolName
: Name of the dedicated connection Pool
connecting the client to a cluster of servers. Defaults to gemfirePool
. Only applicable on the client.
regionName
: Declares the name of the Region
used to store and manage HttpSession
state. Defaults to “ClusteredSpringSessions”.
serverRegionShortcut
: Configures the data management policy on the client using the RegionShortcut
(see VMware GemFire Java API Reference). Defaults to PARTITION
. Only applicable on the server, or when the P2P topology is employed.
Note: The Tanzu GemFire client Region
name must match a server Region
by the same name if the client Region
is a PROXY
or CACHING_PROXY
. Client and server Region
names are not required to match if the client Region
is LOCAL
. However, by using a client LOCAL
Region, HttpSession
state will not be propagated to the server and you lose all the benefits of using Tanzu GemFire to store and manage HttpSession
state on the servers in a distributed, replicated manner.
The following is a sample Spring Boot web application with a Tanzu GemFire-Managed HttpSession.
To run the sample app:
Obtain the source code.
In a terminal window, run the server:
./gradlew :spring-session-sample-boot-gemfire:run
In a separate terminal window, run the client:
./gradlew :spring-session-sample-boot-gemfire:bootRun
In a browser, access the application at http://localhost:8080/.
In this sample, the Web application is the Spring Boot, Tanzu GemFire cache client and the server is standalone, separate JVM process.
In the application, complete the form with the following information:
username
test
Click the Set Attribute button. You should see the attribute name and value displayed in the table along with an additional attribute, requestCount
, which shows the number of HTTP requests made.
We interact with the standard javax.servlet.http.HttpSession
in the Spring Web MVC service endpoint, located in src/main/java/sample/client/Application.java
.
@Controller
class SessionController {
@RequestMapping(method = RequestMethod.POST, path = "/session")
public String session(HttpSession session, ModelMap modelMap,
@RequestParam(name = "attributeName", required = false) String name,
@RequestParam(name = "attributeValue", required = false) String value) {
modelMap.addAttribute("sessionAttributes",
attributes(setAttribute(updateRequestCount(session), name, value)));
return INDEX_TEMPLATE_VIEW_NAME;
}
}
Instead of using the embedded HTTP server’s HttpSession
, we persist the Session state in Tanzu GemFire. Spring Session creates a cookie named “SESSION” in your browser that contains the ID of the Session. You can view the cookies using your browser controls.