View Javadoc
1   /*
2    *    Copyright 2010-2026 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       https://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.mybatis.caches.ehcache;
17  
18  import net.sf.ehcache.Ehcache;
19  import net.sf.ehcache.Element;
20  import net.sf.ehcache.constructs.blocking.BlockingCache;
21  
22  /**
23   * Cache implementation that wraps Ehcache 2 with {@link BlockingCache} semantics.
24   * <p>
25   * {@link BlockingCache} acquires a per-key lock when a cache miss occurs so that only one thread computes the missing
26   * value while others block. This prevents cache-stampede on a cold or expired entry.
27   * </p>
28   *
29   * @author Iwao AVE!
30   */
31  public class EhBlockingCache extends AbstractEhcacheCache {
32  
33    /**
34     * Instantiates a new eh blocking cache.
35     *
36     * @param id
37     *          the id
38     */
39    public EhBlockingCache(final String id) {
40      super(id);
41      if (!CACHE_MANAGER.cacheExists(id)) {
42        CACHE_MANAGER.addCache(this.id);
43        Ehcache ehcache = CACHE_MANAGER.getEhcache(this.id);
44        BlockingCache blockingCache = new BlockingCache(ehcache);
45        CACHE_MANAGER.replaceCacheWithDecoratedCache(ehcache, blockingCache);
46      }
47      this.cache = CACHE_MANAGER.getEhcache(id);
48    }
49  
50    @Override
51    public Object removeObject(Object key) {
52      // this method is called during a rollback just to
53      // release any previous lock
54      cache.put(new Element(key, null));
55      return null;
56    }
57  
58    /**
59     * {@inheritDoc}
60     * <p>
61     * Re-wraps the rebuilt cache in a {@link BlockingCache} after replacing it.
62     * </p>
63     */
64    @Override
65    protected void rebuildCacheWith(net.sf.ehcache.config.CacheConfiguration newConfig) {
66      CACHE_MANAGER.removeCache(id);
67      CACHE_MANAGER.addCache(new net.sf.ehcache.Cache(newConfig));
68      Ehcache ehcache = CACHE_MANAGER.getEhcache(id);
69      BlockingCache blockingCache = new BlockingCache(ehcache);
70      CACHE_MANAGER.replaceCacheWithDecoratedCache(ehcache, blockingCache);
71      this.cache = CACHE_MANAGER.getEhcache(id);
72    }
73  
74  }