`
zhangfeilo
  • 浏览: 399140 次
  • 性别: Icon_minigender_1
  • 来自: 昆明
社区版块
存档分类
最新评论

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

阅读更多

背景  :


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作用域。

分享到:
评论
2 楼 dmy110 2012-08-25  
貌似如果不需要使用spring的其他AOP功能的话,可以不使用spring来管理action.至于action中需要注入的依赖,会通过autowired自动注入.

When an object is to be created, it uses the class attribute in the Struts configuration to correspond to the id attribute in the Spring configuration. If not found, the class will try to be created as usual, then be autowired by Spring.
这是struts2-spring plugin中的介绍.
1 楼 瞬息万变 2012-04-20  
讲的挺好的,实用。

相关推荐

    spring管理struts的action的代码

    这行配置告诉Struts框架使用Spring作为对象工厂,这意味着所有的Action实例都将由Spring容器来创建和管理。这样一来,Action类就无需实现特定的接口或继承特定的基类,可以保持其原有的简洁性。 #### 五、示例:...

    spring管理struts和hibernate

    - 使用Spring的`&lt;bean&gt;`元素来创建Struts Action的实例,同时可以利用Spring的依赖注入特性来管理Action与其他组件之间的依赖关系。 2. **简化开发流程**: - 通过Spring管理Struts中的Action,可以减少大量的...

    Struts2+Spring演示实例源代码

    - **Spring插件**:Struts2提供了一个Spring插件,使得Spring管理的Bean可以直接作为Struts2的Action。 - **Action配置**:在struts.xml中声明Spring管理的Action,不再需要在Action类上添加任何Struts注解。 - *...

    spring与struts2整合

    通过在 Action 类上使用 `@Component` 注解并配置在 Spring 配置文件中,可以确保 Spring 能够创建和管理这些类的实例。 5. **拦截器**:Struts2 中的拦截器可以用来实现通用的行为,如权限验证、日志记录等。通过...

    struts2+spring实例程序

    在实际项目中,开发人员会创建一个Struts2的Action类,该类可能会依赖于Spring管理的服务。Action类通过注解或者配置文件声明其依赖,Spring容器会自动将依赖注入到Action类中。同时,Struts2的配置文件(如struts....

    maven构建spring struts2 ibatis velocity小实例

    在本实例中,Maven扮演着核心角色,通过其配置管理Spring、Struts2、iBatis以及Velocity的依赖,使得项目的构建过程更加规范和高效。开发者可以通过编写pom.xml文件来声明项目依赖,Maven会自动下载并管理这些依赖库...

    ibatis+Spring+struts2整合实例

    - **整合工作**:在Struts2的Action类中,通过@Autowired注入Service层bean,Service层再调用由Spring管理的DAO实现类完成数据访问。同时,Spring的AOP功能可以用来实现事务管理,确保业务操作的原子性。 - **测试...

    struts2+spring练习

    这将使Struts2能够从Spring容器中获取Action实例,实现Action的依赖注入。配置通常包括修改`struts.xml`中的`&lt;package&gt;`标签,添加`parent="struts-default"`和`namespace="/"`, 并使用`&lt;action&gt;`标签的`class`属性...

    Spring与Struts2整合

    - 在使用Struts2-Spring插件时,注意Action类的生命周期是由Spring控制,而非Struts2。 整合Spring和Struts2是一个常见的Java Web开发实践,熟练掌握这一技能能够提高开发效率,提升应用的可维护性和扩展性。在实际...

    Maven下建立的spring+struts2+jstl实例

    本实例将探讨如何在Maven环境下搭建一个基于Spring、Struts2和JSTL的项目,这些技术的组合提供了强大的后端控制、依赖管理和前端展示能力。 首先,让我们详细了解每个组件的作用: 1. **Maven**:Maven是一个项目...

    spring_struts2_mybatis_注解的小实例

    在本项目"spring_struts2_mybatis_注解的小实例"中,我们将深入探讨如何使用SSM(Spring、Struts2、MyBatis)框架来实现一个基础的增删改查(CRUD)功能。SSM是Java Web开发中常用的三大组件,它们各自负责不同的...

    JPA+Spring+Struts整合实例,JPA+Spring+Struts整合实例

    同时,可以使用Spring插件(struts2-spring-plugin)来实现Spring与Struts的集成,这样Action类可以直接从Spring容器获取服务层对象。 **4. 实现业务逻辑** 创建JPA实体类,使用`@Entity`注解标识。接着,创建对应...

    spring+struts2图书管理系统

    同时,我们需要在Struts2的配置文件中指定Spring的Action代理(Spring-Action-Proxy),这样,Struts2的Action实例将由Spring管理。 在图书管理系统中,我们可以定义一个Spring Bean来代表图书实体类,包含了如书名...

    struts2_mybatis_spring_框架实例整合_数据库 文档

    Struts2、MyBatis和Spring是Java Web开发中常用的三大框架,它们分别负责MVC模式中的Action层、数据持久层和应用上下文管理。这篇文档将深入探讨如何将这三个框架整合在一起,以及如何结合数据库进行实际应用。 ...

    spring,struts1,hibernate实例

    然而,Struts1在后期的开发中逐渐暴露出一些问题,如性能瓶颈、复杂的配置等,这促使了Struts2的诞生。 最后,Hibernate是一个流行的Java ORM(对象关系映射)框架,它简化了数据库操作,使开发者能够用面向对象的...

    Struts2_Spring_Hibernate整合开发实例

    其次,Spring的角色在于统一管理整个应用程序的组件,包括Struts2的Action和Hibernate的SessionFactory。它通过ApplicationContext来加载和管理bean,提供依赖注入,使得各组件之间的关系更加松耦合。Spring还负责...

    Spring+Struts2.0实例代码

    学习这个实例,你可以了解如何将前端请求与后端服务连接,理解 Spring 如何通过 DI 管理对象,以及 Struts 2.0 如何组织和执行业务逻辑。这对于初学者来说是一个很好的实践平台,能帮助你快速掌握 Java Web 开发的...

    struts2+spring实例

    在Struts2中,我们可以利用Spring的Action代理来创建和管理Action实例,从而实现更灵活的控制。 整合Struts2和Spring的第一步是添加相关的依赖库到项目中,通常包括Struts2的Core库和Spring的Web上下文库。然后,...

    Spring+Struts2+JPA

    4. **整合步骤**:配置Struts2的Spring插件,使Struts2能够从Spring容器中获取Action实例。在Action类中注入Service,Service再注入DAO,形成完整的依赖链。 5. **测试**:编写JUnit测试用例,验证Spring、Struts2...

Global site tag (gtag.js) - Google Analytics