Spring Cache @Cacheable-동일한 Bean의 다른 메소드에서 호출하는 동안 작동하지 않음
동일한 Bean의 다른 메소드에서 캐시 된 메소드를 호출 할 때 Spring 캐시가 작동하지 않습니다.
다음은 내 문제를 명확하게 설명하는 예입니다.
구성 :
<cache:annotation-driven cache-manager="myCacheManager" />
<bean id="myCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="myCache" />
</bean>
<!-- Ehcache library setup -->
<bean id="myCache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:shared="true">
<property name="configLocation" value="classpath:ehcache.xml"></property>
</bean>
<cache name="employeeData" maxElementsInMemory="100"/>
캐시 된 서비스 :
@Named("aService")
public class AService {
@Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = getEmployeeData(date);
...
}
}
결과 :
aService.getEmployeeData(someDate);
output: Cache is not being used
aService.getEmployeeData(someDate);
output:
aService.getEmployeeEnrichedData(someDate);
output: Cache is not being used
getEmployeeData
메소드 호출의 사용은 캐시 employeeData
예상대로 두 번째 호출에. 그러나 클래스 getEmployeeData
내 에서 메서드가 호출 되면 AService
( getEmployeeEnrichedData
) Cache가 사용되지 않습니다.
이것이 스프링 캐시가 작동하는 방식입니까 아니면 내가 뭔가를 놓치고 있습니까?
나는 이것이 작동하는 방식이라고 믿습니다. 내가 읽은 내용에서 모든 요청을 가로 채고 캐시 된 값으로 응답하는 프록시 클래스가 생성되었지만 동일한 클래스 내의 '내부'호출은 캐시 된 값을 얻지 못합니다.
에서 https://code.google.com/p/ehcache-spring-annotations/wiki/UsingCacheable
프록시를 통해 들어오는 외부 메서드 호출 만 차단됩니다. 즉, 자체 호출은 실제로 대상 개체의 다른 메서드를 호출하는 대상 개체 내의 메서드가 호출 된 메서드가 @Cacheable로 표시되어 있더라도 런타임에 실제 캐시 가로 채기로 이어지지 않음을 의미합니다.
Spring 4.3부터 주석에 대한 자체 자동 배선 을 사용하여 문제를 해결할 수 있습니다 @Resource
.
@Component
@CacheConfig(cacheNames = "SphereClientFactoryCache")
public class CacheableSphereClientFactoryImpl implements SphereClientFactory {
/**
* 1. Self-autowired reference to proxified bean of this class.
*/
@Resource
private SphereClientFactory self;
@Override
@Cacheable(sync = true)
public SphereClient createSphereClient(@Nonnull TenantConfig tenantConfig) {
// 2. call cached method using self-bean
return self.createSphereClient(tenantConfig.getSphereClientConfig());
}
@Override
@Cacheable(sync = true)
public SphereClient createSphereClient(@Nonnull SphereClientConfig clientConfig) {
return CtpClientConfigurationUtils.createSphereClient(clientConfig);
}
}
아래 예제는 동일한 빈 내에서 프록시를 누르는 데 사용하는 것입니다. @ mario-eis의 솔루션과 비슷하지만 조금 더 읽기 쉽습니다 (아마도 :-가 아닐 수도 있습니다). 어쨌든 서비스 수준에서 @Cacheable 주석을 유지하고 싶습니다.
@Service
@Transactional(readOnly=true)
public class SettingServiceImpl implements SettingService {
@Inject
private SettingRepository settingRepository;
@Inject
private ApplicationContext applicationContext;
@Override
@Cacheable("settingsCache")
public String findValue(String name) {
Setting setting = settingRepository.findOne(name);
if(setting == null){
return null;
}
return setting.getValue();
}
@Override
public Boolean findBoolean(String name) {
String value = getSpringProxy().findValue(name);
if (value == null) {
return null;
}
return Boolean.valueOf(value);
}
/**
* Use proxy to hit cache
*/
private SettingService getSpringProxy() {
return applicationContext.getBean(SettingService.class);
}
...
Spring Bean에서 새 트랜잭션 시작 도 참조하십시오.
Here is what I do for small projects with only marginal usage of method calls within the same class. In-code documentation is strongly advidsed, as it may look strage to colleagues. But its easy to test, simple, quick to achieve and spares me the full blown AspectJ instrumentation. However, for more heavy usage I'd advice the AspectJ solution.
@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class AService {
private final AService _aService;
@Autowired
public AService(AService aService) {
_aService = aService;
}
@Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = _aService.getEmployeeData(date);
...
}
}
Use static weaving to create proxy around your bean. In this case even 'internal' methods would work correctly
In my Case I add variable :
@Autowired
private AService aService;
So I call the getEmployeeData
method by using the aService
@Named("aService")
public class AService {
@Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = aService.getEmployeeData(date);
...
}
}
It will use the cache in this case.
I use internal inner bean (FactoryInternalCache
) with real cache for this purpose:
@Component
public class CacheableClientFactoryImpl implements ClientFactory {
private final FactoryInternalCache factoryInternalCache;
@Autowired
public CacheableClientFactoryImpl(@Nonnull FactoryInternalCache factoryInternalCache) {
this.factoryInternalCache = factoryInternalCache;
}
/**
* Returns cached client instance from cache.
*/
@Override
public Client createClient(@Nonnull AggregatedConfig aggregateConfig) {
return factoryInternalCache.createClient(aggregateConfig.getClientConfig());
}
/**
* Returns cached client instance from cache.
*/
@Override
public Client createClient(@Nonnull ClientConfig clientConfig) {
return factoryInternalCache.createClient(clientConfig);
}
/**
* Spring caching feature works over AOP proxies, thus internal calls to cached methods don't work. That's why
* this internal bean is created: it "proxifies" overloaded {@code #createClient(...)} methods
* to real AOP proxified cacheable bean method {@link #createClient}.
*
* @see <a href="https://stackoverflow.com/questions/16899604/spring-cache-cacheable-not-working-while-calling-from-another-method-of-the-s">Spring Cache @Cacheable - not working while calling from another method of the same bean</a>
* @see <a href="https://stackoverflow.com/questions/12115996/spring-cache-cacheable-method-ignored-when-called-from-within-the-same-class">Spring cache @Cacheable method ignored when called from within the same class</a>
*/
@EnableCaching
@CacheConfig(cacheNames = "ClientFactoryCache")
static class FactoryInternalCache {
@Cacheable(sync = true)
public Client createClient(@Nonnull ClientConfig clientConfig) {
return ClientCreationUtils.createClient(clientConfig);
}
}
}
'Program Tip' 카테고리의 다른 글
2D 배열의 크기는 어떻게 찾습니까? (0) | 2020.10.09 |
---|---|
Java의 기존 파일에 새 텍스트 줄을 추가하는 방법은 무엇입니까? (0) | 2020.10.09 |
Ubuntu의 php 5.6에 php-zip 설치 (0) | 2020.10.09 |
내 info.plist 및 .pch 파일이 어디에 있는지 Xcode에 알리는 방법 (0) | 2020.10.09 |
사용자 지정 알림 레이아웃 및 텍스트 색상 (0) | 2020.10.09 |