论坛首页 Java企业应用论坛

讨论:关于ThreadLocal用法的一点疑惑

浏览 34833 次
该帖已经被评为精华帖
作者 正文
   发表时间:2003-12-03  
我使用ThreadLocal来管理session的动机是,为了避免在一个页面,也就是一个线程中过于频繁的openSession,和closeSession(),而增加不必要的性能负担。这是ThreadLocalSession的代码:
public class ThreadLocalSession{
	
	// The object of Hibernate environment settings, generating via using XML files.  
	private static Configuration config;
	
	// SessionFactory
	private static SessionFactory sessionFactory;

	// ThreadLocal variable, used to save the object of ThreadLocalSession
	private static final ThreadLocal sessionContext = new ThreadLocal();;
	
	static {
		init();;
	}
	
	private static final void init(); {    
		try {      
			config = new Configuration();.configure();;      
			sessionFactory = config.buildSessionFactory();; 
		} catch (HibernateException he); {
			he.printStackTrace(System.err);;
			config = null;
			sessionFactory = null;
		}  
	}
	
	public static Session getSession(); throws HibernateException {    
		Session session = (Session);sessionContext.get();;
		if(session == null);{
			session = sessionFactory.openSession();;      
			sessionContext.set(session);;
		}
		return session;  
	}  
	
	public static void closeSession(); throws HibernateException{
		Session session = (Session);sessionContext.get();;
		sessionContext.set(null);;
		if(session != null);{
			session.close();;
		}
	}
	
	
	public static Configuration getConfig();{    
		return config;  
	}  
	
	public static SessionFactory getSessionFactory();{    
		return sessionFactory;  
	}
	
}


在一个jsp页面中,如果我某处调用了类foo的函数method,
<%
foo.method();;
%>

我认为foo.method()应该这样用ThreadLocal:
public void method() throws HibernateException{
ThreadLocalSession.getSession();
//to do something...
//此处并不调用关闭ThreadLocalSession.closeSession();
}

而是在一个jsp页面中来管理ThreadLocalSession,结构如下:
<%
Session sess = ThreadLocalSessin.getSession();;
 Transaction tx;
 try {
     tx = sess.beginTransaction();;
     //do some work
     ...
     tx.commit();;
 }
 catch (Exception e); {
     if (tx!=null); tx.rollback();;
     throw e;
 }
 finally {
     ThreadLocalSession.closeSession();;
 }
%>


但是网上好些例子都将ThreadLocalSession.closeSession();放在method中,我觉得那样的话,ThreadLocal岂不是没有任何作用?
照样在一个线程中open,close session多次?但是,由于见到的这样的代码
好几次,所以来这里确认一下。

btw:这段GavinKing的话,不是太明白,帮忙解释一下:
Thread Local Session
Hibernate is designed to be useable in any kind of Java application, including applications that make extensive use of multithreading. So, unlike the ODMG API, Hibernate's native API does not use the current thread to maintain associations between Session and Transaction or between Session and application thread. This can be inconvenient for J2EE applications where access to a Session instance is always from a particular thread. It is particularly inconvenient when using a DAO pattern, when the different DAO classes need to obtain the (same) current session
   发表时间:2003-12-03  
引用
但是网上好些例子都将ThreadLocalSession.closeSession();放在method中

如果在Web应用中,应该放在ServletFilter里面同一closeSession的。如果在页面里面就closeSession,那么肯定就没有发挥ThreadLocal的效果。

我现在写的程序不是Web程序,我也在程序里面不关闭Session的,而是最后统一关闭。

例如:

	public static boolean updateUser(User user); {
		try {
			Session s = ReportSession.currentSession();;
			ReportSession.currentTransaction();;			
			s.update(user);;
			s.flush();;			
			return true;
		} catch (HibernateException e); {
			System.out.println(e.getMessage(););;
			return false;
		}		
	}
0 请登录后投票
   发表时间:2003-12-03  
ServletFilter 是一种模式吗?
我没有在设计模式中找到他,我是不是可以这样理解:

假如我完成一个动作,比如createXXX。一共涉及到3个步骤,最后提交,一共四个页面完成。如果我按照页面来作的话,session一共开关四次。
--当然我最期望的事情是做完这个事情(createXXX)一共开关一次。

