Spring-Boot应用程序无法找到ehcache的属性factory_class

时间:2014-06-17 16:58:48

标签: spring jpa ehcache spring-boot

我正在使用弹簧应用程序(使用弹簧靴),直到今天早上才能正常工作。我现在需要配置第二个数据源以使用两个不同的数据库(mysql + embedded h2)。

我现在有两个班级" MainDatabaseConfiguration"和" EmbeddedDatabaseConfiguration",它们都提供类型为Bean的数据" DataSource" (mainDataSource和embeddedDataSource),以及类型为" EntityManager"," EntityManagerFactory"的关联Bean。和" TransactionManager"。

不幸的是,应用程序初始化失败并出现以下错误:

...
Caused by: org.hibernate.cache.NoCacheRegionFactoryAvailableException: Second-level cache is used in the application, but property hibernate.cache.region.factory_class is not given; please either disable second level cache or set correct region factory using the hibernate.cache.region.factory_class setting and make sure the second level cache provider (hibernate-infinispan, e.g.) is available on the classpath.
at org.hibernate.cache.internal.NoCachingRegionFactory.buildEntityRegion(NoCachingRegionFactory.java:83)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:363)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1857)
...

然而,当我查看我的配置文件时:

application-dev.yml:
server:
    port: 8080
    address: localhost

spring:
    profiles: dev
    datasource:
        main:
            dataSourceClassName: org.h2.jdbcx.JdbcDataSource
            url: jdbc:h2:mem:jhipster
            databaseName: 
            serverName: 
            username: 
            password:
        embedded:
            dataSourceClassName: org.h2.jdbcx.JdbcDataSource
            url: jdbc:h2:mem:jhipster
            databaseName: 
            serverName: 
            username: 
            password:
    jpa:
        database-platform: org.hibernate.dialect.H2Dialect
        database: H2
        openInView: false
        show_sql: true
        generate-ddl: false
        hibernate:
            ddl-auto: none
            naming-strategy: org.hibernate.cfg.EJB3NamingStrategy
        properties:
            hibernate.cache.use_second_level_cache: true
            hibernate.cache.use_query_cache: false
            hibernate.generate_statistics: true
            hibernate.cache.region.factory_class: org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory

    thymeleaf:
        mode: XHTML
        cache: false

metrics:
    jmx.enabled: true
    graphite:
        enabled: false
        host:
        port:

cache:
    timeToLiveSeconds: 3600
    ehcache:
        maxBytesLocalHeap: 16M

# You can add as many as folders to watch
# You just need to add a dash + the directory to watch
hotReload:
    enabled: true
    package:
      project: com.sfr.sio
      domain: com.sfr.sio.domain
      restdto: com.sfr.sio.web.rest.dto
    liquibase:
      defaultCatalogName: 
      defaultSchema: public
    watchdir:
      - target/classes

属性&#34; hibernate.cache.region.factory_class&#34;存在。我对第二个数据源的文件所做的唯一改变是在&#34; spring.datasource&#34;将它分成两部分(spring.datasource.main和spring.datasource.embedded)。 (注意:在我的开发环境中,两个数据源都是H2,但在生产中使用了mysql) 正如您所看到的,错误中提到的属性存在,但Spring似乎无法检索它。

可能涉及错误的其他类的代码:

mainDataSourceConfiguration.java:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "mainEntityManagerFactory", 
        transactionManagerRef = "mainTransactionManager",
        basePackages = { "com.sfr.sio.repository" })
public class MainDatabaseConfiguration extends AbstractDatabaseConfiguration implements EnvironmentAware {

    /** prefix for the main datasource properties. **/
    private static final String MAIN_DATASOURCE_PREFIX = "spring.datasource.main.";

    /** Logger. */
    private final Logger log = LoggerFactory.getLogger(MainDatabaseConfiguration.class);


    @Override
    public void setEnvironment(Environment environment) {
        this.propertyResolver = new RelaxedPropertyResolver(environment, MAIN_DATASOURCE_PREFIX);
    }

    /**
     * Main Datasource bean creator.
     * <ul>
     * <li>Mysql for qualif and sfr environments</li>
     * <li>h2 for dev environment</li>
     * </ul>
     * 
     * @return the datasource.
     */
    @Bean(name="mainDataSource")
    @Primary
    public DataSource dataSource() {
        log.debug("Configuring Datasource");
        if (propertyResolver.getProperty(URL_PARAMETER) == null && propertyResolver.getProperty(DATABASE_NAME_PARAMETER) == null) {
            log.error("Your database connection pool configuration is incorrect! The application" +
                    "cannot start. Please check your Spring profile, current profiles are: {}",
                    Arrays.toString(env.getActiveProfiles()));

            throw new ApplicationContextException("Database connection pool is not configured correctly");
        }
        HikariConfig config = new HikariConfig();
        config.setDataSourceClassName(propertyResolver.getProperty(DS_CLASS_NAME_PARAMETER));
        if (propertyResolver.getProperty(URL_PARAMETER) == null || "".equals(propertyResolver.getProperty(URL_PARAMETER))) {
            config.addDataSourceProperty(DATABASE_NAME_PARAMETER, propertyResolver.getProperty(DATABASE_NAME_PARAMETER));
            config.addDataSourceProperty(SERVER_NAME_PARAMETER, propertyResolver.getProperty(SERVER_NAME_PARAMETER));
        } else {
            config.addDataSourceProperty(URL_PARAMETER, propertyResolver.getProperty(URL_PARAMETER));
        }
        config.addDataSourceProperty(USER_PARAM, propertyResolver.getProperty(USERNAME_PARAMETER));
        config.addDataSourceProperty(PASSWORD_PARAMETER, propertyResolver.getProperty(PASSWORD_PARAMETER));
        return new HikariDataSource(config);
    }

