由Spring管理的Struts2的Action的单实例问题

13 篇文章 0 订阅

背景  :


1) Struts2  会对每一个请求,产生一个Action的实例来处理.

2) Spring的Ioc容器管理的bean默认是单实例的.


Struts2 与Spring整合后,由spring来管理Struts2 的Action,会遇到什么问题  ?如何解决  ?

----------------------------------------------------------------


会遇到什么问题?


Struts2 与Spring整合后, 由spring来管理Struts2 的Action,   bean默认是单实例有情况下,会有如下问题:

1) Action是单例,其中的FieldError,actionerror中的错误信息 会累加, 即使再次输入了正确的信息,也过不了验证.

2) Struts2 的Action是有状态的,他有自己的成员属性, 所以在多线程下,会有问题.


----------------------------------------------------------------

 

如何解决?


方案一: 就是不用单例, spring中bean的作用域设为prototype,每个请求对应一个实例.

或者取消单例模式,如配置文件修改为(Spring版本的不同,在DTD文件约束也不同):

方案二: spring中bean的作用域设为session ,每个session对应一个实例,解决了多线程问题.

 

<bean id="authgroupact" class="com.skywalk.framework.web.struts.action.AuthoriseGroupAct" singleton="false">
        <property name="ibser">
            <ref bean="ibser" />
        </property>
    </bean>
 

再写一个拦截器,  清空 FieldError与actionerror

 

public class ClearFieldErrorInterceptor extends AbstractInterceptor {   
  
@Override  
public String intercept(ActionInvocation invocation) throws Exception {   
ActionSupport actionSupport = (ActionSupport)invocation.getAction();   
actionSupport.clearErrorsAndMessages();   
String resultCode = invocation.invoke();   
return resultCode;   
}   

 

 

总结  :

 

方案一 , bean的作用域设为prototype,  担心性能不好, 但没实际测试过,不好说话,也只是担心而已.


方案二:  由于对方案一有担心, 所有才有了方案二, 不知比方案一性能 能高多少


我们知道在Struts中Action是从map中拿出来的,是单实例的。那么在多线程调用的时候会出问题。

那么在Spring中通过getBean方法每调用一次,spring都会new一个实例给我们,所以可以利用这一点把Struts中action的创建交给Spring来处理。

Spring Bean的作用域:

Bean作用域

作用域描述

singleton

在每个Spring IoC容器中一个bean定义对应一个对象实例。

prototype

一个bean定义对应多个对象实例。

request

在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例, 它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。

session

在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。

global session

在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。

继续之前先回顾一下==与equals的用法

我们说==比较的是两个对象的地址,而equals比较的是两个对象的内容。所以

	String s1 = new String("sfsf");
String s2 = new String("sfsf");
System.out.println(s1==s2);
System.out.println(s1.equals(s2));

 上面打印的结果为:

false
true

 

说明:s1,s2分别在栈中分配内存,即两个局部变量。那么他们的值存放的是地址。

new String的时候会在堆中分配对象的空间,显然调用了两次new分配了两个对象的地址。所以s1与s2的值即地址是不一样的,所以s1==s2返回为false.

而s1.equals(s2)比较的是两个对象的内容,显然对象内容都是sfsf所以返回为true.

 

相关知识如:

String s = new String("xyz");创建了几个String Object

  答:"xyz"本身作为字符常量,在汇编语言中应该作为常量放在数据段,Java有一个类似数据段的constant pool保存这个常量,在classloader加载这个类的时候就把"xyz"和这个类的其他一些信息放在constant pool new String("xyz")根据常量"xyz"在heap上创建String对象所以,一共两个对象
String(String original) Initializes a newly created String object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string.

 

那么现在我们对从spring得到的对象进行测试。

 

测试代码:

package com.lwf.bean;

public class Bean1 {

}

 配置文件:

 
 
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns:aop="http://www.springframework.org/schema/aop"
		xmlns:tx="http://www.springframework.org/schema/tx"
		xsi:schemaLocation="
			http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
			http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
			http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
	<bean id="bean1" class="com.lwf.bean.Bean1"></bean>


</beans>
 

 测试类:

package com.lwf.client;

import junit.framework.TestCase;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.lwf.bean.Bean1;


public class Client extends TestCase {
public void testScope() {

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext*.xml");
Bean1 bean1 = (Bean1)ctx.getBean("bean1");
Bean1 bean2 = (Bean1)ctx.getBean("bean1");
System.out.println(bean1==bean2);
System.out.println(bean1.equals(bean2));


}
}

 

运行结果:

2010-05-19 14:34:07,419 INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1c78e57: display name [org.springframework.context.support.ClassPathXmlApplicationContext@1c78e57]; startup date [Wed May 19 14:34:07 CST 2010]; root of context hierarchy
2010-05-19 14:34:07,654 INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - Loading XML bean definitions from file [D:\workdirlocal\SpringBean\bin\applicationContext.xml]
2010-05-19 14:34:08,076 INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@1c78e57]: org.springframework.beans.factory.support.DefaultListableBeanFactory@80fa6f
2010-05-19 14:34:08,123 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@80fa6f: defining beans [bean1]; root of factory hierarchy
true
true

 

测试发现bean1==bean2,bean1.equals(bean2)均返回为true。这说明默认的情况下,Spring采用的是单例Singleton模式创建对象,一旦创建,以后每次只是把引用返回。所以所有返回的对象都是同一个。

 

这个在配置文件中是可以修改的,如我们在bean的配置上增加scope属性:

<bean id="bean1" class="com.lwf.bean.Bean1" scope="prototype"></bean>

 

测试上面代码:

结果为:

2010-05-19 16:05:47,353 INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1c78e57: display name [org.springframework.context.support.ClassPathXmlApplicationContext@1c78e57]; startup date [Wed May 19 16:05:47 CST 2010]; root of context hierarchy
2010-05-19 16:05:47,524 INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - Loading XML bean definitions from file [D:\workdirlocal\SpringBean\bin\applicationContext.xml]
2010-05-19 16:05:47,899 INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@1c78e57]: org.springframework.beans.factory.support.DefaultListableBeanFactory@80fa6f
2010-05-19 16:05:47,931 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@80fa6f: defining beans [bean1]; root of factory hierarchy
false
false

 

可以看到返回为false,false即每次创建的实例是不同的。我们在使用这一特性解决struts action单实例时就要这样配置。

 

Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值