Struts+Spring+Hibernate整合笔记一

OpenSessionInview:

1.如果当前方法没有事物环境,则调用完毕getHibernate以后。session关闭;

  说明:1如果测试dao层,没有事物环境

     2如果测试service层,但是如果service层的方法没有包含在事物的声明中,则也没有事物环境

2.如果当前方法有事物环境,则不能关闭session

3.如果事物环境方法被调用完毕以后,session关闭

背景:

hibernate 允许对关联对象、属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Session 范围之内进行。如果 Service 层返回一个启用了延迟加载功能的领域对象给 Web 层,当 Web 层访问到那些需要延迟加载的数据时,由于加载领域对象的 Hibernate Session 已经关闭,这些导致延迟加载数据的访问异常。

把一个Hibernate Session和一次完整的请求过程对应的线程相绑定。目的是为了实现”Open Session in View”的模式。例如: 它允许在事务提交之后延迟加载显示所需要的对象。
OpenSessionInViewFilter 过滤器将 Hibernate Session 绑定到请求线程中,它将自动被 spring 的事务管理器探测到。所以 OpenSessionInViewFilter 适用于 Service 层使用HibernateTransactionManager 或 JtaTransactionManager 进行事务管理的环境,也可以用于非事务只读的数据操作中。

在不同的技术框架下,实现Open session in view的手段不同:
在servlet中用过滤器实现
在struts中用拦截器实现
在spring中使用AOP实现
这里给出在ssh框架中用spring的AOP实现:

配置:

 1 <filter>  
 2         <filter-name>Spring OpenSessionInViewFilter</filter-name>  
 3         <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>  
 4      <init-param>  
 5 
 6 <!--  
 7 指定org.springframework.orm.hibernate3.LocalSessionFactoryBean在spring配置文件中的名称,默认值为sessionFactory  
 8      如果LocalSessionFactoryBean在spring中的名称不是sessionFactory,该参数一定要指定,否则会出现找不到sessionFactory的异常  
 9 -->  
10      <param-name>sessionFactoryBean</param-name>  
11    <param-value>sessionFactory</param-value>  
12   </init-param>  
13     </filter>  
14     <filter-mapping>  
15         <filter-name>Spring OpenSessionInViewFilter</filter-name>  
16         <url-pattern>/*</url-pattern>  
17     </filter-mapping>  
View Code

原理:

 1 protected void doFilterInternal(    
 2             HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)    
 3             throws ServletException, IOException {    
 4         SessionFactory sessionFactory = lookupSessionFactory(request);    
 5         boolean participate = false;    
 6         if (isSingleSession()) {    
 7             // single session mode    
 8             if (TransactionSynchronizationManager.hasResource(sessionFactory)) {    
 9                 // Do not modify the Session: just set the participate flag.    
10                 participate = true;    
11             }    
12             else {    
13                 logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");    
14                 Session session = getSession(sessionFactory);    
15                 TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));    
16             }    
17         }    
18         else {    
19             // deferred close mode    
20             if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {    
21                 // Do not modify deferred close: just set the participate flag.    
22                 participate = true;    
23             }    
24             else {    
25                 SessionFactoryUtils.initDeferredClose(sessionFactory);    
26             }    
27         }    
28         try {    
29             filterChain.doFilter(request, response);    
30         }    
31         finally {    
32             if (!participate) {    
33                 if (isSingleSession()) {    
34                     // single session mode    
35                     SessionHolder sessionHolder =    
36                             (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);    
37                     logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");    
38                     closeSession(sessionHolder.getSession(), sessionFactory);    
39                 }    
40                 else {    
41                     // deferred close mode    
42                     SessionFactoryUtils.processDeferredClose(sessionFactory);    
43                 }    
44             }    
45         }    
46     }    
47 
48 
49 protected void doFilterInternal(HttpServletRequest request,  
50         HttpServletResponse response, FilterChain filterChain)  
51         throws ServletException, IOException {  
52     /**
53      * 从spring的上下文中取得SessionFactory对象
54      * WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
55      * return (SessionFactory) wac.getBean(getSessionFactoryBeanName(),SessionFactory.class);
56      * getSessionFactoryBeanName()方法默认返回"sessionFactory"字符串,在spring配置文件中可要注意了,别写错了.
57      */  
58     SessionFactory sessionFactory = lookupSessionFactory(request);  
59     boolean participate = false;// 标识过滤器结束时是否进行关闭session等后续处理  
60     if (isSingleSession()) {//单session模式  
61         //判断能否在当前线程中取得sessionFactory对象对应的session  
62         if (TransactionSynchronizationManager.hasResource(sessionFactory)) {  
63             //当能够找到session的时候证明会有相关类处理session的收尾工作,这个过滤器不能进行关闭session操作,否则会出现重复关闭的情况.  
64             participate = true;//但我并没有想出正常使用的情况下什么时候会出现这种情况.  
65         } else {  
66             Session session = getSession(sessionFactory);//当前线程取不到session的时候通过sessionFactory创建,下面还会详细介绍此方法  
67             //将session绑定到当前的线程中,SessionHolder是session的一层封装,里面有个存放session的map,而且是线程同步的Collections.synchronizedMap(new HashMap(1));  
68             //但是单session模式下一个SessionHolder对应一个session,核心方法是getValidatedSession 取得一个open状态下的session,并且取出后从map中移出.  
69             TransactionSynchronizationManager.bindResource(sessionFactory,  
70 
71              new SessionHolder(session));  
72     }  
73 } else {//这段是非单session模式的处理情况,没有研究.但粗略看上去,大概思想是一样的  
74     if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {  
75         participate = true;  
76     } else {  
77         SessionFactoryUtils.initDeferredClose(sessionFactory);  
78     }  
79 }  
80 try {  
81     //将session绑定到了当前线程后,就该处理请求了  
82     filterChain.doFilter(request, response);  
83 }finally {  
84     if (!participate) {  
85         if (isSingleSession()) {  
86             //当请求结束时,对于单session模式,这时候要取消session的绑定,因为web容器(Tomcat等)的线程是采用线程池机制的,线程使用过后并不会销毁.  
87             SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager  
88                     .unbindResource(sessionFactory);  
89             //取消绑定只是取消session对象和线程对象之间的引用,还没有关闭session,不关闭session相对于不关闭数据库连接,所以这里要关闭session  
90             closeSession(sessionHolder.getSession(), sessionFactory);  
91         } else {  
92             //非单session模式,没有研究.  
93             SessionFactoryUtils.processDeferredClose(sessionFactory);  
94         }  
95     }  
96 }  
View Code

