package com.primeton.dgs.kernel.core.dao.hibernate; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; import java.util.Map; import java.util.Properties; import com.primeton.dgs.kernel.core.util.MetadataWebContext; import com.primeton.dgs.kernel.core.web.springframework.DatabaseRecognizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContextException; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.orm.hibernate5.LocalSessionFactoryBean; import javax.sql.DataSource; /** * Hibernate 配置。 * * 加载不同的 Hibernate 配置,根据 DatabaseRecognizer 返回的数据库类别,初始化不同的 Hibernate 方言 * * @author zhaopx * */ public class HibernateLocalSessionFactoryBean extends LocalSessionFactoryBean { private static final String PREFIX = "META-INF/hibernate/"; // 加载hibernate模型文件的路径前缀 private static final String ENDFIX = "*.hbm.xml"; // 文件名的扩展后缀名 private DatabaseRecognizer databaseRecognizer; // 数据库的品牌和版本 private String databaseProductName; private String databaseProductVersion; private static final Logger logger = LoggerFactory.getLogger(HibernateLocalSessionFactoryBean.class); @Override public void setDataSource(DataSource dataSource) { super.setDataSource(dataSource); try(Connection conn = dataSource.getConnection()) { DatabaseMetaData meta = conn.getMetaData(); String databaseName = meta.getDatabaseProductName(); String productVersion = meta.getDatabaseProductVersion(); if (logger.isInfoEnabled()) { logger.info("Current Database is " + databaseName + ", Version is " + productVersion); } databaseName = recognizeDatabaseName(databaseName, productVersion); databaseRecognizer.setCurrentDatabaseProductName(databaseName); databaseRecognizer.setCurrentDatabaseProductVersion(productVersion); // 将数据库名缓存起来 MetadataWebContext.getInstance().setDatabaseName(databaseName); } catch (SQLException e) { String s = "Cannot determine the database brand name for loading ApplicationContext"; logger.error(s, e); throw new ApplicationContextException(s, e); } } /** * 覆写该方法,将hibernate配置文件,通过读取特定类路径下的文件获取 */ @Override public void setMappingResources(String mappingResources[]) { try { ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources("classpath*:".concat(PREFIX).concat(ENDFIX)); String[] resourceStrings = new String[resources.length]; for(int index = 0; index < resources.length; index++){ resourceStrings[index] = PREFIX.concat(resources[index].getFilename()); } super.setMappingResources(resourceStrings); } catch (IOException e) { throw new IllegalStateException("无法加载 " + ENDFIX + " 文件。", e); } } @Override public void afterPropertiesSet() throws IOException { // 首先根据数据库选择配置文件 String databaseName = MetadataWebContext.getInstance().getDatabaseName(); Properties props = new Properties(); String configFile = "classpath*:".concat("/spring/hibernate_").concat(databaseName.toLowerCase()).concat("_local.properties"); try { ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources(configFile); for (Resource resource : resources) { logger.info("found hibernate local file: {}", resource.getURL()); try(InputStream inputStream = resource.getInputStream()) { Properties tmp = new Properties(); tmp.load(inputStream); props.putAll(tmp); } } } catch (Exception e) { logger.error("无法读取配置文件: " + configFile, e); } if(!props.isEmpty()) { for (Map.Entry entry : props.entrySet()) { getHibernateProperties().put(entry.getKey(), entry.getValue()); } } logger.info("hibernate properties print as "); for (Map.Entry entry : getHibernateProperties().entrySet()) { logger.info("{}: {}", entry.getKey(), entry.getValue()); } super.afterPropertiesSet(); } /** * 识别数据库名称,已经配置在spring/corebean/context-base.xml文件中 * @param databaseName 从数据库连接获取的数据库名称 * @param productVersion 数据库版本 * @return 转换成系统需要的名称 */ private String recognizeDatabaseName(String databaseName, String productVersion) { this.databaseProductName = databaseName; this.databaseProductVersion = productVersion; return databaseRecognizer.getDatabaseName(databaseName); } public void setDatabaseRecognizer(DatabaseRecognizer databaseRecognizer) { this.databaseRecognizer = databaseRecognizer; } public String getDatabaseProductName() { return databaseProductName; } public String getDatabaseProductVersion() { return databaseProductVersion; } }