【发布时间】:2019-01-23 11:03:08
【问题描述】:
我正在尝试创建一个基于 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"]
}
}
其中之一是作为参考。第二个是把 jhipster 东西拿出来的项目。我遵循的步骤是:
- 删除了 jhipster BOM 并包含了现在缺少的依赖项。
- 在本地复制使用的 JHipster 框架类(主要用于配置和实用程序)。
- 将提及的“JHipster”重命名为“应用程序”。
- 将 application-*.yml hispter 框架引用更改为本地引用。
问题是当我尝试运行该项目时,我在 Hibernate 2nd level cache / 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 hibernate 配置指向新的本地类:
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,但戴夫的目的与我的不同。事实上,我并没有对 jhipster 生成的缓存实现进行任何更改。
我有什么遗漏的吗? liquibase 可能会做我错过的事情吗?
【问题讨论】:
标签: java spring hibernate jhipster ehcache