JHipster-Hibernate 2nd cache / ehcache试图从JHipster生成的项目中弹出JHipster的问题

时间:2019-01-17 22:20:19

标签: java spring hibernate jhipster ehcache

我正在尝试基于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"]
    }
}

其中之一是作为参考。第二个项目是将时髦的东西拿出来的项目。我遵循的步骤是:

  1. 删除了jhipster BOM,并包括了现在缺少的依赖项。
  2. 本地复制使用过的JHipster框架类(主要用于config和utils)。
  3. 将“ JHipster”重命名为“应用程序”。
  4. 已将application-*。yml hispter框架引用更改为本地引用。

这些是项目的主要结构更改: Primary changes

问题是,当我尝试运行项目时,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可能正在做我错过的事情吗?

1 个答案:

答案 0 :(得分:0)

也可能根本没有调用CacheConfiguration.cacheManagerCustomizer。这将意味着您破坏了缓存配置,并且可能没有使用缓存或仅使用了简单缓存,而不是Ehcache。请检查javax.cache在您的类路径中是否正确。

另一种可能性是您没有为Hibernate和Spring使用相同的CacheManage。请调试进入EhcacheCachingProvider,并检查是否仅创建了一个CacheManager。如果不是这种情况,则需要查看有什么不同。通常是类加载器,但是BeanClassLoaderAwareJCacheRegionFactory通常应避免这种情况。