Reputation: 835
I have this Spring webservice test code:
@RestController
@RequestMapping("/counter")
public class CounterController
{
@Autowired
private Counter counter;
@RequestMapping(value = "/inc", method = GET)
public int inc() throws Exception {
counter.incCounter();
return counter.getCounter();
}
@RequestMapping(value = "/get", method = GET)
public int get() throws Exception {
Thread.sleep(5000);
return counter.getCounter();
}
}
where Counter is a session scoped object
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Counter implements Serializable {
private static final long serialVersionUID = 9162936878293396831L;
private int value;
public int getCounter() {
return value;
}
public void incCounter() {
value += 1;
}
}
The session configuration
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds=1800)
public class HttpSessionConfig {
@Bean
public JedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory();
}
@Bean
public HttpSessionStrategy httpSessionStrategy(){
return new HeaderHttpSessionStrategy();
}
}
As you can see the get()
method sleeps 5 secons and returns the value of the counter.
The problem is that if I call inc()
many times during the execution of the get()
all the counter changes are lost because when get()
finishes returns the value of the counter that it has when started the execution. The weird problem is that get()
when finishes persists the counter (It is a session object) and when this operation is done all the changes are lost.
Does exist a way to prevent that functions that do not modify a session object not persist it?
Update: I think that the Spring code corroborates this wrong behavior. This snippet of code of the class ServletRequestAttributes
shows that every session object that is accessed (regardless if the access is for read) is marked to be saved when the webservice operation finishes:
@Override
public Object getAttribute(String name, int scope) {
if (scope == SCOPE_REQUEST) {
if (!isRequestActive()) {
throw new IllegalStateException(
"Cannot ask for request attribute - request is not active anymore!");
}
return this.request.getAttribute(name);
}
else {
HttpSession session = getSession(false);
if (session != null) {
try {
Object value = session.getAttribute(name);
if (value != null) {
this.sessionAttributesToUpdate.put(name, value);
}
return value;
}
catch (IllegalStateException ex) {
// Session invalidated - shouldn't usually happen.
}
}
return null;
}
}
According to the Spring Session documentation:
Optimized Writes
The Session instances managed by RedisOperationsSessionRepository keeps track of the properties that have changed and only updates those. This means if an attribute is written once and read many times we only need to write that attribute once.
Or the documentation is wrong or I'm doing something wrong.
Upvotes: 0
Views: 880
Reputation: 835
It seems that it is nothing to do with this problem, this is the expected behavior of Spring Session with session scoped beans. For me it 's a critical problem and I've decided forget distributed caches (Redis
and Hazelcast
) and use the MapSessionRepository
Upvotes: 0
Reputation: 3686
I think You did some mistakes while testing Your code. I have just tested it, and it works as expected.
I have used SoapUI, created 2 request's with the same JSESSIONID
value in Cookie (same session).
Then I requested for /get, and meanwhile in second request window, i spammed /inc.
What /get returned was the number of /inc. (at the beggining value was 0 , than I have incremented it to 11 while /get was sleeping. Finally, /get returned 11).
I suggest You double check if nothing is messed up with Your session.
Edit: Your code with additional logs: (I've increased the sleeping time to 10000):
2016-04-06 11:56:10.977 INFO 7884 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 14 ms
2016-04-06 11:56:11.014 INFO 7884 --- [nio-8080-exec-1] c.p.controller.TestServiceController : Before 10sec counter value: 0
2016-04-06 11:56:21.015 INFO 7884 --- [nio-8080-exec-1] c.p.controller.TestServiceController : After 10sec counter value: 0
2016-04-06 11:56:36.955 INFO 7884 --- [nio-8080-exec-2] c.p.controller.TestServiceController : Before 10sec counter value: 0
2016-04-06 11:56:46.956 INFO 7884 --- [nio-8080-exec-2] c.p.controller.TestServiceController : After 10sec counter value: 0
2016-04-06 11:56:50.558 INFO 7884 --- [nio-8080-exec-3] c.p.controller.TestServiceController : Incrementing counter value: 1
2016-04-06 11:56:53.494 INFO 7884 --- [nio-8080-exec-4] c.p.controller.TestServiceController : Before 10sec counter value: 1
2016-04-06 11:57:03.496 INFO 7884 --- [nio-8080-exec-4] c.p.controller.TestServiceController : After 10sec counter value: 1
2016-04-06 11:57:05.600 INFO 7884 --- [nio-8080-exec-5] c.p.controller.TestServiceController : Before 10sec counter value: 1
2016-04-06 11:57:06.715 INFO 7884 --- [nio-8080-exec-6] c.p.controller.TestServiceController : Incrementing counter value: 2
2016-04-06 11:57:06.869 INFO 7884 --- [nio-8080-exec-7] c.p.controller.TestServiceController : Incrementing counter value: 3
2016-04-06 11:57:07.038 INFO 7884 --- [nio-8080-exec-8] c.p.controller.TestServiceController : Incrementing counter value: 4
2016-04-06 11:57:07.186 INFO 7884 --- [nio-8080-exec-9] c.p.controller.TestServiceController : Incrementing counter value: 5
2016-04-06 11:57:07.321 INFO 7884 --- [io-8080-exec-10] c.p.controller.TestServiceController : Incrementing counter value: 6
2016-04-06 11:57:07.478 INFO 7884 --- [nio-8080-exec-1] c.p.controller.TestServiceController : Incrementing counter value: 7
2016-04-06 11:57:07.641 INFO 7884 --- [nio-8080-exec-2] c.p.controller.TestServiceController : Incrementing counter value: 8
2016-04-06 11:57:07.794 INFO 7884 --- [nio-8080-exec-3] c.p.controller.TestServiceController : Incrementing counter value: 9
2016-04-06 11:57:07.967 INFO 7884 --- [nio-8080-exec-4] c.p.controller.TestServiceController : Incrementing counter value: 10
2016-04-06 11:57:08.121 INFO 7884 --- [nio-8080-exec-6] c.p.controller.TestServiceController : Incrementing counter value: 11
2016-04-06 11:57:15.602 INFO 7884 --- [nio-8080-exec-5] c.p.controller.TestServiceController : After 10sec counter value: 11
Upvotes: 1