我正在尝试基于JHipster生成的模板创建通用的Spring Boot后端模板(因为某些应用程序不会由我维护,而其他spring开发人员可能必须适应jhipster才能对jhipster进行更改办法)。也就是说,我要实现的过程是:使用以下设置生成两个jhipster项目:
{
"generator-jhipster": {
"promptValues": {
"packageName": "com.mypackage.springtemplate",
"nativeLanguage": "en"
},
"jhipsterVersion": "5.7.2",
"applicationType": "monolith",
"baseName": "springtemplate",
"packageName": "com.mypackage.springtemplate",
"packageFolder": "com/mypackage/springtemplate",
"serverPort": "8080",
"authenticationType": "jwt",
"cacheProvider": "ehcache",
"enableHibernateCache": true,
"websocket": "spring-websocket",
"databaseType": "sql",
"devDatabaseType": "mysql",
"prodDatabaseType": "mysql",
"searchEngine": false,
"messageBroker": false,
"serviceDiscoveryType": false,
"buildTool": "maven",
"enableSwaggerCodegen": false,
"jwtSecretKey": "****",
"clientFramework": "angularX",
"useSass": true,
"clientPackageManager": "npm",
"testFrameworks": [],
"jhiPrefix": "jhi",
"otherModules": [],
"enableTranslation": true,
"nativeLanguage": "en",
"languages": ["en", "es"]
}
}
其中之一是作为参考。第二个项目是将时髦的东西拿出来的项目。我遵循的步骤是:
问题是,当我尝试运行项目时,Hibernate 2级缓存/ ehcache出现以下错误:
Caused by: java.lang.IllegalStateException: All Hibernate caches should be created upfront. Please update CacheConfiguration.java to add com.mypackage.springtemplate.domain.User
at com.mypackage.springtemplate.config.cache.NoDefaultJCacheRegionFactory.createCache(NoDefaultJCacheRegionFactory.java:24)
at org.hibernate.cache.jcache.JCacheRegionFactory.getOrCreateCache(JCacheRegionFactory.java:190)
at org.hibernate.cache.jcache.JCacheRegionFactory.buildEntityRegion(JCacheRegionFactory.java:113)
at org.hibernate.cache.spi.RegionFactory.buildEntityRegion(RegionFactory.java:132)
application-dev.yml休眠配置指向新的本地类:
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
database: MYSQL
show-sql: true
properties:
hibernate.id.new_generator_mappings: true
hibernate.connection.provider_disables_autocommit: true
hibernate.cache.use_second_level_cache: true
hibernate.cache.use_query_cache: false
hibernate.generate_statistics: true
hibernate.cache.region.factory_class: com.mypackage.springtemplate.config.cache.BeanClassLoaderAwareJCacheRegionFactory
与缓存相关的类保持不变...
BeanClassLoaderAwareJCacheRegionFactory.java
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Objects;
import java.util.Properties;
import javax.cache.CacheException;
import javax.cache.CacheManager;
import javax.cache.spi.CachingProvider;
/**
* Fixes Spring classloader issues that were introduced in Spring Boot 2.0.3.
*
* This allows to use the same classloader for ehcache, both for the Spring Cache abstraction and for the Hibernate
* 2nd level cache.
*
* See https://github.com/jhipster/generator-jhipster/issues/7783 for more information.
*/
public class BeanClassLoaderAwareJCacheRegionFactory extends NoDefaultJCacheRegionFactory {
private static volatile ClassLoader classLoader;
@Override
protected CacheManager getCacheManager(Properties properties) {
Objects.requireNonNull(classLoader, "Please set Spring's classloader in the setBeanClassLoader " +
"method before using this class in Hibernate");
CachingProvider cachingProvider = getCachingProvider( properties );
String cacheManagerUri = getProp( properties, CONFIG_URI );
URI uri = getUri(cachingProvider, cacheManagerUri);
CacheManager cacheManager = cachingProvider.getCacheManager(uri, classLoader);
// To prevent some class loader memory leak this might cause
setBeanClassLoader(null);
return cacheManager;
}
private URI getUri(CachingProvider cachingProvider, String cacheManagerUri) {
URI uri;
if (cacheManagerUri != null) {
try {
uri = new URI(cacheManagerUri);
}
catch (URISyntaxException e) {
throw new CacheException("Couldn't create URI from " + cacheManagerUri, e);
}
}
else {
uri = cachingProvider.getDefaultURI();
}
return uri;
}
/**
* This method must be called from a Spring Bean to get the classloader.
* For example: BeanClassLoaderAwareJCacheRegionFactory.setBeanClassLoader(this.getClass().getClassLoader());
*
* @param classLoader The Spring classloader
*/
public static void setBeanClassLoader(ClassLoader classLoader) {
BeanClassLoaderAwareJCacheRegionFactory.classLoader = classLoader;
}
}
NoDefaultJCacheRegionFactory.java
import java.util.Properties;
import javax.cache.Cache;
import org.hibernate.cache.jcache.JCacheRegionFactory;
import org.hibernate.cache.spi.CacheDataDescription;
/**
* Extends the default {@code JCacheRegionFactory} but makes sure all caches already exist to prevent
* spontaneous creation of badly configured caches (e.g. {@code new MutableConfiguration()}.
*
* See http://www.ehcache.org/blog/2017/03/15/spontaneous-cache-creation.html for more information.
*/
@SuppressWarnings("serial")
public class NoDefaultJCacheRegionFactory extends JCacheRegionFactory {
public static final String EXCEPTION_MESSAGE = "All Hibernate caches should be created upfront. " +
"Please update CacheConfiguration.java to add";
@Override
protected Cache<Object, Object> createCache(String regionName, Properties properties, CacheDataDescription
metadata) {
throw new IllegalStateException(EXCEPTION_MESSAGE + " " + regionName);
}
}
CacheConfiguration.java
import java.time.Duration;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.jsr107.Eh107Configuration;
import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.mypackage.springtemplate.config.properties.ApplicationProperties;
@Configuration
@EnableCaching
public class CacheConfiguration {
private final javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration;
public CacheConfiguration(ApplicationProperties applicationProperties) {
BeanClassLoaderAwareJCacheRegionFactory.setBeanClassLoader(this.getClass().getClassLoader());
ApplicationProperties.Cache.Ehcache ehcache =
applicationProperties.getCache().getEhcache();
jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(
CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class,
ResourcePoolsBuilder.heap(ehcache.getMaxEntries()))
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(ehcache.getTimeToLiveSeconds())))
.build());
}
@Bean
public JCacheManagerCustomizer cacheManagerCustomizer() {
return cm -> {
cm.createCache(com.mypackage.springtemplate.repository.UserRepository.USERS_BY_LOGIN_CACHE, jcacheConfiguration);
cm.createCache(com.mypackage.springtemplate.repository.UserRepository.USERS_BY_EMAIL_CACHE, jcacheConfiguration);
cm.createCache(com.mypackage.springtemplate.domain.User.class.getName(), jcacheConfiguration);
cm.createCache(com.mypackage.springtemplate.domain.Authority.class.getName(), jcacheConfiguration);
cm.createCache(com.mypackage.springtemplate.domain.User.class.getName() + ".authorities", jcacheConfiguration);
};
}
}
已经选中this question,但dave的目的与我的不同。实际上,我没有对jhipster生成的缓存实现进行任何更改。
有什么我想念的吗? liquibase可能正在做我错过的事情吗?
答案 0 :(得分:0)
也可能根本没有调用CacheConfiguration.cacheManagerCustomizer
。这将意味着您破坏了缓存配置,并且可能没有使用缓存或仅使用了简单缓存,而不是Ehcache。请检查javax.cache
在您的类路径中是否正确。
另一种可能性是您没有为Hibernate和Spring使用相同的CacheManage
。请调试进入EhcacheCachingProvider
,并检查是否仅创建了一个CacheManager
。如果不是这种情况,则需要查看有什么不同。通常是类加载器,但是BeanClassLoaderAwareJCacheRegionFactory
通常应避免这种情况。