那么是不是整个过程都应该在XXX.doFiter()中控制?
谁能解释一些这个过程?
最好有些代码框架。
0 请登录后投票
   发表时间:2003-12-03  
简单 Servlet2.3 filter 开发
作者:润名

一:简介

新的 Java Servlet 2.3 规范有不少最激动人心的功能,其中之一便是 filter (过滤器)。filter可以改变一个请求(request)或者是修改响应(response)。filter不是一个servlet,它只是一个servlet接受到请求前的预处理器。就是说,用户发送一个请求给servlet时,在servlet处理之前,这个filter首先执行,然后才是servlet的执行。

二:作用

filter可以用在下面几个方面

1:访问特定资源(Web 页、JSP 页、servlet)时的身份

2:访问资源的记录

3:访问资源的转换

三:编写filter

一个filter 必须实现javax.servlet.Filter 接口,即实现下面的三个方法:


1: doFilter(ServletRequest, ServletResponse, FilterChain):这是一个完成过滤行为的方法。这同样是上游过滤器调用的方法。引入的 FilterChain 对象提供了后续过滤器所要调用的信息。


2: init(FilterConfig):这是一个容器所调用的初始化方法。它保证了在第一次 doFilter() 调用前由容器调用。您能获取在 web.xml 文件中指定的初始化参数。


3: destroy():容器在破坏过滤器实例前,doFilter()中的所有活动都被该实例终止后,调用该方法。 

四:示例

功能:限制客户端 IP 的访问

代码如下:

package com.Servlet.filter; 
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.Filter;

public class myfilter implements Filter
{
private FilterConfig filterConfig = null;

public void init(FilterConfig filterConfig)
{
this.filterConfig = filterConfig;
}

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException
{
try
{
res.setContentType("text/html;CHARSET=utf8");
PrintWriter out = res.getWriter();
String remoteAddr = ((HttpServletRequest) req).getRemoteAddr();

if ((remoteAddr.indexOf("127.0.0.1") != -1) || (remoteAddr.indexOf("localhost") != -1)) { //这里做判断

out.println("&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;");
out.println("&lt;h1&gt;哈哈,IP 127.0.0.1 和 IP localhost 不能访问本网站~~&lt;/h1&gt;");
out.println("&lt;/body&gt;&lt;/html&gt;");
out.close();
return;
}
else
{
out.println("&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;");
out.println("&lt;h1&gt;恭喜,你已经成功访问本网站了~~&lt;/h1&gt;");
out.println("&lt;/body&gt;&lt;/html&gt;");
out.close();
}

}
catch (Exception e)
{
e.printStackTrace();
}
}

public void destroy()
{
}
}


实现思路:通过ServletRequest类的getRemoteAddr()方法得到访问这个应用的客户端ip,然后对这个ip作一些处理,如果不符合条件,可以限制访问。这样可以很好的保护应用。

五:配置

以 Weblogic 为例:每个使用filter的应用的web.xml类似下面


&lt;?xml version="1.0" ?&gt;
&lt;!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"&gt;
&lt;web-app&gt;
&lt;welcome-file-list&gt;
&lt;welcome-file&gt;index.html&lt;/welcome-file&gt;
&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;
&lt;/welcome-file-list&gt; 

// 下面是过滤器的配置

&lt;filter&gt;
&lt;filter-name&gt;MyFilter&lt;/filter-name&gt; //这里是Filter的名字,随便你怎么起
&lt;filter-class&gt;com.Servlet.filter.myfilter&lt;/filter-class&gt; //Filter的类名,注意包含package
&lt;/filter&gt;

