张慧的博客

张慧的博客

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  45 Posts :: 0 Stories :: 24 Comments :: 0 Trackbacks

#

顺序队列各种基本运算算法的实现

顺序队列是较为普遍的一种队列实现方式,采用环状数组来存放队列元素,并用两个变量分别指向队列的前端(front)和尾端(rear),往队列中加进或取出元素时分别改变这两个变量的计数(count)。
队列中用环状数组存储数据(合理利用空间、减少操作),通过基本的append()将元素加入队列,serve()将元素移出队列,先进入的先移出,retieve得到最先加入队列的元素。此外在继承的Extended_queue()中我增加了empty()和serve_and_retrieve()的功能。

【实验说明】

我选择的题目:课本中Programming Projects 3.3 P1
问题描述:Write a function that will read one line of input from the terminal. The input is supposed to consist of two parts separated by a colon ':'. As its results, your function should produce a single character as follows:
N   No colon on the line.
L   The left part(before the colon) is longer than the right.
R   The right part(after the colon) is longer than the left.
D   The left and right parts have the same length but are different.
S   The left and right are exactly the same.
Examples:
Use either a queue or an extended queue to keep track of the left part of the line while reading the right part.
1.分析队列要实现的基本功能以及继承的类要拓展的功能从而确定基本成员函数——append(),serve(),retireve(),拓展队列中:empty(),serve_and_retrieve(),确定队列中以环形数组存储数据从而确定成员函数——Queue_entry entry[],count(记录队列中数据数量)
2.编写队列的头文件及实现
3.分析题目中结束程序并输出几种字母的条件,简略画出功能实现的流程图,编写程序。(具体思路见源代码注释)
4.简单测试程序的几种情况,分析需要改进的地方

【相关代码】

queue.h

#ifndef QUEUE_H
#define QUEUE_H

const int maxqueue=10;
enum Error_code {success,overflow,underflow};
typedef 
char Queue_entry ;

class Queue{
public:
    Queue();
    
bool empty() const;
    Error_code append(
const Queue_entry &item);
    Error_code serve();
    Error_code retrieve(Queue_entry 
&item)const;
protected:
    
int count;
    
int front,rear;
    Queue_entry entry[maxqueue];
};

class Extended_queue:public Queue{
public:
    
bool full()const;
    
int size()const;
    
void clear();
    Error_code serve_and_retrieve(Queue_entry 
&item);
};

#endif

#include"queue.h"

Queue::Queue()
{
    count
=0;
    rear
=maxqueue-1;
    front
=0;
}

bool Queue::empty() const
{
    
return count==0;
}

Error_code Queue::append(
const Queue_entry &item)
{
    
if(count>=maxqueue)return overflow;
    count
++;
    rear
=((rear+1)==maxqueue)?0:(rear+1);
    entry[rear]
=item;
    
return success;
}

Error_code Queue::serve()
{
    
if(count<=0)return underflow;
    count
--;
    front
=((front+1)==maxqueue)?0:(front+1);
    
return success;
}

Error_code Queue::retrieve(Queue_entry 
&item) const
{
    
if(count<=0)return underflow;
    item
=entry[front];
    
return success;
}
bool Extended_queue::full() const{
    
return count==maxqueue;
}
int Extended_queue::size()const{
    
return count;
}
void Extended_queue::clear(){
    count
=0;
    rear
=front;
}
Error_code Extended_queue::serve_and_retrieve(Queue_entry 
&item){
    
if(count==0)return underflow;
    count
--;
    item
=entry[front];
    front
=((front+1)==maxqueue)?0:(front+1);
    
return success;
}

【过程记录】

实验截图:


【结果分析】

