001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.cache.transaction; 018 019import java.util.concurrent.Callable; 020 021import org.springframework.cache.Cache; 022import org.springframework.lang.Nullable; 023import org.springframework.transaction.support.TransactionSynchronizationAdapter; 024import org.springframework.transaction.support.TransactionSynchronizationManager; 025import org.springframework.util.Assert; 026 027/** 028 * Cache decorator which synchronizes its {@link #put}, {@link #evict} and 029 * {@link #clear} operations with Spring-managed transactions (through Spring's 030 * {@link TransactionSynchronizationManager}, performing the actual cache 031 * put/evict/clear operation only in the after-commit phase of a successful 032 * transaction. If no transaction is active, {@link #put}, {@link #evict} and 033 * {@link #clear} operations will be performed immediately, as usual. 034 * 035 * <p><b>Note:</b> Use of immediate operations such as {@link #putIfAbsent} and 036 * {@link #evictIfPresent} cannot be deferred to the after-commit phase of a 037 * running transaction. Use these with care in a transactional environment. 038 * 039 * @author Juergen Hoeller 040 * @author Stephane Nicoll 041 * @author Stas Volsky 042 * @since 3.2 043 * @see TransactionAwareCacheManagerProxy 044 */ 045public class TransactionAwareCacheDecorator implements Cache { 046 047 private final Cache targetCache; 048 049 050 /** 051 * Create a new TransactionAwareCache for the given target Cache. 052 * @param targetCache the target Cache to decorate 053 */ 054 public TransactionAwareCacheDecorator(Cache targetCache) { 055 Assert.notNull(targetCache, "Target Cache must not be null"); 056 this.targetCache = targetCache; 057 } 058 059 060 /** 061 * Return the target Cache that this Cache should delegate to. 062 */ 063 public Cache getTargetCache() { 064 return this.targetCache; 065 } 066 067 @Override 068 public String getName() { 069 return this.targetCache.getName(); 070 } 071 072 @Override 073 public Object getNativeCache() { 074 return this.targetCache.getNativeCache(); 075 } 076 077 @Override 078 @Nullable 079 public ValueWrapper get(Object key) { 080 return this.targetCache.get(key); 081 } 082 083 @Override 084 public <T> T get(Object key, @Nullable Class<T> type) { 085 return this.targetCache.get(key, type); 086 } 087 088 @Override 089 @Nullable 090 public <T> T get(Object key, Callable<T> valueLoader) { 091 return this.targetCache.get(key, valueLoader); 092 } 093 094 @Override 095 public void put(final Object key, @Nullable final Object value) { 096 if (TransactionSynchronizationManager.isSynchronizationActive()) { 097 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { 098 @Override 099 public void afterCommit() { 100 TransactionAwareCacheDecorator.this.targetCache.put(key, value); 101 } 102 }); 103 } 104 else { 105 this.targetCache.put(key, value); 106 } 107 } 108 109 @Override 110 @Nullable 111 public ValueWrapper putIfAbsent(Object key, @Nullable Object value) { 112 return this.targetCache.putIfAbsent(key, value); 113 } 114 115 @Override 116 public void evict(final Object key) { 117 if (TransactionSynchronizationManager.isSynchronizationActive()) { 118 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { 119 @Override 120 public void afterCommit() { 121 TransactionAwareCacheDecorator.this.targetCache.evict(key); 122 } 123 }); 124 } 125 else { 126 this.targetCache.evict(key); 127 } 128 } 129 130 @Override 131 public boolean evictIfPresent(Object key) { 132 return this.targetCache.evictIfPresent(key); 133 } 134 135 @Override 136 public void clear() { 137 if (TransactionSynchronizationManager.isSynchronizationActive()) { 138 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { 139 @Override 140 public void afterCommit() { 141 targetCache.clear(); 142 } 143 }); 144 } 145 else { 146 this.targetCache.clear(); 147 } 148 } 149 150 @Override 151 public boolean invalidate() { 152 return this.targetCache.invalidate(); 153 } 154 155}