struts1安全问题,和struts2的区别

struts1.x的一个安全性问题是值得注意的。因为过去的模式是前台页面数据通过actionForm传入,action中的excute方法接收,这个问题是不存在的。但是,如果在action中直接定义实例变量,问题就很大了。原因其实也很简单:为了确保线程安全(thread-safe),在一个应用的生命周期中,Struts框架只会为每个Action类创建一个Action实例(与servlet是一样的)。所有的客户请求共享一个Action实例,并且所有请求线程可以同时执行它的execute()方法。所以,每个action只有一个实例,在action打印this也可以看到,确实是一样的,所以,不要在Action里面使用全局变量记忆数据,没有意义而且不安全使用actionForm则不会有问题,原因也很简单:actionForm是通过参数形式传入action的,不存在共享变量的问题,其实每个request产生的actionForm实例也是不同的。因此在使用struts1.x的时候要注意线程安全性问题

************************************************************************************************

总的来说,Struts1的Action是单例模式,因此开发者必须保证它是线程安全的或是同步的,因为Struts1中每个Action仅有一个实例来处理所有的请求。

但是在用Struts1开发时并没有考虑到线程安全问题,这是因为我们在Action中使用的基本都是局部变量,而“局部变量是线程安全的。因为每执行一个方法,都会在独立的空间创建局部变量,它不是共享的资源。局部变量包括方法的参数变量”(忘了引自哪了)。在Struts1中,所有的变量都是定义在Action中我们要执行的方法里的(Action中的execute方法或DispatchAction中指定要执行的方法),我们用于封装客户端请求参数的ActionForm,也是作为一个参数传入,也属于局部变量,因此,不存在线程安全问题。

Struts2的Action对象为每一个请求产生一个实例,因此,虽然在Action中定义了很多全局变量,也不存在线程安全问题。

Struts2框架在处理每一个用户请求的时候,都建立一个单独的线程进行处理,值栈ValueStack也是伴随着局部线程而存在的。在该线程存在过程中,可以随意访问值栈,这就保证了值栈的安全性。

在Struts2中,ActionContext是一个局部线程,这就意味着每个线程中的ActionContext内容都是唯一的。所以开发者不用担心Action的线程安全。

《strut2权威指南》中有这么一段:

线程模式方面的对比:Struts1Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1Action能做的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的;Struts2Action对象为每一个请求产生一个实例,因此没有线程安全问题。

都产生一个实例,所以说全局的变量应该是共享的。

************************************************************************************************

Struts的线程安全

Servlet是在多线程环境下的。即可能有多个请求发给一个servelt实例,每个请求是一个线程。

struts下的action也类似,同样在多线程环境下。可以参考strutsuserguide:http://struts.apache.org/struts-action/userGuide/building_controller.html中的ActionClassDesignGuidelines一节:Writecodeforamulti-threadedenvironment-OurcontrollerservletcreatesonlyoneinstanceofyourActionclass,andusesthisoneinstancetoserviceallrequests.Thus,youneedtowritethread-safeActionclasses.Followthesameguidelinesyouwouldusetowritethread-safeServlets.

译:为多线程环境编写代码。我们的controllerservlet指挥创建你的Action类的一个实例,用此实例来服务所有的请求。因此,你必须编写线程安全的Action类。遵循与写线程安全的servlet同样的方针。

1.什么是线程安全的代码

在多线程环境下能正确执行的代码就是线程安全的。

安全的意思是能正确执行,否则后果是程序执行错误,可能出现各种异常情况。

2.如何编写线程安全的代码

很多书籍里都详细讲解了如何这方面的问题,他们主要讲解的是如何同步线程对共享资源的使用的问题。主要是对synchronized关键字的各种用法,以及锁的概念。

Java1.5中也提供了如读写锁这类的工具类。这些都需要较高的技巧,而且相对难于调试。

但是,线程同步是不得以的方法,是比较复杂的,而且会带来性能的损失。等效的代码中,不需要同步在编写容易度和性能上会更好些。

我这里强调的是什么代码是始终为线程安全的、是不需要同步的。如下:

1)常量始终是线程安全的,因为只存在读操作。

2)对构造器的访问(new操作)是线程安全的,因为每次都新建一个实例,不会访问共享的资源。

3)最重要的是:局部变量是线程安全的。因为每执行一个方法,都会在独立的空间创建局部变量,它不是共享的资源。局部变量包括方法的参数变量。

strutsuserguide里有:

OnlyUseLocalVariables-Themostimportantprinciplethataidsinthread-safecodingistouseonlylocalvariables,notinstancevariables,inyourActionclass.

译:只使用用局部变量。--编写线程安全的代码最重要的原则就是,在Action类中只使用局部变量,不使用实例变量。

总结:

在Java的Web服务器环境下开发,要注意线程安全的问题。最简单的实现方式就是在Servlet和StrutsAction里不要使用类变量、实例变量,但可以使用类常量和实例常量。

如果有这些变量,可以将它们转换为方法的参数传入,以消除它们。

注意一个容易混淆的地方:被Servlet或Action调用的类中(如值对象、领域模型类)中是否可以安全的使用实例变量?如果你在每次方法调用时

新建一个对象,再调用它们的方法,则不存在同步问题---因为它们不是多个线程共享的资源,只有共享的资源才需要同步---而Servlet和Action的实例对于多个线程是共享的。

换句话说,Servlet和Action的实例会被多个线程同时调用,而过了这一层,如果在你自己的代码中没有另外启动线程,且每次调用后续业务对象时都是先新建一个实例再调用,则都是线程安全的。

相关推荐