&lt;filter-mapping&gt;
&lt;filter-name&gt;MyFilter&lt;/filter-name&gt;//与上面的保持一致
&lt;url-pattern&gt;/*&lt;/url-pattern&gt; //对所有资源应用此filter
&lt;/filter-mapping&gt;
&lt;/web-app&gt;
0 请登录后投票
   发表时间:2003-12-03  
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain); throws IOException, ServletException
    {
        // cast to the types I want to use
        HttpServletRequest request = (HttpServletRequest); req;
        HttpServletResponse response = (HttpServletResponse); resp;
        HttpSession session = request.getSession(true);;

        Session ses = null;
        boolean sessionCreated = false;

        try
        {
            chain.doFilter(request, response);;
        }
        finally
        {
            try
            {
                [b]ThreadLocalSession.closeSession();;[/b]
            }
            catch (Exception exc);
            {
                log.error("Error closing hibernate session.", exc);;
                exc.printStackTrace();;
            }
        }
    }

在Filter完成之后,岂不是在我的正活servlet和jsp,还没有开始之前,session也就关闭了?
0 请登录后投票
   发表时间:2003-12-03  
我式了一下,明白了
在doFilter()之前的代码将在filter作用的url之前运行,(也就是session.open()应该执行的地方)
而doFilter()之后的代码将在filter作用的url之后运行。(也就是session.close()应该执行的地方)

我刚开始的时候误以为在filter执行完成之后,才开始将request发送给url。才会有此愚蠢的问题。
1 请登录后投票
   发表时间:2003-12-03  

引用
如果在Web应用中,应该放在ServletFilter里面同一closeSession的。如果在页面里面就closeSession,那么肯定就没有发挥ThreadLocal的效果。

使用filter也是在一个页面或者一个servlet中,开关一次session啊?
0 请登录后投票
   发表时间:2003-12-06  
org.xml.sax.SAXParseException: Element type "filter" must be declared.
        at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Un
known Source);
        at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source);
        at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source);
        at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source);
        at org.apache.xerces.impl.dtd.XMLDTDValidator.handleStartElement(Unknown
 Source);
        at org.apache.xerces.impl.dtd.XMLDTDValidator.startElement(Unknown Sourc
e);
        at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanStartElemen
t(Unknown Source);(Compiled Code);


我照着做了,出现如上错误!

我得web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">

   <web-app id="WebApp_1068866653656">
      <display-name>CenPortal</display-name>
      <servlet id="Servlet_1068866556453">
         <servlet-name>jetspeed</servlet-name>
         <servlet-class>org.apache.turbine.Turbine</servlet-class>
         <init-param id="InitParam_1068866653672">
            <param-name>properties</param-name>
            <param-value>WEB-INF/conf/TurbineResources.properties</param-value>
         </init-param>
         <load-on-startup>1</load-on-startup>
      </servlet>

	  <filter> 
		<filter-name>MyFilter</filter-name> 
		<filter-class>com.Servlet.filter.myfilter</filter-class>
	  </filter> 

	  <filter-mapping> 
		<filter-name>MyFilter</filter-name>
		<url-pattern>/*</url-pattern>
	  </filter-mapping> 


      <servlet-mapping id="ServletMapping_1068866653672">
         <servlet-name>jetspeed</servlet-name>
         <url-pattern>/portal/*</url-pattern>
      </servlet-mapping>
      <servlet-mapping id="ServletMapping_1068866653673">
         <servlet-name>jetspeed</servlet-name>
         <url-pattern>/jetspeed/*</url-pattern>
      </servlet-mapping>
      <mime-mapping id="MimeMapping_1068866653672">
         <extension>wbmp</extension>
         <mime-type>image/vnd.wap.wbmp</mime-type>
      </mime-mapping>
      <mime-mapping id="MimeMapping_1068866653673">
         <extension>wml</extension>
         <mime-type>text/vnd.wap.wml</mime-type>
      </mime-mapping>
      <mime-mapping id="MimeMapping_1068866653674">
         <extension>wmls</extension>
         <mime-type>text/vnd.wap.wmlscript</mime-type>
      </mime-mapping>
      <welcome-file-list id="WelcomeFileList_1068866653672">
         <welcome-file>index.jsp</welcome-file>
         <welcome-file>index.wml</welcome-file>
         <welcome-file>index.html</welcome-file>
      </welcome-file-list>


	  

   </web-app>
0 请登录后投票
   发表时间:2003-12-07  
chill 写道
		<filter-class>com.Servlet.filter.myfilter</filter-

我猜可能是这里的问题,java的类名一般是大写字母开头。
你为什么独树一帜呢?-myfilter。
是不是些错了?
0 请登录后投票
   发表时间:2003-12-08  
如果在业务流程中会使用多个数据库服务器,如何在Filter类中进行设置?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics