我在一個類中有一個@Cacheable 方法。我嘗試在第一次呼叫該方法后創建該快取,然后,第二次呼叫不應進入方法getCacheLeads。
@Service
public class LeadService {
@Autowired
private LeadRepository leadRepository;
@Autowired
public LeadService(LeadRepository leadRepository) {
this.leadRepository = leadRepository;
}
public void calculateLead(Lead leadBean) {
Lead lead = this.getCacheLeads(leadBean);
}
@Cacheable(cacheNames="leads", key="#leadBean.leadId")
public Lead getCacheLeads(Lead leadBean){
Lead result = leadRepository.findByLeadId(leadBean.getLeadId());
***logic to transform de Lead object***
return result;
}
}
但是在測驗期間,從不使用快取,使用相同的引數(serviceIsCalled)呼叫它兩次以確保它被呼叫兩次來檢查它。
@ExtendWith(SpringExtension.class)
public class LeadServiceTest {
private LeadService leadService;
@Mock
private LeadRepository leadRepository;
@Autowired
CacheManager cacheManager;
@BeforeEach
public void setUp(){
leadService = new LeadService(leadRepository);
}
@Configuration
@EnableCaching
static class Config {
@Bean
CacheManager cacheManager() {
return new ConcurrentMapCacheManager("leads");
}
}
@Test
public void testLead(){
givenData();
serviceIsCalled();
serviceIsCalled();
checkDataArray();
}
private void givenData() {
Lead lead = new Lead();
lead.setLeadId("DC635EA19A39EA128764BB99052E5D1A9A");
Mockito.when(leadRepository.findByLeadId(any()))
.thenReturn(lead);
}
private void serviceIsCalled(){
Lead lead = new Lead();
lead.setLeadId("DC635EA19A39EA128764BB99052E5D1A9A");
leadService.calculateLead(lead);
}
private void checkDataArray(){
verify(leadRepository, times(1)).findByLeadId(anyString());
}
}
為什么叫它2次?
uj5u.com熱心網友回復:
您在這里發生了很多事情,看到這個并回答您的問題的人肯定必須在字里行間閱讀。
首先,您的 Spring 配置甚至都不正確。您正在使用接受快取名稱陣列作為引數的ConcurrentMapCacheManager 建構式“靜態”宣告 Spring 應用程式(和測驗)使用的所有快取的名稱。
注意:由名稱明確標識的快取,并且只有這些快取在運行時可用。
@Bean
CacheManager cacheManager() {
return new ConcurrentMapCacheManager("LEAD_DATA");
}
在這種情況下,您的第一個也是唯一的快取稱為“LEAD_DATA”。
注意:只有 `ConcurrentMapCacheManager 中的無引數建構式允許在運行時按名稱動態創建快取。
但隨后,在您的@Service LeadService類、@Cacheable getCacheLeads(:Lead)方法中,您將快取宣告為用作“線索”。
@Service
public class LeadService {
@Cacheable(cacheNames="leads", key="#leadBean.leadId")
public Lead getCacheLeads(Lead leadBean){
// ...
}
}
這種未命中配置實際上會在運行時導致類似于以下內容的例外:
java.lang.IllegalArgumentException: Cannot find cache named 'leads' for Builder[public io.stackoverflow.questions.spring.cache.StaticCacheNamesIntegrationTests$Lead io.stackoverflow.questions.spring.cache.StaticCacheNamesIntegrationTests$LeadService.load(io.stackoverflow.questions.spring.cache.StaticCacheNamesIntegrationTests$Lead)] caches=[leads] | key='#lead.id' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'
at org.springframework.cache.interceptor.AbstractCacheResolver.resolveCaches(AbstractCacheResolver.java:92)
at org.springframework.cache.interceptor.CacheAspectSupport.getCaches(CacheAspectSupport.java:252)
at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContext.<init>(CacheAspectSupport.java:724)
at org.springframework.cache.interceptor.CacheAspectSupport.getOperationContext(CacheAspectSupport.java:265)
at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContexts.<init>(CacheAspectSupport.java:615)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:345)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:64)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)
at io.stackoverflow.questions.spring.cache.StaticCacheNamesIntegrationTests$LeadService$$EnhancerBySpringCGLIB$$86664246.load(<generated>)
...
..
.
此外,我沒有看到任何呼叫,方法的LeadsServicebean 的“外部”。在您的測驗中,您正在呼叫:@CacheablegetCacheLeads(..)
leadService.calculateLead(lead);
如下:
private void serviceIsCalled(){
Lead lead = new Lead();
lead.setLeadId("DC635EA19A39EA128764BB99052E5D1A9A");
leadService.calculateLead(lead);
}
如果該calculateLead(:Lead) LeadService方法正在呼叫@Cacheable,getCacheLeads(:Lead) LeadService方法(在內部),那么這不會導致快取功能啟動,因為您已經“落后”了 Spring 的 AOP 代理設定以“啟用”您的LeadServicebean 的快取行為。
See the Spring Framework AOP documentation on this matter.
NOTE: Spring's Cache Abstraction, like the Spring's Transaction Management, is built on the Spring AOP infrastructure, as are many other things in Spring.
In your case this means:
Test -> <PROXY> -> LeadService.calculateLead(:Lead) -> LeadService.getCacheLeads(:Lead)
However, between LeadSevice.calculateLead(:Lead) and LeadService.getCacheLeads(:Lead), NO PROXY is involved, therefore Spring's caching behavior will not be applied.
Only...
Test (or some other bean) -> <PROXY> -> LeadService.getCacheLeads(:Lead)
Will result in the AOP Proxy decorated with the Caching Interceptors being invoked and the caching behavior applied.
You can see that your use case will work correctly when configured and used correctly as demonstrated in my example test class, modeled after your domain.
Look for the comments that explain why your configuration will fail in your case.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/457268.html
上一篇:在Xunit中模擬EF