1.实验中我以课本后面的练习题为例,实现并验证了顺序队列的更种功能。
2.队列与栈一样是在类中以数组存储数据,但由于队列先进先出的特点在实现存储形式上与栈有一定的不同。因为如果与栈一样对数据操作,队列会无限向后扩大,而前面取出过数据的地方将不会再被利用,十分浪费,也很容易溢出。所以我们采用循环数组来存储,这样合理利用了资源。但在类的实现要要极为时刻考虑周全rear和front的各种可能,要判断是不是循环到了前面,count在此时的功能也极为突出。
3.书中的程序看似简单,但实际判断各种输出情况的时候却极难考虑周全。我首先做出了简易的流程图,然后才写函数,具体分析及思路可见我源码的注释。另外本题还有另外一种实现思路:即将左右输入分别存放在两个队列中,边取去边比较,那样在逻辑上容易理解一些。但鉴于题目的要求,我还是用边从左边队列中取出边比较右边输入的方法。
4.我在实验中遇到的问题:
(1)自己一开始在循环判断用的是cin.get()=='\n'即遇到回车就停止输入,但却无法如料想中结束循环……最终采用cin>>a && waiting(用以标志‘:’的输入)来作为循环终止的条件,这样虽然可以运行,但用户必须输入Ctrl+‘Z’以结束输入。看来自己对输入流的理解与掌握还没有到位。
(2)另外在检验的时候,我发现输入‘:’之前是否输入回车情况是有区别的。如
输入“sam:sam”(无空格),结果为“R”
输入“sam : sam”(有空格),结构为“S”
显然后者是我希望得到的结果,我分析可能是前面情况‘:’被列入了right的判断,从而使结构右边比左边长。还没有想到如何改进。


posted @ 2012-07-16 22:14 张慧 阅读(1737) | 评论 (0)编辑 收藏

(以oracle9i版本为例,本机必须安装oralce9i的客户端)

第一步:orahome92-configuration and migration tools- net managers


第二步:在“服务命名”中点“+


第三步:编辑一个你的服务名,(不是对方的数据库名)


第四步:默认选择TCP/IP


第五步:主机名填入对方的机器IP地址,端口默认(不要改)


第六步:服务名是对方的数据库名(要问对方),连接类型默认(不要改)


第七步:连接测试


一般测试结果需要“更改登录”


更改登录中,在用户名和口令中,录入对方数据库的用户名口令(你要访问的库)


测试成功!点击“关闭”

点“完成”


第八步:保存网络配置


在“E:\oracle\ora92\network\admin”中打开tnsnames.ora,可以看到配置情况:

MORCL =

  (DESCRIPTION =

    (ADDRESS_LIST =

      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.100.34)(PORT = 1521))

    )

    (CONNECT_DATA =

      (SERVICE_NAME = orcl)

    )

  )

第九步:到此,可以检查配置是否正确,是否连接成功

运行—输入sqlplus,在“请输入用户名”中键入 数据库连接方式


第十步:连接成功,可以通过PLSQL等客户端工具连接别人的数据库了!

posted @ 2012-07-16 22:12 张慧 阅读(6145) | 评论 (0)编辑 收藏

假如你要在linux下删除大量文件,比如100万、1000万,像/var/spool/clientmqueue/的mail邮件, 

像/usr/local/nginx/proxy_temp的nginx缓存等,那么rm -rf *可能就不好使了。 
rsync提供了一些跟删除相关的参数 
rsync --help | grep delete 
     --del                   an alias for --delete-during 
     --delete                delete files that don't exist on the sending side 
     --delete-before         receiver deletes before transfer (default) 
     --delete-during         receiver deletes during transfer, not before 
     --delete-after          receiver deletes after transfer, not before 
     --delete-excluded       also delete excluded files on the receiving side 
     --ignore-errors         delete even if there are I/O errors 
     --max-delete=NUM        don't delete more than NUM files 

其中--delete-before    接收者在传输之前进行删除操作 
可以用来清空目录或文件,如下: 
1、先建立一个空目录 
mkdir /data/blank 
2、用rsync删除目标目录 
rsync --delete-before -d /data/blank/ /var/spool/clientmqueue/ 
这样目标目录很快就被清空了 

