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.3-gemfire-10.1</artifactId>
<version>2.0.0</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
Spring Boot Configuration
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.
Spring Boot, Tanzu GemFire Cache Client Web Application
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 Tanzu GemFire cluster. 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")//SEE COMMENT 3
@EnablePool(name = "sessionPool", readTimeout = 15000, retryAttempts = 1)
@EnableGemFireHttpSession(poolName = "sessionPool") //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
. -
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-sideRegion
(by default, “ClusteredSpringSessions” as aPROXY
Region
) corresponding to the same server-sideRegion
by name. AllHttpSession
state will be sent from the cache client Web application to the server throughRegion
data access operations. The client-sideRegion
uses the “sessionPool”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.
Enabling HttpSession
Management
The @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 theClientRegionShortcut
(see VMware GemFire Java API Reference). Defaults toPROXY
. Only applicable on the client. -
maxInactiveIntervalInSeconds
:ControlsHttpSession
Idle Expiration Timeout (TTI; defaults to 30 minutes). -
poolName
: Name of the dedicated connectionPool
connecting the client to a cluster of servers. Defaults togemfirePool
. Only applicable on the client. -
regionName
: Declares the name of theRegion
used to store and manageHttpSession
state. Defaults to “ClusteredSpringSessions”.
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.
Spring Boot Sample Web Application
The following is a sample Spring Boot web application with a Tanzu GemFire-Managed HttpSession.
Running the Boot Sample Application
To run the sample app:
-
Obtain the source code.
-
In a terminal window, run the server using
gfsh
and create the “ClusteredSpringSessions” region:gfsh> start server gfsh> create region --name=ClusteredSpringSessions --type=PARTITION
-
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.
Exploring the Sample Application
-
In the application, complete the form with the following information:
- Attribute Name:
username
- Attribute Value:
test
- Attribute Name:
-
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.
How the Application Works
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.
Content feedback and comments