    /**
     * @return the entity manager for the main datasource
     * @see MainDatabaseConfiguration.dataSource()
     */
    @Bean(name = "mainEntityManager")
    public EntityManager entityManager() {
        return entityManagerFactory().createEntityManager();
    }

    /**
     * @return the entity manager factory for the main datasource
     * @see MainDatabaseConfiguration.dataSource()
     */
    @Bean(name = "mainEntityManagerFactory")
    public EntityManagerFactory entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
        lef.setDataSource(this.dataSource());
        lef.setJpaVendorAdapter(jpaVendorAdapter);
        lef.setPackagesToScan("com.sfr.sio.domain");
        lef.setPersistenceUnitName("mainPersistenceUnit");
        lef.afterPropertiesSet();
        return lef.getObject();
    }

    /**
     * @return the transaction manager for the main datasource
     * @see MainDatabaseConfiguration.dataSource()
     */
    @Bean(name = "mainTransactionManager")
    @Primary
    public PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory());
    }

    /**
     * Liquibase bean creator.
     * @return the liquibase bean
     */
    @Bean
    @Profile(value = Constants.SPRING_PROFILE_DEVELOPMENT)
    public SpringLiquibase liquibase() {
        log.debug("Configuring Liquibase");
        SpringLiquibase liquibase = new SpringLiquibase();
        liquibase.setDataSource(dataSource());
        liquibase.setChangeLog("classpath:config/liquibase/master.xml");
        liquibase.setContexts("development, production");
        return liquibase;
    }
} 

MainDatabaseConfiguration和EmbeddedDatabaseConfiguration之间的唯一区别是embeddedDatasource替换了mainDatasource。代码是相同的。

CacheConfiguration.java

@Configuration
@EnableCaching
@AutoConfigureAfter(value = {MetricsConfiguration.class, MainDatabaseConfiguration.class, EmbeddedDatabaseConfiguration.class})
public class CacheConfiguration {

    /** Logger. */
    private final Logger log = LoggerFactory.getLogger(CacheConfiguration.class);

    /** Entity manager. */
    @PersistenceContext(unitName="mainPersistenceUnit")
    private EntityManager mainEntityManager;

    /** Current environment. */
    @Inject
    private Environment env;

    /** Metrics regitry. */
    @Inject
    private MetricRegistry metricRegistry;

    /** Ehcache manager. */
    private net.sf.ehcache.CacheManager cacheManager;

    /** TTL parameter. */
    private static final Integer CACHE_TIME_TO_LIVE = 3600;

    /**
     * Prepare destroy of the object.
     */
    @PreDestroy
    public void destroy() {
        log.info("Remove Cache Manager metrics");
        SortedSet<String> names = metricRegistry.getNames();
        for (String name : names) {
            metricRegistry.remove(name);
        }
        log.info("Closing Cache Manager");
        cacheManager.shutdown();
    }

    /**
     * Cache manager bean creator.
     * @return the cache manager.
     */
    @Bean
    public CacheManager cacheManager() {
        log.debug("Starting Ehcache");
        cacheManager = net.sf.ehcache.CacheManager.create();
        cacheManager.getConfiguration().setMaxBytesLocalHeap(env.getProperty("cache.ehcache.maxBytesLocalHeap", String.class, "16M"));
        log.debug("Registring Ehcache Metrics gauges");
        Set<EntityType<?>> entities = mainEntityManager.getMetamodel().getEntities();
        for (EntityType<?> entity : entities) {

            String name = entity.getName();
            if ( name == null ) {
                name = entity.getJavaType().getName();
            }
            Assert.notNull(name, "entity cannot exist without a identifier");

            net.sf.ehcache.Cache cache = cacheManager.getCache(name);
            if (cache != null) {
                cache.getCacheConfiguration().setTimeToLiveSeconds(env.getProperty("cache.timeToLiveSeconds", Integer.class, CACHE_TIME_TO_LIVE));
                net.sf.ehcache.Ehcache decoratedCache = InstrumentedEhcache.instrument(metricRegistry, cache);
                cacheManager.replaceCacheWithDecoratedCache(cache, decoratedCache);
            }
        }
        EhCacheCacheManager ehCacheManager = new EhCacheCacheManager();
        ehCacheManager.setCacheManager(cacheManager);
        return ehCacheManager;
    }
}

对不起,很长的帖子。我希望它足够清楚。不要犹豫要求精确。

1 个答案:

答案 0 :(得分:1)

我遇到了同样的问题。在调试之后,似乎application.properties文件中的属性稍后在初始化过程中被拾取,并且在初始化SessionFactory时尚未准备好。

以下可能是一个丑陋的解决方案,但它对我有用:

@Bean
public SessionFactory sessionFactory() {
    final LocalSessionFactoryBuilder localSessionFactoryBuilder = new LocalSessionFactoryBuilder(dataSource);
    localSessionFactoryBuilder.scanPackages(myModelPackage);
    localSessionFactoryBuilder.setProperty(Environment.CACHE_REGION_FACTORY, "org.hibernate.cache.ehcache.EhCacheRegionFactory");
    return localSessionFactoryBuilder.buildSessionFactory();
}

此部分将进入您的数据库配置路径。 正如您所看到的,我在会话工厂创建的早期阶段强制缓存区域工厂属性。