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.