Spring中对OpenSessionInViewFilter的描述如下:
1.OpenSessionInViewFilter是Spring提供的一个针对Hibernate的一个支持类,其主要意思是在发起一个页面请求时打开Hibernate的Session,一直保持这个Session,直到这个请求结束,具体是通过一个Filter来实现的。
2.它是一个过滤器,用来把一个Hibernate Session和一次完整的请求过程对应的线程相绑定。目的是为了实现"Open Session in View"的模式。例如: 它允许在事务提交之后延迟加载显示所需要的对象。
public class OpenSessionInViewFilter extends OncePerRequestFilter {
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter继承了OncePerRequestFilter抽象类,
doFilter()方法是OpenSessionInViewFilter的父类OncePerRequestFilter(抽象类)的方法,是过滤器的入口,是处理请求的第一个方法,父类的doFilter()方法调用了doFilterInternal()方法
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
//首选判断进行过滤的是否是http请求
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
throw new ServletException("OncePerRequestFilter just supports HTTP requests");
}
//如果是http请求的话进行强转
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
//alreadyFilteredAttributeName 是一个标识,用于判断是否需要进行OpenSessionInViewFilter
String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) {
// Proceed without invoking this filter...
filterChain.doFilter(request, response);
}
else {
// Do invoke this filter...
request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
//下面这个方法是abstract方法由OpenSessionInViewFilter 实现,是OpenSessionInViewFilter 的核心方法
doFilterInternal(httpRequest, httpResponse, filterChain);
}
}
protected abstract void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException;
}
OpenSessionInViewFilter重写了doFilterInternal方法,
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
//从spring的上下文中取得SessionFactory对象
SessionFactory sessionFactory = lookupSessionFactory(request);
//标识同一个请求的当前线程中存不存在Session,是不是共享同一个Session(SessionFactory里面对应的Session)
boolean participate = false;
//判断是否单session模式,当singleSession 设置为true是当页面跳转的时候是不是单例的,同一个Session。
if (isSingleSession()) {
//判断能否在当前线程中取得sessionFactory对象对应的session,一般只有Action跳Action的时候才会跑,其它时都是false
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
participate = true;
}else {
logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
//当前线程取不到session的时候通过sessionFactory创建,getSession()还在session中设置了flushMode,注意设置flushMode的模式。
Session session = getSession(sessionFactory);
/*将session绑定到当前的线程中,SessionHolder是session的一层封装,里面有个存放session的map,而且是线程同 步的Collections.synchronizedMap(newHashMap(1));*/
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
}
}else {
//这段是非单session模式的处理情况
if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
// Do not modify deferred close: just set the participate flag.
participate = true;
}else {
SessionFactoryUtils.initDeferredClose(sessionFactory);
}
}
try {
//将session绑定到了当前线程后,就该处理请求了
filterChain.doFilter(request, response);
}
finally {
if (!participate) {
if (isSingleSession()) {
//当请求结束时,对于单session模式,这时候要取消session的绑定,因为web容器(Tomcat等)的线程是采用线程池机制的,线程使用过后并不会销毁.解除session的绑定就是从map里面移除
logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
//取消绑定只是取消session对象和线程对象之间的引用,还没有关闭session,不关闭session相对于不关闭数据库连接,所以这里要关闭session
closeSession(sessionHolder.getSession(), sessionFactory);
}else {
SessionFactoryUtils.processDeferredClose(sessionFactory);
}
}
}
}
1.上面的源码中首先从lookupSessionFactory()方法中从Spring中获得一个SessionFactory,
protected SessionFactory lookupSessionFactory() {
if (logger.isDebugEnabled()) {
logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter");
}
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
return wac.getBean(getSessionFactoryBeanName(), SessionFactory.class);
}
2. getSessionFactoryBeanName()方法默认返回"sessionFactory"字符串,在spring配置文件中可要注意了,如果是其它的名字,则要配正确。从这里看出Opensessioninview也需要sessionfactory的bean的注入,他默认的去找bean的id为sessionfactory的bean,如果sessionfactory的bean的id不是这个名字的话,要记得给这个过滤器配置一个参数,参数名为sessionfactoryBeanName,把他的value设置为的sessionfactory的bean的id值。
下一篇TransactionSynchronizationManager概述.还有SessionHolder类.
http://blog.sina.com.cn/s/blog_821025b70100w5b3.html
http://blog.163.com/juanming5612@126/blog/static/60345421201012115435606/
http://blog.youkuaiyun.com/sunyujia/article/details/2788192
http://www.iteye.com/topic/32001
http://blog.youkuaiyun.com/zxq1406spys/article/details/4748283