步骤:
1. 获取session,打开session
2. filterChain.doFilter(request, response);
3. 关闭session
在2中可能执行了若干的Servlet、JSP、Action等等,最终处理完渲染完页面之后,再进入OpenSessionInViewFilter的3关闭session
现在只要保证在2中不论是Servlet、JSP还是Action中执行DAO时获取的session都是1中打开的同一个session,并且在DAO关闭session时并不实际关闭,留到OpenSessionInViewFilter的3中再最终关闭,就实现了懒加载了,因为只要是在OpenSessionInViewFilter过滤的范围内,session都处于打开,比如在一个Servlet中查到一个Bean,这时他的关联实体并没有加载,当这个Servlet重定向到一个JSP,在其中得到这个Bean后直接访问之前没加载的那些关联实体,会实时的加载这个关联实体,因为session还未关闭,这便是懒加载了。

解决方法:使用spring提供的过滤器

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
 3   <display-name>day04-02-itheima08-s2sh</display-name>
 4       <listener>
 5         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 6     </listener>
 7     <context-param>
 8         <param-name>contextConfigLocation</param-name>
 9         <param-value>classpath:spring/applicationContext.xml</param-value>
10     </context-param>
11     
12     <filter>
13         <filter-name>OpenSessionInViewFilter</filter-name>
14         <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
15     </filter>
16     <filter-mapping>
17         <filter-name>OpenSessionInViewFilter</filter-name>
18         <url-pattern>*.action</url-pattern>
19     </filter-mapping>
20     
21     
22     <filter>
23         <filter-name>struts2</filter-name>
24         <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
25     </filter>
26     <filter-mapping>
27         <filter-name>struts2</filter-name>
28         <url-pattern>/*</url-pattern>
29     </filter-mapping>
30     
31     
32   <welcome-file-list>
33     <welcome-file>index.jsp</welcome-file>
34   </welcome-file-list>
35 </web-app>
web.xml

猜你喜欢

转载自www.cnblogs.com/biaogejiushibiao/p/9495629.html