Complete final edits on the new Spring Boot with Apache Geode Sample using Spring Scoped Proxy Beans.

Resolves Issue #3.
This commit is contained in:
John Blum
2017-11-07 11:13:33 -08:00
parent f136c1edeb
commit 05f3baee33
2 changed files with 196 additions and 162 deletions

View File

@@ -1,35 +1,34 @@
= Spring Session - HttpSession with Apache Geode Client/Server using Spring Boot
= Spring Session - HttpSession using Apache Geode with Spring Boot and Scoped Proxy Beans
John Blum
:toc:
This guide describes how to build a _Spring Boot_ application configured with _Spring Session_ that transparently
delegates to Apache Geode for managing a Web application's `javax.servlet.http.HttpSession` in a clustered/replicated,
highly available and optionally, durable fashion.
This guide describes how to build a _Spring Boot_ Web application configured with _Spring Session_ to transparently
manage a Web application's `javax.servlet.http.HttpSession` using Apache Geode in a clustered (distributed),
replicated, highly available and optionally, durable manner.
In addition, this samples explores the effects of using _Spring Session_ and Apache Geode (or Pivotal GemFire) to
transparently manage the (HTTP) Session when the _Spring Boot_, Web application also declares both Session and Request
scoped bean definitions used by the application when processing requests.
In addition, this samples explores the effects of using _Spring Session_ and Apache Geode to manage the `HttpSession`
when the _Spring Boot_ Web application also declares both "_session_" and "_request_" scope bean definitions to process
client HTTP requests.
This sample originated from a https://stackoverflow.com/questions/45674137/can-session-scope-beans-be-used-with-spring-session-and-gemfire[_StackOverflow_ post],
This sample is based on a https://stackoverflow.com/questions/45674137/can-session-scope-beans-be-used-with-spring-session-and-gemfire[_StackOverflow_ post],
which posed the following question...
> _Can session scope beans be used with Spring Session and GemFire?_
> _Can session scope beans be used with Spring Session and Pivotal GemFire?_
The poster when on to state...
The poster of the question when on to state and ask...
> If using Spring Session for "session" scoped beans Spring creates an extra HttpSession for this bean,
is this an existing issue? What is the solution for this?
> When using Spring Session for "session" scope beans, Spring creates an extra HttpSession for this bean.
Is this an existing issue? What is the solution for this?
Well, in a nutshell, the answer to the first question is most definitely, *yes*. And, the second statement/question
is not correct/valid, as explained in the answer.
The answer to the first question is most definitely, *yes*. And, the second statement/question is not correct/valid,
as explained in the answer.
This sample uses Apache Geode's client/server topology with a pair of _Spring Boot_ applications, one to configure
and run a Geode Server, and another to configure and run a GemFire-based cache client, Spring MVC Web application
making use of the `HttpSession`.
and run a Geode server, and another to configure and run a Geode client, which is also a _Spring_ MVC Web application
making use of an `HttpSession`.
NOTE: The completed guide can be found in the section,
<<spring-session-sample-boot-geode-with-scoped-proxies,Spring Boot Sample Web Application with Apache Geode-managed HttpSessions and Request and Session Scoped Proxy Beans>>,
below.
NOTE: The completed guide can be found below, in section
<<spring-session-sample-boot-geode-with-scoped-proxies,Sample Spring Boot Web Application using Apache Geode-managed HttpSessions with Request and Session Scoped Proxy Beans>>.
== Updating Dependencies
@@ -56,8 +55,8 @@ If you are using _Maven_, include the following `dependencies` in your `pom.xml`
</dependencies>
----
NOTE: if using Pivotal GemFire, you may substitute the `spring-session-data-gemfire` artifact
for `spring-session-data-geode`.
NOTE: If you are using Pivotal GemFire instead of Apache Geode, you may substitute the `spring-session-data-gemfire`
artifact for `spring-session-data-geode`.
ifeval::["{version-snapshot}" == "true"]
Since we are using a SNAPSHOT version, we need to add the _Spring_ Snapshot Maven Repository.
@@ -113,29 +112,27 @@ We start with a _Spring Boot_ application to configure and bootstrap the Apache
include::{samples-dir}boot/gemfire-with-scoped-proxies/src/main/java/sample/server/GemFireServer.java[tags=class]
----
<1> First, we annotate the Apache Geode server configuration class with `@SpringBootApplication` to declare this as a
_Spring Boot_ application allowing us to leverage all of _Spring Boot's_ features (e.g. _auto-configuration_).
<2> Next, we declare _Spring Data Geode's_ `@CacheServerApplication`, which creates a peer, cache server that allows
our cache client to connect.
<3> (Optional) Then, we declare the `@EnableGemFireHttpSession` annotation to create the necessary server-side `Region`
(by default, "_ClusteredSpringSessions_") used to store the `HttpSessions` state. This step is optional since
the `Region` used to store `Session` state could be manually created. Using `@EnableGemFireHttpSession` is easy
and convenient, and ensure that our client and server-side Region match by name, which is required by GemFire/Geode.
<4> Additionally, and optionally, we also enable Apache Geode's embedded Management service, which allows JMX clients
(e.g. Apache Geode's _Gfsh_ shell tool) to connect to the server and manage the server/cluster.
<5> Finally, we adjust the port that the `CacheServer` will use to listen for cache clients by declaring
a `CacheServerConfigurer` bean that modified the port using SDG's `CacheServerFactoryBean` with property placeholders.
Defaults to *40404* if not adjusted.
The sample also makes use of _Spring's_ `PropertySourcesPlaceholderConfigurer` in order to externalize
the sample application's configuration using a properties file or with JVM System properties.
<1> First, we annotate the `GemFireServer` class with `@SpringBootApplication` declaring that this is a _Spring Boot_
application, which allows us to leverage all of _Spring Boot's_ features (e.g. _auto-configuration_).
<2> Next, we also annotate the `GemFireServer` class with _Spring Data Geode's_ `@CacheServerApplication`,
which creates a peer, cache server allowing cache clients to connect.
<3> (_Optional_) Then, we declare the `@EnableGemFireHttpSession` annotation to create the necessary server-side `Region`
(by default, "_ClusteredSpringSessions_") used to store the `HttpSession` state. This step is optional since
the Region used to store session state could be manually created. Using `@EnableGemFireHttpSession` is easy
and convenient, and ensures that our client and server-side Regions match by name, which is required by Apache Geode.
<4> (_Optional_) Additionally, we also enable Apache Geode's embedded Management service, which allows JMX clients
(e.g. Apache Geode's _Gfsh_ shell tool) to connect to the server in order to manage the server or the entire cluster.
<5> Finally, we adjust the port that the `CacheServer` uses to listen for cache client connections by declaring
a `CacheServerConfigurer` bean, which gives us access to SDG's `CacheServerFactoryBean` in order to modify the port.
Property placeholders can be used to externalize the cache server port configuration. The cache server port
defaults to *40404* if not explicitly configured.
=== Spring Boot, Apache Geode Cache Client Web application
Now, we create a _Spring Boot_ Web application exposing our Web service with _Spring_ MVC, running as an Apache Geode
cache client connected to our _Spring Boot_, Apache Geode server. The Web application will use _Spring Session_
backed by Apache Geode to manage (HTTP) Session state in a clustered (i.e. distributed) and replicated,
as well as highly available manner.
backed by Apache Geode to manage `HttpSession` state in a clustered (i.e. distributed), replicated and highly available
manner.
[source,java]
----
@@ -143,33 +140,36 @@ include::{samples-dir}boot/gemfire-with-scoped-proxies/src/main/java/sample/clie
----
<1> Like the server, we declare our Web application to be a _Spring Boot_ application
by annotating our application class with `@SpringBootApplication`.
<2> `@Controller` is a _Spring_ Web MVC annotation enabling our MVC handler mapping methods (i.e. methods annotated
with `@RequestMapping`) to process client HTTP requests (e.g. <6>)
<3> We also declare our Web application to be a Geode cache client by annotating our application class with
`@ClientCacheApplication`. Additionally, we adjust a few basic, "DEFAULT" Geode client `Pool` settings.
<4> Next, we declare that the Web application will use _Spring Session_ backed by Apache Geode to manage the (HTTP)
`Session's` state by annotating the nested `ClientCacheConfiguration` class with `@EnableGemFireHttpSession`.
This will create the necessary client-side `PROXY` `Region` (by default, "ClusteredSpringSessions`) corresponding to
the same server `Region` by name. All Session state will be sent from the client to the server through `Region`
data access operations. The client-side `Region` uses the "DEFAULT" `Pool` (of connections) to communicate
by annotating our `Application` class with `@SpringBootApplication`.
<2> `@Controller` is a _Spring_ Web MVC annotation enabling our MVC request mapping handler methods (i.e. methods
annotated with `@RequestMapping`) to process client HTTP requests (e.g. <6>)
<3> We also declare our Web application to be an Apache Geode cache client by annotating our `Application` class
with `@ClientCacheApplication`. Additionally, we adjust a few basic, "DEFAULT" client Pool settings.
<4> Next, we declare that the Web application will use _Spring Session_ backed by Apache Geode to manage
the `HttpSession's` state by annotating the nested `ClientCacheConfiguration` class with `@EnableGemFireHttpSession`.
This will create the necessary client-side `PROXY` Region (by default, "_ClusteredSpringSessions_") corresponding to
the same server Region by name. All session state will be sent from the client to the server through Region
data access operations. The client-side Region uses the "DEFAULT" Pool (of connections) to communicate
with the server.
<5> Then, we adjust the port used by the cache client `Pool` to connect to the `CacheServer` using a SDG
`ClientCacheConfigurer`.
<6> We adjust the _Spring_ Web MVC configuration to set the home page, and...
<7> Finally, we declare the `/counts` HTTP request handler method to keep track of the number of instances created by
the Sprig container of both Request and Session scoped proxy beans, of types `RequestScopedProxyBean`
and `SessionScopedProxyBean`, respectively, every time a request is processed by this Web service endpoint.
<5> Then, we adjust the port used by the client Pool to connect to the cache server using _Spring Data Geode's_
`ClientCacheConfigurer`. This callback interface is similar in purpose to the `CacheServerConfigurer` we saw
in the server's configuration. In this case, the `ClientCacheConfigurer` gives us access to the underlying
SDG `ClientCacheFactoryBean` in order to adjust the configuration of the Apache Geode `ClientCache`.
<6> We adjust the _Spring_ Web MVC configuration to set the home page, and finally...
<7> We declare the `/counts` HTTP request mapping handler method to keep track of the number of instances
created by the _Spring_ container for both "_request_" and "_session_" scoped proxy beans, of types
`RequestScopedProxyBean` and `SessionScopedProxyBean`, respectively, each and every time a request is processed by
the handler method.
TIP: In typical Geode production deployments, where the cluster includes potentially hundreds or thousands of servers
(a.k.a. data nodes), it is more common for clients to connect to 1 or more Geode Locators running in the 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 operations. See more details about the
TIP: In typical Apache Geode production deployments, where the cluster includes potentially hundreds or thousands
of servers (a.k.a. data nodes), it is more common for clients to connect to 1 or more Geode 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 operations. See more details about the
http://geode.apache.org/docs/guide/12/topologies_and_comm/cs_configuration/standard_client_server_deployment.html[Client/Server Deployment]
in the Apache Geode User Guide.
NOTE: For more information on configuring _Spring Data Geode, refer to the
NOTE: For more information on configuring _Spring Data Geode_, refer to the
http://docs.spring.io/spring-data-gemfire/docs/current/reference/html/[Reference Guide].
==== Enabling GemFire HttpSession Management
@@ -180,78 +180,79 @@ out-of-the-box using the following attributes:
* `clientRegionShortcut` - specifies the Apache Geode http://geode.apache.org/docs/guide/12/developing/region_options/region_types.html[data management policy]
used on the client with http://geode.apache.org/releases/latest/javadoc/org/apache/geode/cache/client/ClientRegionShortcut.html[ClientRegionShortcut]
(default is `PROXY`). This attribute is only used when configuring the client `Region`.
* `indexableSessionAttributes` - Identifies the Session attributes by name that should be indexed for querying purposes.
Only Session attributes explicitly identified by name will be indexed. This is useful in situations where your application
is looking up the `HttpSession` by the currently authenticated user's, or principal's, name.
* `maxInactiveIntervalInSeconds` - controls _HttpSession_ idle-timeout expiration (defaults to **30 minutes**).
* `poolName` - name of the dedicated Apache Geode `Pool` used to connect a client to the cluster of servers.
This attribute is only used when the application is a cache client. Defaults to `gemfirePool`.
* `regionName` - specifies the name of the Apache Geode `Region` used to store and manage `HttpSession` state
(default is "*ClusteredSpringSessions*").
* `indexableSessionAttributes` - Identifies session attributes by name that should be indexed for querying purposes.
Only session attributes explicitly identified by name will be indexed. This is useful in situations where your application
is looking up the `HttpSession` by the currently authenticated principal's name, for example.
* `maxInactiveIntervalInSeconds` - controls `HttpSession` _idle-timeout expiration_ (TTI; defaults to **30 minutes**).
* `poolName` - name of the dedicated Apache Geode Pool used by a client to connect to a cluster of servers (defaults to
"_gemfirePool_").
* `regionName` - specifies the name of the Apache Geode Region used to store and manage `HttpSession` state
(defaults to "_ClusteredSpringSessions_").
* `serverRegionShortcut` - specifies the Apache Geode http://geode.apache.org/docs/guide/12/developing/region_options/region_types.html[data management policy]
used on the server with http://geode.apache.org/releases/latest/javadoc/org/apache/geode/cache/RegionShortcut.html[RegionShortcut]
(default is `PARTITION`). This attribute is only used when configuring server `Regions`, or when a P2P topology
is employed.
* `sessionSerializerBeanName` - refers to the name of the bean that handles serializing the (HTTP) `Session` state
(default is `PARTITION`). This attribute is only used when configuring server Regions, or when Apache Geode's P2P
topology is employed.
* `sessionSerializerBeanName` - refers to the name of the bean that handles serialization of the `HttpSession` state
between the client and the server.
NOTE: It is important to remember that the Apache Geode 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` used to store Sessions is `LOCAL` only. However, keep in mind
that Session state will not be propagated to the server when the client Region is only `LOCAL` to the client
and you lose all the benefits of using Apache Geode to store and manage Session state information on the servers
in a cluster in a highly available and replicated manner.
NOTE: It is important to remember that the Apache Geode client Region name must match a server Region by the same name
if the client Region is either a `PROXY` or `CACHING_PROXY`. Client and server Region names are not required to match
if the client Region used to store session state is `LOCAL` only. However, keep in mind that session state will not
be propagated to the server when the client Region is only `LOCAL` to the client. Additionally, you lose all benefits
of using Apache Geode to store and manage session state on servers in a clustered, replicated and highly available
manner.
=== Session-scoped Proxy Bean
The Geode cache client, Spring Web application defines the `SessionScopedProxyBean` class.
The _Spring Boot_ Apache Geode cache client Web application defines the `SessionScopedProxyBean` domain class.
[source,java]
----
include::{samples-dir}boot/gemfire-with-scoped-proxies/src/main/java/sample/client/model/SessionScopedProxyBean[tags=class]
include::{samples-dir}boot/gemfire-with-scoped-proxies/src/main/java/sample/client/model/SessionScopedProxyBean.java[tags=class]
----
<1> First, the `SessionScopedProxyBean` domain class is stereotyped as a Spring `@Component` to be picked up in
_Spring's_ classpath component-scan.
<2> Additionally, instances of this class are scoped to the (HTTP) `Session`. That is, each time a client interaction
results in a (HTTP) Session being created (such as by a login event), a single instance of this type will be created
and will last for the duration of the (HTTP) Session. When the Session ends or expires, this instance is destroyed
by the _Spring_ container. If the client re-establishes a new (HTTP) Session, then another, new instance of this type
will be provided to the application's beans. However only ever 1 instance of this type exists for the duration
of the (HTTP) Session, no more!
<1> First, the `SessionScopedProxyBean` domain class is stereotyped as a _Spring_ `@Component` to be picked up by
_Spring's classpath component-scan_.
<2> Additionally, instances of this class are scoped to the `HttpSession`. Therefore, each time a client request
results in a new `HttpSession` (such as during a login event), a single instance of this class is created and will last
for the duration of the `HttpSession`. When the `HttpSession` ends or expires, this instance is destroyed by
the _Spring_ container. If the client re-establishes a new `HttpSession`, then another, new instance of this class
will be provided to the application's beans. However only ever 1 instance of this class exists for the duration of
the `HttpSession` and no more!
<3> Finally, this class keeps track of how many instances of this type are created by the _Spring_ container throughout
the entire lifecycle of the application.
the entire application lifecycle.
TIP: More information on Spring's `@SessionScope` (i.e. Session-scoped proxy beans) can be found in the
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes-other[Reference Documentation]
and specifically https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes-session[this].
TIP: More information on Spring's `@SessionScope` (i.e. "_session_" scope proxy beans) can be found in the
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes-other[Reference Documentation],
along with https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes-session[this].
=== Request-scoped Proxy Bean
The Geode cache client, Spring Web application defines the `RequestScopedProxyBean` class.
The _Spring Boot_ Apache Geode cache client Web application additionally defines the `RequestScopedProxyBean`
domain class.
[source,java]
----
include::{samples-dir}boot/gemfire-with-scoped-proxies/src/main/java/sample/client/model/RequestScopedProxyBean[tags=class]
include::{samples-dir}boot/gemfire-with-scoped-proxies/src/main/java/sample/client/model/RequestScopedProxyBean.java[tags=class]
----
<1> First, this `RequestScopedProxyBean` domain class is stereotyped as a Spring `@Component` to be picked up in
_Spring's_ classpath component-scan.
<2> Additionally, instances of this class are scoped to the (HTTP) Request. That is, each time a client request
is sent (e.g. to process a Thread-scoped transaction), a single instance of this type will be created and will last
for the duration of the (HTTP) Request. When the Request ends, this instance is destroyed by the _Spring_ container.
Any subsequent client (HTTP) Requests results in another, new instance of this type, which will be provided to
the application's beans. However, only ever 1 instance of this type exists for the duration of the (HTTP) Request,
no more!
<1> First, this `RequestScopedProxyBean` domain class is stereotyped as a _Spring_ `@Component` to be picked up by
_Spring's classpath component-scan_.
<2> Additionally, instances of this class are scoped to the `HttpServletRequest`. Therefore, each time a client HTTP
request is sent (e.g. to process a Thread-scoped transaction), a single instance of this class will be created
and will last for the duration of the `HttpServletRequest`. When the request ends, this instance is destroyed
by the _Spring_ container. Any subsequent client `HttpServletRequests` results in another, new instance of this
class, which will be provided to the application's beans. However, only ever 1 instance of this class exists
for the duration of the `HttpServletRequest` and no more!
<3> Finally, this class keeps track of how many instances of this type are created by the _Spring_ container throughout
the entire lifecycle of the application.
the entire application lifecycle.
TIP: More information on Spring's `@RequestScope` (i.e. Request-scoped proxy beans) can be found in the
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes-other[Reference Documentation]
and specifically, https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes-request[this].
TIP: More information on Spring's `@RequestScope` (i.e. "_request_" scope proxy beans) can be found in the
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes-other[Reference Documentation],
along with https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes-request[this].
[spring-session-sample-boot-geode-with-scoped-proxies]]
== Spring Boot Sample Web Application with Apache Geode-managed HttpSessions and Request and Session Scoped Proxy Beans
[[spring-session-sample-boot-geode-with-scoped-proxies]]
== Sample Spring Boot Web Application using Apache Geode-managed HttpSessions with Request and Session Scoped Proxy Beans
=== Running the Boot Sample Application
@@ -260,90 +261,123 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
First, you must run the server:
----
$ ./gradlew :spring-session-sample-boot-gemfire:run [-Dgemfire.log-level=config]
$ ./gradlew :spring-session-sample-boot-gemfire-with-scoped-proxies:run
----
Then, in a separate terminal, run the client:
----
$ ./gradlew :spring-session-sample-boot-gemfire:bootRun [-Dgemfire.log-level=config]
$ ./gradlew :spring-session-sample-boot-gemfire-with-scoped-proxies:bootRun
----
You should now be able to access the application at http://localhost:8080/.
You should now be able to access the application at http://localhost:8080/counts.
In this sample, the Web application is the _Spring Boot_, Apache Geode cache client
and the server is standalone, separate (JVM) process.
=== Exploring the Sample Application
=== Exploring the Boot Sample Application
When you access the Web application @ http://localhost:8080/counts, you will see a screen similar to...
Try using the application. Fill out the form with the following information:
image::{samples-dir}/boot/gemfire-with-scoped-proxies/sample-boot-gemfire-with-scoped-proxies.png[]
* **Attribute Name:** _username_
* **Attribute Value:** _test_
The table shows 1 row with 3 columns of information.
Now click the **Set Attribute** button. You should now see the attribute name and value displayed in the table
along with an additional attribute (`requestCount`) indicating the number of Session interactions (via HTTP requests).
The `Session ID` and `Session Count` columns show current `HttpSession` information including the current
`HttpSession's` ID along with the number of `HttpSessions` created during the (client) application's current run.
=== How does it work?
Additionally, the current `Request Count` is shown to indicate how many requests have been made by the client,
which in this case is your web browser.
We interact with the standard `javax.servlet.http.HttpSession` in the the Spring Web MVC service endpoint,
shown here for convenience:
You can use your web browser's refresh button to increase both the session and request count.
However, the session count only increases after the current session ends or times out and a new session
has been created for the client.
.src/main/java/sample/client/Application.java
[source,java]
The session will time out after *10 seconds*, which was configured on the server using the `@EnableGemFireHttpSession`
annotation as we saw before (#3)...
.src/main/java/sample/server/GemFireServer.java
[source, java]
----
@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;
@SpringBootApplication
@CacheServerApplication(name = "SpringSessionDataGeodeServerWithScopedProxiesBootSample")
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = 10) // <3>
...
public class GemFireServer {
...
}
----
Instead of using the embedded HTTP server's `HttpSession`, we are actually persisting the Session state in Apache Geode.
_Spring Session_ creates a cookie named SESSION in your browser that contains the id of your Session.
Go ahead and view the cookies (click for help with https://developer.chrome.com/devtools/docs/resources#cookies[Chrome]
or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]).
Here, you see that `maxInactiveIntervalInSeconds` is set to *10 seconds*. After 10 seconds, Apache Geode will expire
the `HttpSession`, and upon refreshing your web browser, a new session will be created and the session count
will increase.
NOTE: The following instructions assume you have a local Apache Geode installation. For more information on installation,
see http://geode.apache.org/docs/guide/12/prereq_and_install.html[Prerequisites and Installation Instructions].
However, every request naturally results in incrementing the request count.
If you like, you can easily remove the Session using `gfsh`.
=== How does it work?
For example, on a Linux-based system type the following at the command-line:
Well, from our defined Web service endpoint in our Spring MVC `@Controller` class on the client...
$ gfsh
.src/main/java/sample/client/Application.java
[source, java]
----
@RequestMapping(method = RequestMethod.GET, path = "/counts")
public String requestAndSessionInstanceCount(HttpServletRequest request, HttpSession session, Model model) { // <7>
Then, enter the following commands in _Gfsh_, ensuring to replace `70002719-3c54-4c20-82c3-e7faa6b718f3` with the value
of your SESSION cookie, or the Session id returned by the Apache Geode OQL query (which should match):
model.addAttribute("sessionId", session.getId());
model.addAttribute("requestCount", this.requestBean.getCount());
model.addAttribute("sessionCount", this.sessionBean.getCount());
....
gfsh>connect --jmx-manager=localhost[1099]
return INDEX_TEMPLATE_VIEW_NAME;
}
----
gfsh>query --query='SELECT * FROM /ClusteredSpringSessions.keySet'
We see that we have injected a reference to the `HttpSession` as a request mapping method handler parameter.
This will result in a new `HttpSession` on the client's first HTTP request. Subsequent requests from the same client
within the duration of the existing, current `HttpSession` will result in the same `HttpSession` being injected.
Result : true
startCount : 0
endCount : 20
Rows : 1
Of course, an `HttpSession` is identified by the session's identifier, which is stored in a Cookie sent between
the client and server during HTTP request processing.
Result
------------------------------------
70002719-3c54-4c20-82c3-e7faa6b718f3
Additionally, we also see that we have injected references to the `SessionScopedProxyBean` and `RequestScopedProxyBean`
in our `@Controller` class...
NEXT_STEP_NAME : END
.src/main/java/sample/client/Application.java
[source, java]
----
@Autowired
private RequestScopedProxyBean requestBean;
gfsh>remove --region=/ClusteredSpringSessions --key="70002719-3c54-4c20-82c3-e7faa6b718f3"
....
@Autowired
private SessionScopedProxyBean sessionBean;
----
NOTE: The _Apache Geode User Guide_ contains more detailed instructions on using
http://geode.apache.org/docs/guide/12/tools_modules/gfsh/chapter_overview.html[gfsh].
Based on the class definitions of these two types, as previously shown, these bean instances are scoped according
to _Spring's_ "_request_" and "_session_" scopes, respectively. The 2 scopes can only be used in Web applications.
Now visit the application at `http://localhost:8080/` again and observe the attribute we added is no longer displayed.
For each and every HTTP request sent by the client (i.e. on each web browser refresh), _Spring_ will create
a new instance of the `RequestScopedProxyBean`. This is why the request count increases with every refresh,
which effectively is sending another HTTP request to the server to access and pull the content.
Alternatively, you can wait **20 seconds** for the Session to timeout and expire and then refresh the page.
The attribute we added should no longer be displayed in the table.
Furthermore, after each new `HttpSession`, a new instance of `SessionScopedProxyBean` is created. This instance
persists for the duration of the session. If the `HttpSession` remains inactive (i.e. no request has been made)
for longer than *10 seconds*, the client's current `HttpSession` will expire. Therefore, on any subsequent client
HTTP request, a new `HttpSession` will be created by the Web container (e.g. Tomcat), which is replaced by
_Spring Session_ and backed with Apache Geode.
Additionally, this "_session_" scope bean is stored in the `HttpSession`, referenced by a session attribute.
Therefore, you will also notice that the `SessionScopedProxyBean` class, unlike the `RequestScopedProxyBean` class,
is also `java.io.Serializable`...
.src/main/java/sample/client/model/SessionScopedProxyBean.java
[source, java]
----
@Component
@SessionScope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SessionScopedProxyBean implements Serializable {
...
}
----
This class is `Serializable` since it is stored in the `HttpSession`, which will be transferred as part of
the `HttpSession` when sent to the Apache Geode cluster to be managed. Therefore, the type must be `Serializable`.
Any `RequestScopedProxyBeans` are not stored in the `HttpSession` and therefore will not be sent to the server,
and as such, do not need to be `Serializable`.