又假如你有一些特别大的文件要删除,比如nohup.out这样的实时更新的文件,动辄都是几十个G上百G的,也可 

以用rsync来清空大文件,而且效率比较高 
1、创建空文件 
touch /data/blank.txt 
2、用rsync清空文件 
rsync -a --delete-before --progress --stats /root/blank.txt /root/nohup.out 
building file list ... 
1 file to consider 
blank.txt 
           0 100%    0.00kB/s    0:00:00 (xfer#1, to-check=0/1) 

Number of files: 1 
Number of files transferred: 1 
Total file size: 0 bytes 
Total transferred file size: 0 bytes 
Literal data: 0 bytes 
Matched data: 0 bytes 
File list size: 27 
File list generation time: 0.006 seconds 
File list transfer time: 0.000 seconds 
Total bytes sent: 73 
Total bytes received: 31 

sent 73 bytes  received 31 bytes  208.00 bytes/sec 
total size is 0  speedup is 0.00 


tips: 
当SRC和DEST文件性质不一致时将会报错 
当SRC和DEST性质都为文件【f】时,意思是清空文件内容而不是删除文件 
当SRC和DEST性质都为目录【d】时,意思是删除该目录下的所有文件,使其变为空目录 
最重要的是,它的处理速度相当快,处理几个G的文件也就是秒级的事 
最核心的内容是:rsync实际上用的就是替换原理 
posted @ 2012-07-12 22:26 张慧 阅读(7570) | 评论 (0)编辑 收藏

核心思想:加密和解密采用不同的密钥 

一般发送者和接收者拥有自己的公钥和密钥,公钥是公开的,密钥不公开。 

保密机制:A向B发送消息时,首先用B的公钥对消息进行加密,生成密文发送,B接收到密文后,用自己的密钥进行解密,进而得到消息原文。因为B公钥加密过的消息只有B的密钥才能解密,所以实现了保密功能。 
认证机制:A向B发送消息时,首先用自己的密钥加密,B接收到密文后用A的公钥解密,得到原文。因为只有A的公钥才可解开A密钥加密过的消息,所以可以确认解密后的原文必是来自A。 

若要同时实现保密和认证机制,需要对消息进行两次加密。  
posted @ 2012-07-12 22:26 张慧 阅读(1503) | 评论 (0)编辑 收藏


为什么要拆分样式文件?

更易于查找样式规则. 简化维护,方便管理. 还可以针对某一页面提供特定的样式.

为什么要添加桥接样式?

你可以随时添加或移除样式而不需要修改HTML 文档.

 

为什么要定义两种媒体类型?

NN4 不支持@import ,故识别不到桥接样式.

 

@import ‘header.css’;

@import ‘content.css’;

@import ‘footer.css’;

 

@imports 如何工作?

它将所有CSS 规则从一个文件导入到另外一个文件.@import 不能被老的

浏览器所识别.

 

 

对于 大型站点 来说,这是一个理想的概念.

 

 

Hack-free CSS

处理诸如IE 这样烦人的浏览器 的兼容性是我们最头疼的事儿之一.

很多朋友使用CSS Hack 来解决这些问题.

问题是当IE版本进行升级更替,改进对CSS的支持后,之前使用的hacks将会无效 !

你是怎么解决这个问题 的呢?

“我们要求你在不使用CSS hacks 的情况下更新你的页面.假如你想针对IE或者避开IE,你可以使用条件注释.”

条件注释 如何工作?

步骤一、针对IE,创建一个心得样式文件

步骤二、在HTML文档的开头添加条件注释 代码

只有指定的IE浏览器版本识别这个心的样式,其它的浏览器将会彻底忽略 它.

平常的浏览器识别:(非IE浏览器,如火狐、Chrome等等)

 

特定IE 版本识别:

举个例子, 大多数浏览器会将补白加进容器的宽度里,但是IE5 不会. 这种情况下,IE5 显示的是一个比较小的容器.

 

main.css (被包含IE5在内的所有浏览器识别):

#container{ width: 600px; padding: 100px;}

 

ie5.css (只有IE5识别):

#container {width: 800px; }

 

 

为什么条件注释是一个好的解决方案呢?

1.  No hacks
特定的CSS 规则仅出现在新的样式表里.

2.  文件分离
针对特定版本的IE 定义的样式脱离了主样式表,可以在IE 浏览器升级更新对属性支持时轻松移除这些文件.

3.  针对性
可对不同版本的IE 浏览器有针对性的进行相关属性的定义。

posted @ 2012-07-12 22:25 张慧 阅读(1324) | 评论 (0)编辑 收藏

     摘要: 本人的重点是怎么构建一个简单有效可扩展的jQuery表单验证插件,这篇文章没有教你怎么用 validate plugin。我们的重点在学习一些jQuery,Javascript面向对象编程的知识。下面是一个完整的html页面代码,可以直接运行测试的。Code highlighting produced by Actipro CodeHighlighter (freeware)http://www....  阅读全文
posted @ 2012-07-12 22:24 张慧 阅读(2477) | 评论 (1)编辑 收藏

自己写了一个基于jquery的返回页面顶端的组件。 
(function($) { 
var g; 
$.backtop = function(options) { 
extend($.backtop.config, options); 
this.config = $.backtop.config; 
this.init(); 
g = this; 
}; 
$.backtop.config = { 
title : null,// 返回顶端文字说明 
df_color : "#77AA55"// 组件默认颜色 
}; 
$.backtop.prototype = { 
config : null, 
backtop : null,// 当前创建返回顶端对象 
init : function() { 
this._scrool(); 
}, 
_scrool : function() { 
window.onscroll = function() { 
g._create_ob($(window).scrollTop()); 
}; 
}, 
_create_ob : function(top) { 
if(top==0){ 
$("#back_top").remove(); 
return; 

$("#back_top").remove(); 
this.backtop = $("<div class='mouseover'><img src='ui/main/gotop.gif'></img></div>"); 
$(this.backtop).bind("click",function(){ 
g._moveTo(); 
}); 
$(this.backtop).bind("mouseover",function(){ 
$(g.backtop).removeClass(); 
$(g.backtop).addClass("mouse"); 
}); 
$(this.backtop).bind("mouseout",function(){ 
$(g.backtop).removeClass(); 
$(g.backtop).addClass("mouseover"); 
}); 
$(this.backtop).attr("id","back_top"); 
/*$(this.backtop).css("backgroundColor", this.config.df_color);*/ 
$(this.backtop).css("zIndex", 1000); 
$(this.backtop).css("position", "absolute"); 
$(this.backtop).css("cursor","pointer"); 
$(this.backtop).width(30); 
$(this.backtop).height(30); 
$(this.backtop).css("left",$("body").attr("clientWidth")-50); 
$(this.backtop).css("top", top+300); 
$("body").append(this.backtop); 
},// 创建返回顶端jquery对象 
_moveTo:function(){ 
$("#back_top").remove(); 
window.scroll(0,0); 

}; 
})(jQuery); 
var extend = function($cf, options) { 
for ( var a in options) { 
$cf[a] = options[a]; 

}; 
posted @ 2012-07-12 22:22 张慧 阅读(754) | 评论 (0)编辑 收藏

准备阶段:

Hibernate可用于各种类型的项目,要在项目中使用Hibernate,需要下载Hibernate的API.
通过http://www.hibernate.org/网址可以下载到Hibernate的API和一些帮助文档.

点击downloads —> release bundles即可下载

下载解压后,在lib -> required目录下可找到项目中需要的jar包(API).

官网上好像没有API的帮助文档,大家可以到这里下载:http://115.com/file/bensl2vy#hibernate api帮助文档.chm

 

开发阶段:

新建一个JAVA项目,目录结构如下:

将准备的jar包引入到项目中。

 

hibernate.cfg.xml:(Hibernate的配置文件,放在项目的src目录下):<?xml version='1.0' encoding='UTF-8'?>

 <!DOCTYPE hibernate-configuration PUBLIC
           "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
           "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"
>
 
     <!-- Generated by MyEclipse Hibernate Tools.                   -->
 <hibernate-configuration>
 
     <session-factory>
         <!-- 设置驱动类 -->
         <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
         <!-- 设置连接池默认个数 -->
         <property name="connection.pool_size">20</property>
         <!-- 设置JDBC URL -->
         <property name="connection.url">jdbc:mysql://localhost:3306/book</property>
         <!-- 设置数据库用户名 -->
         <property name="connection.username">username</property>
         <!-- 设置数据库用户密码 -->
         <property name="connection.password">passwrod</property>
         <!-- 设置SQL方言 -->
         <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
         <!-- 设置是否显示SQL语句 -->
         <property name="show_sql">true</property>
         <!-- 设置格式化SQL语句 -->
         <property name="format_sql">true</property>
         <property name="current_session_context_class">thread</property>
 
         <mapping resource="com/sunflower/bean/Person.hbm.xml" />
     </session-factory>
 
 </hibernate-configuration>

这里配置的是MySQL数据库的驱动和连接,在开始的时候忘了加26行,结果调试的时候出错,得不到session,关于这个标签的使用,请参考如下文章:http://blog.sina.com.cn/s/blog_5ecfe46a0100e467.html 第28行是对象关系映射文件的配置.

Person.java:(人的实体类,对应到关系数据库中的blog表)package com.sunflower.bean;

 
 import java.io.Serializable;
 
 /**
  * 博客用户的实体类
  * 
  * 
@author hanyuan
  * @time 2012-7-8 下午11:53:23
  
*/
 public class Person implements Serializable {
     private Integer id;
     private String username;
     private String password;
     private String caption;
     private String content;
 
     public Integer getId() {
         return id;
     }
 
     public void setId(Integer id) {
         this.id = id;
     }
 
     public String getUsername() {
         return username;
     }
 
     public void setUsername(String username) {
         this.username = username;
     }
 
     public String getPassword() {
         return password;
     }
 
     public void setPassword(String password) {
         this.password = password;
     }
 
     public String getCaption() {
         return caption;
     }
 
     public void setCaption(String caption) {
         this.caption = caption;
     }
 
     public String getContent() {
         return content;
     }
 
     public void setContent(String content) {
         this.content = content;
     }
 
 }

 第12~16行中的属性对应到数据库中的blog表的字段,其中id是主键索引.

Person.hbm.xml:(对象关系映射配置文件)<?xml version="1.0"?>

 <!DOCTYPE hibernate-mapping PUBLIC 
     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
 
 <hibernate-mapping>
     <!-- 设置实体类与数据库中表的对应关系 -->
     <class name="com.sunflower.bean.Person" table="blog">
 
         <id name="id" type="java.lang.Integer">
             <column name="id"></column>
             <!-- 将逐渐设置为自增 -->
             <generator class="increment"></generator>
         </id>
 
         <property name="username" type="java.lang.String" not-null="true">
             <column name="username"></column>
         </property>
 
         <property name="password" type="java.lang.String">
             <column name="password"></column>
         </property>
 
         <property name="caption" type="java.lang.String">
             <column name="caption"></column>
         </property>
 
         <property name="content" type="java.lang.String">
             <column name="content"></column>
         </property>
 
     </class>
 </hibernate-mapping>

<class name="com.sunflower.bean.Person" table="blog">表示对象对应的表,<id>字段是必须要有的,表示主键。开始的时候没有加第13行,结果调试出错,需要加上<generator>标签,这里设置为自增类型.关于<generator>标签的使用,参考下列文章:http://sarin.iteye.com/blog/605712

这个配置文件的是以hbm.xml结尾的,名字建议命名为对象名.hbm.xml,并且和实体类对象放在同一个包下,这样比较好找.

Test.java:(调用Hibernate API 插入数据)package com.sunflower.main;

 
 import org.hibernate.Session;
 import org.hibernate.SessionFactory;
 import org.hibernate.Transaction;
 import org.hibernate.cfg.Configuration;
 
 import com.sunflower.bean.Person;
 
 public class Test {
     @SuppressWarnings("deprecation")
     public static void main(String[] args) {
         // 读取Hibernate的配置信息
         Configuration config = new Configuration();
         config.configure();
 
         // 读取配置里面的SessionFactory
         SessionFactory sessionFactory = config.buildSessionFactory();
         Session session = sessionFactory.getCurrentSession();
         Transaction transaction = session.beginTransaction();
 
         Person person = new Person();
         person.setUsername("邓光桥");
         person.setPassword("123");
         person.setCaption("Hibernate");
         person.setContent("Hibernate 入门实例");
 
         // 提交事务
         session.save(person);
         transaction.commit();
         sessionFactory.close();
     }
 }

 

 

posted @ 2012-07-10 00:46 张慧 阅读(1107) | 评论 (0)编辑 收藏

在Java Web开发中,经常需要导出大量的数据到Excel,使用POI、JXL直接生成Excel,很容易就造成内存溢出了。

  1、有一种方式,就是把数据写成csv格式文件。

  1)csv文件可以直接用Excel打开。

  2)写csv文件的效率和写txt文件的效率一样高。

  3)同样的数据内容,生成的csv文件的大小远远小于生成的Excel文件。

  从以上优点就可以看出生成csv文件消耗的内存绝对小于生成Excel文件。

  2、按一定的格式去生成csv文件,在Excel中打开的时候就是完整的行和列格式。

  例如:在Excel中的格式:

                                   

  那么,在csv文件中格式就必须为:

                                  

  就是说,列和列之间,需要用英文输入法状态下的逗号","间隔:风云第一刀,古龙。

  3、在Struts2中导出数据到Excel,一个简单的例子。

  CsvAction,生成csv文件,并且将生成的csv文件完整路径传递到下载Action。

package cn.luxh.struts2.action;

import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import cn.luxh.struts2.entity.Novel;

import com.opensymphony.xwork2.ActionSupport;


/**
 * 导出数据到csv文件
 * 
@author Luxh
 
*/
public class CsvAction extends ActionSupport {

    private static final long serialVersionUID = -2862629695443964658L;
    
    /**
     * 包含完整路径的文件名
     * 传递给下载Action进行下载
     
*/
    private String fileName;
    
    
    /**
     * 导出数据
     
*/
    public String exportData2CSV() {
        List<Novel> novels = getNovels();
        fileName = "D:/novels.csv";
        writeData2CSV(novels,fileName);
        return SUCCESS;
        
    }
    
    /**
     * 构造一些数据
     * 实际上可能是从数据库中把大量的数据查出来
     
*/
    private List<Novel> getNovels() {
        List<Novel> novels = new ArrayList<Novel>();
        
        Novel novel1 = new Novel("风云第一刀","古龙",new Date());
        Novel novel2 = new Novel("书剑恩仇录","金庸",new Date());
        Novel novel3 = new Novel("陆小凤传奇","古龙",new Date());
        Novel novel4 = new Novel("鹿鼎记","金庸",new Date());
        
        novels.add(novel1);
        novels.add(novel2);
        novels.add(novel3);
        novels.add(novel4);
        
        return novels;
    }
    
    /**
     * 把数据按一定的格式写到csv文件中
     * 
@param novels     数据集合
     * 
@param fileName  csv文件完整路径
     
*/
    public void writeData2CSV(List<Novel> novels,String fileName) {
        FileWriter fw = null;
        try {
            fw = new FileWriter(fileName);
            //输出标题头
            
//注意列之间用","间隔,写完一行需要回车换行"\r\n"
            String title = "序号,小说名称,作者,出版日期\r\n";
            fw.write(title);
            
            String content = null;
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            for(int i=0;i<novels.size();i++) {
                Novel novel = novels.get(i);
                //注意列之间用","间隔,写完一行需要回车换行"\r\n"
                content =(i+1)+","+novel.getName()+","+novel.getAuthor()+","+sdf.format(novel.getPublishDate())+"\r\n";
                fw.write(content);
            }
        }catch(Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            try {
                if(fw!=null) {
                    fw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

复制代码

  配置文件:

<!--将csv文件路径传递到公共的下载Action进行下载  -->
         <action name="exportData2CSV" class="cn.luxh.struts2.action.CsvAction" method="exportData2CSV">
            <result type="redirectAction">
                <param name="actionName">download</param>
                <param name="nameSpace">/download</param>
                <!--附件的完整路径 ,传递给下载Action -->
                <param name="fileName">${fileName}</param>
            </result>
        </action>

  提供下载功能的Action参考http://www.cnblogs.com/luxh/archive/2012/07/01/2571778.html

  4、看一下同样的数据内容,csv文件和Excel文件的大小对比: 

                                        

 

 

 

 

 

 

 

  

posted @ 2012-07-10 00:43 张慧 阅读(7370) | 评论 (1)编辑 收藏

对于Servlet的生命周期,主要围绕着init()、service()和destroy()三个回调方法展开的。什么是回调方法?通俗的说就是这三个方法定义完后由web容器负责在特定时间(需要的时候)调用。

Servlet容器,如Tomcat一般会在用户第一次请求Servlet的时候实例化该对象。另一种情况是在服务器启动时立即加载并实例化,但这需要在web.xml文件中对Servlet进行load-on-startup的配置。

当第一个用户请求到来时,服务器根据部署描述符找到所访问的Servlet类,并查找当前容器,发现没有此类的实例,说明是第一次访问此Servlet,所以容器开始加载Servlet,并实例化此对象,实例化之后会立即调用init()方法,而且init()方法由始至终只被调用一次,所以比较适合进行对象的初始化工作,比如读取配置文件,初始化属性等。当调用完init()方法后,Servlet实例处于ready状态,这时开始调用其service()方法,并等待着下一次请求的到来。

service()方法是服务方法,只要再有请求到来,服务器都会产生一个新的线程,调用service()方法,进行相关的服务。service()方法会检查HTTP请求的类型(GET、POST等),来相应的调用doGet()、doPost()等。GET请求起因于正常URL请求,或没有指定Method的HTML表单;Post请求起因于将Method定为Post的HTML表单。从图中可见,service()方法可以被调用多次,因为之后用户每一次访问该Servlet,都会触发服务器调用service()方法。

如果实例长时间未被访问,或者web服务器关闭,则容器会负责调用destroy()方法,该方法可以将一些资源释放,destroy()方法也是只被调用一次,之后Servlet实例将被JVM回收空间。这样通过init()-->service()-->destroy(),完成了Servlet的一个生命周期。

上图是UML中的状态图,形象的描述了一个对象在不同事件触发时,其内部状态的变更过程。实心的圆圈代表初始状态,代表Servlet刚刚被实例化:中间写Ready的椭圆形代表就绪状态,最下面的圆圈代表结束,这时对象已被JVM的GC回收。图中的另外一个分支,代表在执行init()操作时抛出了异常,造成无法调用service()方法,生命周期提前终止。

posted @ 2012-07-08 23:33 张慧 阅读(1415) | 评论 (0)编辑 收藏

仅列出标题
共5页: 上一页 1 2 3 4 5 下一页