Hibernate 配置详解(2)
6) hibernate.session_factory_name:
配置一个JNDI名称,通过Configuration对象创建的SessionFactory会绑定到JNDI下该名称中。一般名字格式为jndi/someName。注意,要使用JNDI,需要在具有JNDI功能的环境之中,比如WEB容器或者EJB容器中。
下面再tomcat中做一个示例,首先在一个标准的WEB项目中添加hibernate的一些基本功能,接着在hibernate.properties文件中添加:
hibernate.session_factory_name jndi/sf
创建一个Filter作为Open Session In View过滤器:
public class OpenSessioninViewFilter implements Filter { public void destroy() {} public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HibernateUtil.getInstance().getCurrentSession(); chain.doFilter(req, resp); HibernateUtil.getInstance().closeSession(); } public void init(FilterConfig arg0) throws ServletException {} }
在HibernatUtil类的创建过程中就初始化并创建了一个SessionFactory,那么该SessionFactory就已经绑定在了JNDI中Naming为jndi/sf上:
private HibernateUtil() { sf = new Configuration().configure().buildSessionFactory( new ServiceRegistryBuilder().buildServiceRegistry()); }接着再创建一个Filter来验证JNDI是否绑定成功:
public class SomeFilter implements Filter { public void destroy() {} public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { try { Context ctx = new InitialContext(); System.out.println(ctx.lookup("jndi/sf")); } catch (Exception e) { e.printStackTrace(); } chain.doFilter(req, resp); } public void init(FilterConfig arg0) throws ServletException {} }该Filter仅仅是很简单的从上下文中找到名字为jndi/sf的资源并打印出来。要能够正常打印,必须要保证open session in view 过滤器在该SomeFilter之前运行(主要的目的是要求在第一次使用JNDI查找SessionFactory资源之前完成SessionFactory的实例化):
<filter> <filter-name>osiv</filter-name> <filter-class>util.OpenSessioninViewFilter</filter-class> </filter> <filter-mapping> <filter-name>osiv</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>filter</filter-name> <filter-class>util.SomeFilter</filter-class> </filter> <filter-mapping> <filter-name>filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>运行应用,随意请求一个地址,后台打印:
org.hibernate.internal.SessionFactoryImpl@6186ee4d
已经工作正常。注意一点的就是,如果只是在JUnit中测试Hibernate,在Hibernate启动过程当中就会看到这样的异常:
WARN: HHH000277: Could not bind factory to JNDI org.hibernate.service.jndi.JndiException: Error parsing JNDI name [foo] at org.hibernate.service.jndi.internal.JndiServiceImpl.parseName(JndiServiceImpl.java:92) at org.hibernate.service.jndi.internal.JndiServiceImpl.bind(JndiServiceImpl.java:108) at org.hibernate.internal.SessionFactoryRegistry.addSessionFactory(SessionFactoryRegistry.java:89) at org.hibernate.internal.SessionFactoryImpl.(SessionFactoryImpl.java:480) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1750) at cd.itcast.hibernate.day1.jdbc.HibernateUtil.(HibernateUtil.java:15) at cd.itcast.hibernate.day1.jdbc.HibernateUtil.(HibernateUtil.java:10) at cd.itcast.hibernate.day1.jdbc.UserTest.test(UserTest.java:14) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ... Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial at javax.naming.spi.NamingManager.getInitialContext(Unknown Source) at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source) at javax.naming.InitialContext.getURLOrDefaultInitCtx(Unknown Source) at javax.naming.InitialContext.getNameParser(Unknown Source) at org.hibernate.service.jndi.internal.JndiServiceImpl.parseName(JndiServiceImpl.java:86) ... 30 more
该异常并不影响Hibernate的正常使用,其原因是因为在hibernate的project/etc/中的hibernate.cfg.xml文件模板中,sessionFactory配置了name这个属性,这个属性同hibernate.session_factory_name作用相同,也是用于指定JNDI绑定名称,因为在JUNIT环境下没有JNDI功能,所以绑定失败,报错。要去掉这个异常,只需要把SessionFactory元素的name属性删除即可。