[SPRING] Spring Cache @Cacheable - 같은 빈의 다른 메소드에서 호출하는 동안 작동하지 않는다.
SPRINGSpring Cache @Cacheable - 같은 빈의 다른 메소드에서 호출하는 동안 작동하지 않는다.
같은 bean의 다른 메소드에서 캐시 된 메소드를 호출 할 때 스프링 캐시가 작동하지 않습니다.
여기 내 문제를 명확한 방법으로 설명하는 예제가 있습니다.
구성 :
<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에 있음) 내에서 호출되면 캐시가 사용되지 않습니다.
스프링 캐쉬가 작동하는 방식인가요, 뭔가 빠진 것입니까?
해결법
-
==============================
1.나는 이것이 그것이 어떻게 작동하는지 믿습니다. 내가 읽은 것을 보면, 모든 요청을 차단하고 캐시 된 값으로 응답하는 프록시 클래스가 생성되지만 동일한 클래스 내의 '내부'호출은 캐시 된 값을 가져 오지 않습니다.
나는 이것이 그것이 어떻게 작동하는지 믿습니다. 내가 읽은 것을 보면, 모든 요청을 차단하고 캐시 된 값으로 응답하는 프록시 클래스가 생성되지만 동일한 클래스 내의 '내부'호출은 캐시 된 값을 가져 오지 않습니다.
https://code.google.com/p/ehcache-spring-annotations/wiki/UsingCacheable에서
-
==============================
2.아래 예제는 같은 빈에서 프록시를 치기 위해 사용하는 예제입니다. @ mario-eis '솔루션과 비슷하지만 좀 더 읽기 쉽습니다 (아마도 그렇지는 않습니다 :-). 어쨌든 서비스 수준에서 @Cacheable 주석을 유지하고 싶습니다.
아래 예제는 같은 빈에서 프록시를 치기 위해 사용하는 예제입니다. @ 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에서 새로운 트랜잭션 시작하기
-
==============================
3.Spring 4.3부터 @Resource 주석 위에 self-autowiring을 사용하면 문제를 해결할 수있다.
Spring 4.3부터 @Resource 주석 위에 self-autowiring을 사용하면 문제를 해결할 수있다.
@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); } }
-
==============================
4.같은 클래스 내에서 메소드 호출을 거의 사용하지 않는 소규모 프로젝트에서 내가하는 일은 다음과 같습니다. 동료에게 스트레스를 줄 수 있으므로 코드 내 문서가 강력하게 권고됩니다. 그러나 테스트하기 쉽고, 간단하고, 빠르게 달성 할 수 있으며, 완전히 손상된 AspectJ 장비를 절약 할 수 있습니다. 그러나, 더 많은 사용량에 대해 나는 AspectJ 솔루션에 대한 조언을 원한다.
같은 클래스 내에서 메소드 호출을 거의 사용하지 않는 소규모 프로젝트에서 내가하는 일은 다음과 같습니다. 동료에게 스트레스를 줄 수 있으므로 코드 내 문서가 강력하게 권고됩니다. 그러나 테스트하기 쉽고, 간단하고, 빠르게 달성 할 수 있으며, 완전히 손상된 AspectJ 장비를 절약 할 수 있습니다. 그러나, 더 많은 사용량에 대해 나는 AspectJ 솔루션에 대한 조언을 원한다.
@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); ... } }
-
==============================
5.static weaving을 사용하여 bean 주위에 프록시를 작성하십시오. 이 경우에도 '내부'메소드가 올바르게 작동합니다.
static weaving을 사용하여 bean 주위에 프록시를 작성하십시오. 이 경우에도 '내부'메소드가 올바르게 작동합니다.
-
==============================
6.내 경우에는 변수를 추가합니다.
내 경우에는 변수를 추가합니다.
@Autowired private AService aService;
그래서 나는 Service를 사용하여 Employee Data 메소드를 호출한다.
@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); ... }
}
이 경우 캐시를 사용합니다.
-
==============================
7.이 목적을 위해 내부 캐시 (FactoryInternalCache)와 내부 내부 bean을 사용합니다.
이 목적을 위해 내부 캐시 (FactoryInternalCache)와 내부 내부 bean을 사용합니다.
@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); } } }
from https://stackoverflow.com/questions/16899604/spring-cache-cacheable-not-working-while-calling-from-another-method-of-the-s by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Autowiring으로 Spring 통합 테스트가 느립니다. (0) | 2019.01.26 |
---|---|
[SPRING] HibernateJpaVendorAdapter 문제 대신 EclipseLinkJpaVendorAdapter (0) | 2019.01.26 |
[SPRING] @Qualifier와 @Resource의 차이점 (0) | 2019.01.26 |
[SPRING] 스프링 부트 데이터 JPA - 업데이트 쿼리 수정 - 지속성 컨텍스트 새로 고침 (0) | 2019.01.26 |
[SPRING] HandlerInterceptorAdapter에서 서비스를 Autowire 할 수 없습니다. [duplicate] (0) | 2019.01.26 |