一、起源
这次发现是来源一个我正在开发的系统的一个现象,用户A查询之后,B进入系统,但是查询条件居然是A的。这样说可能不清楚,换句话说就是A在查询时此action的值栈
会存入一些数据,但是当B进入时此值栈居然是A的值栈,而不是一个新的值栈(因为有a访问时存入的数据)。而以我的理解:每个永远会(每个线程)在访问action时,都会
创建一个值栈,当请求结束(即不请求该action)值栈会清除,而且最重要的是A是A的值栈,B是B的值栈。在经过我一些列的测试之后,结果让我非常惊讶:值栈不仅不会清
空,而且值栈是共用的资源。
二、测试
为此我专门写了一个action和一个jsp页面用于测试。
TestAction.java
package com.zs.action;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
public class TestAction extends MyBaseAction implements IMyBaseAction{
String str;//测试用的属性
List<String> sengMail=new ArrayList<String>();
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public List<String> getSengMail() {
return sengMail;
}
public void setSengMail(List<String> sengMail) {
this.sengMail = sengMail;
}
//-------------------------------------------------
public String add() throws Exception {
String mailstr=getRequest().getParameter("mailstr");
sengMail.add(mailstr);
return gotoQuery();
}
public void clearOptions() {
// TODO Auto-generated method stub
}
public String delete() throws Exception {
// TODO Auto-generated method stub
return null;
}
public String gotoQuery() throws UnsupportedEncodingException {
return SUCCESS;
}
public String queryOfFenye() throws UnsupportedEncodingException {
// TODO Auto-generated method stub
return null;
}
public String update() throws Exception {
return gotoQuery();
}
}
test.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'test.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<a href="<%=path %>/test!gotoQuery">测试</a>
<form action="<%=path %>/test!gotoQuery" method="post">
<input type="text" name="str"/>
<input type="submit"/>
</form>
${str }
<hr/>
模拟发邮件
<form action="<%=path %>/test!add" method="post">
假设这是我要发的邮件:<input type="text" name="mailstr"/>
<input type="submit"/>
</form>
<c:forEach items="${sengMail}" var="m">
${m }<br/>
</c:forEach>
<br/>
</body>
</html>
1,值栈是否会自动清空
第一次进入jsp页面时,是这样的,此时没有访问过action,然后在第一个文本框输入123,点击右边提交。
可以看到输入的值已经存入action的str。
当通过改地址栏到test.jsp,这样就意味着请求已结束,按照我的认知action的值栈会被清空,或者说在下一次访问时会被清空。
但是当点击测试,进入action时,发现值栈未被清空,123仍然显示出来了。
那么,这个结果说明值栈是不会被清空的,这与我之前的认知以及网上的说法不符,但既然事实是这样,我选择相信事实。
2,值栈是否是共享资源
紧接着上面的测试,这时我换一个浏览器用于模拟另一个用户访问,点击测试,进入action。
但结果是值栈存在,而且str的值仍然为123。
之后,我使用其他同事的电脑反复测试了几次,得到的结果仍然是一样的。那么,可以得出结论:值栈不仅不会自动清除,而且是所有线程的共有资源。基于此,我想到我的项目邮件提箱功能有一个问题:邮件经常会由于发送频率太快导致发送失败。为此之前我想的解决方案是:写一个公共的邮件发送者,它接受每个用户发送过来的邮件体(封装的邮件),然后按照顺序一个个排队发送,并设置间隔时间以防止频率过快。为实现这种效果我首先想到的是单例模式+观察者模式+资源池化。但这次的发现让我有了一个新的想法,既然action的值栈是公共资源,那么是否可以对它进行改造使它成为邮件发送者呢?期待我下次的测试结果吧。