Issue
The sses
Map has been moved from MessageController class to a class annotated with @Service MessageTemplate.class
. Now we need a way to add SseEmitter
instances (created inside openConn()
) to the sses map inside MessageTemplate class.
Map may not be the best choice here, if so, what other cache alternatives available because I need a away to send messages back to individual clients?
@Controller
@RequestMapping(value="/")
public class MessageController{
@Autowired MessageOperations mesgOps;
//Moved to MessageTemplate
Map<String, SseEmitter> sses = new ConcurrentHashMap<>();
@GetMapping(value = "/conn/{username}")
public SseEmitter openConn(@PathVariable("username") String username){
SseEmitter sseEmitter = new SseEmitter(3600000L);
sses.put(username, sseEmitter);
return sseEmitter;
}
@Service
public class MessageTemplate implements MessageOperations{
//The above map now resides here.
Map<String, SseEmitter> sses = new ConcurrentHashMap<>();
..
}
Solution
Assuming, all the presented abstraction in the question are “custom” (the code that was written in your organization) and do not belong to spring ecosystem by themselves, I see the following:
- A
MessageTemplate
is a singleton-scoped bean driven by spring - The controller is also a singleton bean.
MessageOperations
interface is your custom interface that you’re using for injection.
In this case the obvious change would be:
interface MessageOperations {
SseEmitter associateSseEmitterWithUser(String userName);
}
@Service
public class MessageTemplate implements MessageOperations {
private Map<String, SseEmitter> sses = new ConcurrentHashMap<>();
// other existing code you might already have
public SseEmitter associateSseEmitterWithUser(String username) {
SseEmitter sseEmitter = new SseEmitter(3600000L);
sses.put(username, sseEmitter);
return sseEmitter;
}
}
@Controller
@RequestMapping(value = “/“)
public class MessageController {
@Autowired MessageOperations mesgOps;
@GetMapping(value=“/conn/{username})
public SseEmitter openConn(@PathVariable(“username”) String username) {
return mesgOps.associateSseEmitterWithUser(username);
}
}
Answered By - Mark Bramnik
Answer Checked By - Clifford M. (JavaFixing Volunteer)