1
1
/*
2
- * Copyright 2002-2014 the original author or authors.
2
+ * Copyright 2002-2015 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
@@ -40,20 +40,36 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
40
40
41
41
private final ConcurrentMap <String , Cache > cacheMap = new ConcurrentHashMap <String , Cache >(16 );
42
42
43
- private Set <String > cacheNames = new LinkedHashSet < String >( 16 );
43
+ private volatile Set <String > cacheNames = Collections . emptySet ( );
44
44
45
45
46
46
// Early cache initialization on startup
47
47
48
48
@ Override
49
49
public void afterPropertiesSet () {
50
+ initializeCaches ();
51
+ }
52
+
53
+ /**
54
+ * Initialize the static configuration of caches.
55
+ * <p>Triggered on startup through {@link #afterPropertiesSet()};
56
+ * can also be called to re-initialize at runtime.
57
+ * @since 4.2.2
58
+ * @see #loadCaches()
59
+ */
60
+ public void initializeCaches () {
50
61
Collection <? extends Cache > caches = loadCaches ();
51
62
52
- // Preserve the initial order of the cache names
53
- this .cacheMap .clear ();
54
- this .cacheNames .clear ();
55
- for (Cache cache : caches ) {
56
- addCache (cache );
63
+ synchronized (this .cacheMap ) {
64
+ this .cacheNames = Collections .emptySet ();
65
+ this .cacheMap .clear ();
66
+ Set <String > cacheNames = new LinkedHashSet <String >(caches .size ());
67
+ for (Cache cache : caches ) {
68
+ String name = cache .getName ();
69
+ this .cacheMap .put (name , decorateCache (cache ));
70
+ cacheNames .add (name );
71
+ }
72
+ this .cacheNames = Collections .unmodifiableSet (cacheNames );
57
73
}
58
74
}
59
75
@@ -69,37 +85,79 @@ public void afterPropertiesSet() {
69
85
70
86
@ Override
71
87
public Cache getCache (String name ) {
72
- Cache cache = lookupCache (name );
88
+ Cache cache = this . cacheMap . get (name );
73
89
if (cache != null ) {
74
90
return cache ;
75
91
}
76
92
else {
77
- Cache missingCache = getMissingCache (name );
78
- if (missingCache != null ) {
79
- addCache (missingCache );
80
- return lookupCache (name ); // may be decorated
93
+ // Fully synchronize now for missing cache creation...
94
+ synchronized (this .cacheMap ) {
95
+ cache = this .cacheMap .get (name );
96
+ if (cache == null ) {
97
+ cache = getMissingCache (name );
98
+ if (cache != null ) {
99
+ cache = decorateCache (cache );
100
+ this .cacheMap .put (name , cache );
101
+ updateCacheNames (name );
102
+ }
103
+ }
104
+ return cache ;
81
105
}
82
- return null ;
83
106
}
84
107
}
85
108
86
109
@ Override
87
110
public Collection <String > getCacheNames () {
88
- return Collections . unmodifiableSet ( this .cacheNames ) ;
111
+ return this .cacheNames ;
89
112
}
90
113
91
114
92
- // Common cache initialization delegates/callbacks
115
+ // Common cache initialization delegates for subclasses
116
+
117
+ /**
118
+ * Check for a registered cache of the given name.
119
+ * In contrast to {@link #getCache(String)}, this method does not trigger
120
+ * the lazy creation of missing caches via {@link #getMissingCache(String)}.
121
+ * @param name the cache identifier (must not be {@code null})
122
+ * @return the associated Cache instance, or {@code null} if none found
123
+ * @since 4.1
124
+ * @see #getCache(String)
125
+ * @see #getMissingCache(String)
126
+ */
127
+ protected final Cache lookupCache (String name ) {
128
+ return this .cacheMap .get (name );
129
+ }
93
130
131
+ /**
132
+ * Dynamically register an additional Cache with this manager.
133
+ * @param cache the Cache to register
134
+ */
94
135
protected final void addCache (Cache cache ) {
95
- this .cacheMap .put (cache .getName (), decorateCache (cache ));
96
- this .cacheNames .add (cache .getName ());
136
+ String name = cache .getName ();
137
+ synchronized (this .cacheMap ) {
138
+ if (this .cacheMap .put (name , decorateCache (cache )) == null ) {
139
+ updateCacheNames (name );
140
+ }
141
+ }
97
142
}
98
143
99
- protected final Cache lookupCache (String name ) {
100
- return this .cacheMap .get (name );
144
+ /**
145
+ * Update the exposed {@link #cacheNames} set with the given name.
146
+ * <p>This will always be called within a full {@link #cacheMap} lock
147
+ * and effectively behaves like a {@code CopyOnWriteArraySet} with
148
+ * preserved order but exposed as an unmodifiable reference.
149
+ * @param name the name of the cache to be added
150
+ */
151
+ private void updateCacheNames (String name ) {
152
+ Set <String > cacheNames = new LinkedHashSet <String >(this .cacheNames .size () + 1 );
153
+ cacheNames .addAll (this .cacheNames );
154
+ cacheNames .add (name );
155
+ this .cacheNames = Collections .unmodifiableSet (cacheNames );
101
156
}
102
157
158
+
159
+ // Overridable template methods for cache initialization
160
+
103
161
/**
104
162
* Decorate the given Cache object if necessary.
105
163
* @param cache the Cache object to be added to this CacheManager
@@ -120,6 +178,7 @@ protected Cache decorateCache(Cache cache) {
120
178
* @param name the name of the cache to retrieve
121
179
* @return the missing cache or {@code null} if no such cache exists or could be
122
180
* created
181
+ * @since 4.1
123
182
* @see #getCache(String)
124
183
*/
125
184
protected Cache getMissingCache (String name ) {
0 commit comments