订阅者注册中心
org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry
1、访问缓存
2、更新缓存
3、数据存储
org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry.DestinationCache
private class DestinationCache {
/** Map from destination -> <sessionId, subscriptionId> for fast look-ups */
private final Map<String, LinkedMultiValueMap<String, String>> accessCache =
new ConcurrentHashMap<String, LinkedMultiValueMap<String, String>>(DEFAULT_CACHE_LIMIT);
/** Map from destination -> <sessionId, subscriptionId> with locking */
@SuppressWarnings("serial")
private final Map<String, LinkedMultiValueMap<String, String>> updateCache =
new LinkedHashMap<String, LinkedMultiValueMap<String, String>>(DEFAULT_CACHE_LIMIT, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<String, LinkedMultiValueMap<String, String>> eldest) {
if (size() > getCacheLimit()) {
accessCache.remove(eldest.getKey());
return true;
}
else {
return false;
}
}
};
public LinkedMultiValueMap<String, String> getSubscriptions(String destination, Message<?> message) {
LinkedMultiValueMap<String, String> result = this.accessCache.get(destination);
if (result == null) {
synchronized (this.updateCache) {
result = new LinkedMultiValueMap<String, String>();
for (SessionSubscriptionInfo info : subscriptionRegistry.getAllSubscriptions()) {
for (String destinationPattern : info.getDestinations()) {
if (getPathMatcher().match(destinationPattern, destination)) {
for (Subscription subscription : info.getSubscriptions(destinationPattern)) {
result.add(info.sessionId, subscription.getId());
}
}
}
}
if (!result.isEmpty()) {
this.updateCache.put(destination, result.deepCopy());
this.accessCache.put(destination, result);
}
}
}
return result;
}
public void updateAfterNewSubscription(String destination, String sessionId, String subsId) {
synchronized (this.updateCache) {
for (Map.Entry<String, LinkedMultiValueMap<String, String>> entry : this.updateCache.entrySet()) {
String cachedDestination = entry.getKey();
if (getPathMatcher().match(destination, cachedDestination)) {
LinkedMultiValueMap<String, String> subs = entry.getValue();
subs.add(sessionId, subsId);
this.accessCache.put(cachedDestination, subs.deepCopy());
}
}
}
}
public void updateAfterRemovedSubscription(String sessionId, String subsId) {
synchronized (this.updateCache) {
Set<String> destinationsToRemove = new HashSet<String>();
for (Map.Entry<String, LinkedMultiValueMap<String, String>> entry : this.updateCache.entrySet()) {
String destination = entry.getKey();
LinkedMultiValueMap<String, String> sessionMap = entry.getValue();
List<String> subscriptions = sessionMap.get(sessionId);
if (subscriptions != null) {
subscriptions.remove(subsId);
if (subscriptions.isEmpty()) {
sessionMap.remove(sessionId);
}
if (sessionMap.isEmpty()) {
destinationsToRemove.add(destination);
}
else {
this.accessCache.put(destination, sessionMap.deepCopy());
}
}
}
for (String destination : destinationsToRemove) {
this.updateCache.remove(destination);
this.accessCache.remove(destination);
}
}
}
public void updateAfterRemovedSession(SessionSubscriptionInfo info) {
synchronized (this.updateCache) {
Set<String> destinationsToRemove = new HashSet<String>();
for (Map.Entry<String, LinkedMultiValueMap<String, String>> entry : this.updateCache.entrySet()) {
String destination = entry.getKey();
LinkedMultiValueMap<String, String> sessionMap = entry.getValue();
if (sessionMap.remove(info.getSessionId()) != null) {
if (sessionMap.isEmpty()) {
destinationsToRemove.add(destination);
}
else {
this.accessCache.put(destination, sessionMap.deepCopy());
}
}
}
for (String destination : destinationsToRemove) {
this.updateCache.remove(destination);
this.accessCache.remove(destination);
}
}
}
@Override
public String toString() {
return "cache[" + this.accessCache.size() + " destination(s)]";
}
}