Кэш закрыт, что вызывает исключение при запуске набора тестов
У меня возникла проблема, аналогичная описанной в этом вопросе.
У меня есть набор тестов, который отлично работает в среде разработки. Один из тестов завершается неудачно при выполнении в Bitbucket Pipelines со следующим исключением:
org.springframework.dao.InvalidDataAccessApiUsageException: Cache[model.Role] is closed; nested exception is java.lang.IllegalStateException: Cache[model.Role] is closed
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:364)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
....
Я хочу попробовать принятое решение, но я не знаю, как применить его к моему проекту. Второе решение зависит от файла ehcache.xml. У меня нет этого файла, все настроено в JavaConfig. Как я могу принять предложенные решения для EhCache + JCache (JSR-107) в JavaConfig?
Моя конфигурация кеша:
@Configuration
@EnableCaching
public class CacheConfig {
private final javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration =
Eh107Configuration.fromEhcacheCacheConfiguration(CacheConfigurationBuilder
.newCacheConfigurationBuilder(Object.class, Object.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(100, EntryUnit.ENTRIES))
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(60)))
.build());
@Bean
public JCacheManagerCustomizer cacheManagerCustomizer() {
return cm -> {
createIfNotExists(cm, "model.Role");
createIfNotExists(cm, "model.User.roles");
// ...
};
}
private void createIfNotExists(CacheManager cacheManager, String cacheName) {
if (cacheManager.getCache(cacheName) == null) {
cacheManager.createCache(cacheName, jcacheConfiguration);
}
}
}
Gradle зависимости:
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-cache'
implementation group: 'javax.cache', name: 'cache-api'
implementation group: 'org.ehcache', name: 'ehcache'
implementation group: 'org.hibernate', name: 'hibernate-jcache'
Неудачный тест:
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class SecondLevelCacheTest {
@Autowired
private RoleRepository roleRepository;
private CacheManager manager;
@Before
public void initCacheManager() {
CachingProvider provider = Caching.getCachingProvider();
manager = provider.getCacheManager();
final String cacheRegion = "model.Role";
manager.getCache(cacheRegion).clear();
}
@Test
public final void givenEntityIsLoaded_thenItIsCached() {
final String cacheRegion = "model.Role";
boolean hasNext = manager.getCache(cacheRegion).iterator().hasNext();
final Role role = roleRepository.findByName("USER");
boolean hasNext2 = manager.getCache(cacheRegion).iterator().hasNext();
final Role role2 = roleRepository.findByName("USER");
Assert.assertFalse(hasNext);
Assert.assertTrue(hasNext2);
}
}
Наиболее популярное решение - "установить для общего свойства значение false в контексте тестирования". Как я могу сделать это в отношении моей конфигурации?
3 ответа
Аннотируйте свой неудачный тестовый класс с помощью
@AutoConfigureCache
. По умолчанию эта аннотация установит
NoOpCacheManager
, т.е. базовая, без операции
CacheManager
реализация, подходящая для отключения кэширования, обычно используемая для резервного копирования объявлений кэша без фактического резервного хранилища. Он просто примет любые элементы в кеш, фактически не сохраняя их.
Один из вариантов - предоставить индивидуальный CachingProvider
что не разделяет CacheManager
-с. Пример решения можно найти здесь.
Предлагаемое решение, о котором вы говорите, основано на Ehcache 2. Вы используете Ehcache 3 (хорошо для вас), поэтому оно недействительно.
Весна позаботится о закрытии CacheManager
так обычно вам не нужно ни о чем заботиться. Кроме того, вам не нужно получать к нему доступ через CachingProvider
, Вы можете @Autowired
javax.cache.CacheManager
и таким образом вы обязательно получите правильный.
Тем не менее, вы используете Hibernate. Вы должны убедиться, что Spring и Hibernate используют одинаковые CacheManager
, Способ его настройки зависит от версии Spring и Hibernate.
Можем ли мы получить полную трассировку стека? Сейчас кажется, что что-то закрывает CacheManager
без отмены регистрации из CachingProvider
, Это невозможно, если вы не закрываете org.ehcache.CacheManager
не закрывая javax.cache.CacheManager
оборачивая это. Закрытие позже приведет к отмене регистрации.