spring配置hibernate映射文件的几种方式
在spring中配置hibernate时,即在配置sessionFactory时,
我们一般这样配置:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.query.substitutions">true=1,false=0</prop>
<prop key="hibernate.jdbc.batch_size">25</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.generate_statistics">false</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<prop key="hibernate.cache.region_prefix">direct</prop>
<prop key="hibernate.cache.use_structured_entries">false</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.query.factory_class">org.hibernate.hql.ast.ASTQueryTranslatorFactory</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop>
</props>
</property>
<property name="dataSource" ref="dataSource"/>
<property name="mappingDirectoryLocations">
<list>
<value>classpath:/org/first/config/</value>
<value>classpath:/org/second/config/</value>
</list>
</property>
</bean>
关于Hibernate的映射文件可以有多重配置方式,看一下org.springframework.orm.hibernate3.LocalSessionFactoryBean
这个类的源码就知道了,这里我截取部分变量。
private Class configurationClass;
private Resource configLocations[];
private String mappingResources[];
private Resource mappingLocations[];
private Resource cacheableMappingLocations[];
private Resource mappingJarLocations[];
private Resource mappingDirectoryLocations[];
private Properties hibernateProperties;
private TransactionManager jtaTransactionManager;
private Object cacheRegionFactory;
private CacheProvider cacheProvider;
private LobHandler lobHandler;
private Interceptor entityInterceptor;
private NamingStrategy namingStrategy;
private TypeDefinitionBean typeDefinitions[];
private FilterDefinition filterDefinitions[];
private Properties entityCacheStrategies;
private Properties collectionCacheStrategies;
private Map eventListeners;
private boolean schemaUpdate;
private ClassLoader beanClassLoader;
private Configuration configuration;
关于映射文件的配置有4个变量可以spring注入:
private String mappingResources[];
private Resource mappingLocations[];
private Resource mappingJarLocations[];
private Resource mappingDirectoryLocations[];
现在我们就开始研究怎么使用者4中方式以及4种方式的区别。
mappingResources方式:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.query.substitutions">true=1,false=0</prop>
<prop key="hibernate.jdbc.batch_size">25</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.generate_statistics">false</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<prop key="hibernate.cache.region_prefix">direct</prop>
<prop key="hibernate.cache.use_structured_entries">false</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.query.factory_class">org.hibernate.hql.ast.ASTQueryTranslatorFactory</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop>
</props>
</property>
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>classpath:/org/first/config/context_first.xml</value>
<value>classpath:/org/second/config/context_second.xml</value>
</list>
</property>
</bean>
上面的配置会报错,提示找不到文件
改成下面后正常启动:
<property name="mappingResources">
<list>
<value>/org/first/config/LsyUser.hbm.xml</value>
<value>/org/second/config/LsyDep.hbm.xml</value>
</list>
</property>
这个有点奇怪了,因为我的xml文件时放在源文件夹中的,应该在路径前添加classpath:才正确。
实验的结果却报错,而不加classpath:的反而正确,我的结论:mappingResources这个属性就是要到
classpath下寻找文件,所以写上它反而错。
还有一点路径中<value>/org/first/config/LsyUser.hbm.xml</value>第一个"/"斜杠对于mappingResources
是不用写的,写了也不会报错。原因是spring自己过滤掉了第一个斜杠。
源码:
if(mappingResources != null)
{
String as[];
int j2 = (as = mappingResources).length;
for(int k = 0; k < j2; k++)
{
String mapping = as[k];
Resource resource = new ClassPathResource(mapping.trim(), beanClassLoader);
config.addInputStream(resource.getInputStream());
}
}
其中ClassPathResource源码:
public ClassPathResource(String path, ClassLoader classLoader)
{
Assert.notNull(path, "Path must not be null");
String pathToUse = StringUtils.cleanPath(path);
if(pathToUse.startsWith("/"))
pathToUse = pathToUse.substring(1);
this.path = pathToUse;
this.classLoader = classLoader == null ? ClassUtils.getDefaultClassLoader() : classLoader;
}
关于 classpath: 和 classpath*: 的区别,网上有篇文章介绍的很好:
Spring加载resource时classpath*:与classpath:的区别
http://blog.youkuaiyun.com/kkdelta/article/details/5507799
mappingLocations方式:
把sessionFactory中的<property name="mappingResources">替换成:
<property name="mappingLocations">
<list>
<value>classpath:/org/first/config/LsyUser.hbm.xml</value>
<value>classpath:/org/second/config/LsyDep.hbm.xml</value>
</list>
</property>
正常启动,可见这个mappingLocations是需要添加classpath:属性的,它的类型不是String,而是
Resource。使用它也可以到文件路径下配置(这里我们把xml文件放到了源文件夹中)。
(注意:url中第一个斜杠"/"同样可以省略。)
现在测试文件路径下的加载:
把上面2个文件放到/webapp/WEB-INF/hixml下,同时改变配置如下:
<property name="mappingLocations">
<list>
<value>/WEB-INF/hixml/LsyUser.hbm.xml</value>
<value>/WEB-INF/hixml/LsyDep.hbm.xml</value>
</list>
</property>
启动成功! (注:第一个斜杠"/"可以省略)。
也就是说mappingLocations方式可以加载源文件夹中的文件(加前缀classpath:),
也可以加载物理路径中的文件。而mappingResources方式只能加载源文件夹中的文件
(注意:不能加前缀classpath:)。
还有对于url可以使用通配符,如下同上:
<property name="mappingLocations">
<list>
<value>/WEB-INF/hixml/*.hbm.xml</value>
</list>
</property>
mappingJarLocations方式:
这个方式是加载jar里面的文件,感觉不是很常用,不做研究了。mappingDirectoryLocations方式:
这种方式是加载某个路径下的所有文件。如下:
<property name="mappingDirectoryLocations">
<list>
<value>classpath:/org/first/config/</value>
<value>classpath:/org/second/config/</value>
</list>
</property>
也可以加载物理路径下的文件,如下同上:
<property name="mappingDirectoryLocations">
<list>
<value>/WEB-INF/hixml</value>
</list>
</property>
*************************总结******************************************
清楚了以上4中方式,对于我们设计整个工程的架构是很有帮助的。
我们可以把所有Hibernate文件放在一个目录下,这样的好处就是不用每次
做新功能都要记得把新文件引入,也不用担心引入的时候写错了url,缺点就是
模块没有做到松耦合。我喜欢把配置文件都放在每个模块的package中,这样就
需要从源文件夹中引入,每个模块的所有代码都是在一块的也方面寻找代码。