Coder 爱翻译 How Tomcat Works 第九章 第一部分

[size=x-large]Chapter 9: Session Management[/size]

Catalina通过一个叫做manager的组件来支持session管理。manager是由org.apache.catalina.Manager接口表示。一个manager总是和一个context相关联的。manager负责创建、更新、销毁(使一个session失效)session对象和返回一个有效的session对象给请求组件。

servlet可以通过调用javax.servlet.http.HttpServletRequest接口的getSession方法来获取一个session对象。在默认连接器中org.apache.catalina.connector.HttpRequestBase类实现了HttpServletRequest接口。

public HttpSession getSession() {
return (getSession(true));
}
public HttpSession getSession(boolean create) {
...
return doGetSession(create);
}
private HttpSession doGetSession(boolean create) {
// There cannot be a session if no context has been assigned yet
if (context == null)
return (null);
// Return the current session if it exists and is valid
if ((session != null) && !session.isValid())
session = null;
if (session != null)
return (session.getSession());
// Return the requested session if it exists and is valid
Manager manager = null;
if (context != null)
manager = context.getManager();
if (manager == null)
return (null); // Sessions are not supported
if (requestedSessionId != null) {
try {
session = manager.findSession(requestedSessionId);
}
catch (IOException e) {
session = null;
}
if ((session != null) && !session.isValid())
session = null;
if (session != null) {
return (session.getSession());
}
}
// Create a new session if requested and the response is not
// committed
if (!create)
return (null);
...
session = manager.createSession();
if (session != null)
return (session.getSession());
else
return (null);
}

默认情况下,manager把它的session对象存储在内存中。但是,Tomcat也可以允许manager把它的session对象持久化到存储文件或数据库中。Catalina提供org.apache.catalina.session包,这个包中包含了session对象相关的类型和session管理。

这章分三部分:"Sessions", "Managers"和"Stores"。

[size=large]Sessions[/size]

在servlet编程中,一个session对象由javax.servlet.http.HttpSession接口表示。这个接口的实现是org.apache.catalina.session包下的StandardSession类。但是,出于安全考虑,manager不会传递一个StandardSession实例给一个servlet。它使用在org.apache.catalina.session包下面的facade类:StandardSessionFacade。在内部,管理器与另外一个facade:org.apache.catalina.Session一起工作。类图:

[img]http://dl.iteye.com/upload/attachment/369193/8350bf2f-2ea4-36be-9cfc-a6430928e97e.jpg[/img]

[size=large]The Session Interface[/size]

Session接口作为一个Catalina内部的façade。Session接口的标准实现是StandardSession。
StandardSession也实现了javax.servlet.http.HttpSession接口。

Listing 9.1: The Session interface

package org.apache.catalina;
import java.io.IOException;
import java.security.Principal;
import java.util.Iterator;
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;

public interface Session {
public static final String SESSION_CREATED_EVENT = "createSession";
public static final String SESSION_DESTROYED_EVENT = "destroySession";
public String getAuthType();
public void setAuthType(String authType);
public long getCreationTime();
public void setCreationTime(long time);
public String getId();
public void setId(String id);
public String getInfo();
public long getLastAccessedTime();
public Manager getManager();
public void setManager(Manager manager);
public int getMaxInactiveInterval();
public void setMaxInactiveInterval(int interval);
public void setNew(boolean isNew);
public Principal getPrincipal();
public void setPrincipal(Principal principal);
public HttpSession getSession();
public void setValid(boolean isValid);
public boolean isValid();
public void access();
public void addSessionListener(SessionListener listener);
public void expire();
public Object getNote(String name);
public Iterator getNoteNames();
public void recycle();
public void removeNote(String name);
public void removeSessionListener(SessionListener listener);
public void setNote(String name, Object value);
}

Session对象总是被包含在一个manager里面的。setManager和getManager方法用来把一个Session实例和一个manager相关联起来。一个Session实例也有一个唯一的标识符。可以使用setId和getId方法来访问Session的标识符。manager调用getLastAccessedTime方法来确定一个Session对象是否合法有效。manager调用setValid和reset方法来设置和重新设置一个session对象为合法有效。每次一个Session实例被访问,它的access方法被调用来修改它的最后被访问时间(last accessed time)。最后,manager可以调用它的expire方法把一个session设为超时。getSession方法返回一个被这个facade包装后的HttpSession对象。

[size=large]The StandardSession Class[/size]

StandardSession类是Session接口的标准实现。它除了实现了javax.servlet.http.HttpSession 和org.apache.catalina.Session,还实现了java.lang.Serializable让Session对象可以被序列化。

这个类的构造函数接收一个Manager实例,使一个Session对象总是有一个对应的Manager。

public StandardSession(Manager manager);

下面是一些重要的private变量。注意transient关键字修饰的变量不会被序列化。

// session attributes
private HashMap attributes = new HashMap();
// the authentication type used to authenticate our cached Principal,
private transient String authType = null;
private long creationTime = 0L;
private transient boolean expiring = false;
private transient StandardSessionFacade facade = null;
private String id = null;
private long lastAccessedTime = creationTime;
// The session event listeners for this Session.
private transient ArrayList listeners = new ArrayList();
private Manager manager = null;
private int maxInactiveInterval = -1;
// Flag indicating whether this session is new or not.
private boolean isNew = false;
private boolean isValid = false;
private long thisAccessedTime = creationTime;

注意在Tomcat 5中,上面的变量是protected修饰的。每个变量都有一对get/set方法。

getSession方法通过传递这个实例来创建一个StandardSessionFacade对象。

public HttpSession getSession() {
if (facade == null)
facade = new StandardSessionFacade(this);
return (facade);
}

一个Session对象在一段时间内(超过了Manager里的maxInactiveInterval变量的值)没有被访问。它将被设置为超时过期。让一个Session对象超时过期,调用Session接口的expire方法。

Listing 9.2: The expire method

public void expire(boolean notify) {
// Mark this session as "being expired" if needed
if (expiring)
return;
expiring = true;
setValid(false);
// Remove this session from our manager's active sessions
if (manager != null)
manager.remove(this);
// Unbind any objects associated with this session
String keys [] = keys();
for (int i = 0; i < keys.length; i++)
removeAttribute(keys[i], notify);
// Notify interested session event listeners
if (notify) {
fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null);
}
// Notify interested application event listeners
// FIXME - Assumes we call listeners in reverse order
Context context = (Context) manager.getContainer();
Object listeners[] = context.getApplicationListeners();
if (notify && (listeners != null)) {
HttpSessionEvent event = new HttpSessionEvent(getSession());
for (int i = 0; i < listeners.length; i++) {
int j = (listeners.length - 1) - i;
if (!(listeners[j] instanceof HttpSessionListener))
continue;
HttpSessionListener listener =
(HttpSessionListener) listeners[j];
try {
fireContainerEvent(context, "beforeSessionDestroyed",
listener);
listener.sessionDestroyed(event);
fireContainerEvent(context, "afterSessionDestroyed", listener);
}
catch (Throwable t) {
try {
fireContainerEvent(context, "afterSessionDestroyed",
listener);
}
catch (Exception e) {
;
}
// FIXME - should we do anything besides log these?
log(sm.getString("standardSession.sessionEvent"), t);
}
}
}
// We have completed expire of this session
expiring = false;
if ((manager != null) && (manager instanceof ManagerBase)) {
recycle();
}
}

超时处理包括了设置一个叫做expiring的内部变量、从Manager中移除Session实例和触发一些事件。

[size=large]The StandardSessionFacade Class[/size]

要把一个Session对象传递给servlet,Catalina要实例化StandardSession类,填充属性,然后把它传递给servlet。它传递给一个StandardSessionFacade实例,只提供了在javax.servlet.http.HttpSession的方法实现。这样,servlet程序员就不能把HttpSession对象向下转型成StandardSessionFacade类,访问它的public方法。

[size=large]Manager[/size]

manager管理是session对象的。例如:它创建session对象和让session对象失效。manager是由org.apache.catalina.Manager接口表示的。在Catalina中,org.apache.catalina.session包中包含了ManagerBase类,它提供了通用的功能的实现。ManagerBase有两个直接的子类:StandardManager和PersistentManagerBase。

当应用程序运行是时,StandardManager把session对象存储在内存中。当应用程序停止了,它把就当前在内存中所有的session对象存储到一个文件中去。当再次启动应用程序时,在从文件中把session对象加载进内存。

PersistentManagerBase类是manager组件的基类,它把session对象存储到辅助存储器里面。它有两个子类:PersistentManager和DistributedManager(DistributedManager只在Tomcat 4中),类图:

[img]http://dl.iteye.com/upload/attachment/369195/2cfb8602-8c98-31f6-8840-88c9b5581868.jpg[/img]

[size=large]The Manager Interface[/size]

Manager接口代表了一个Manager组件:

Listing 9.3: The Manager interface

package org.apache.catalina;
import java.beans.PropertyChangeListener;
import java.io.IOException;

public interface Manager {
public Container getContainer();
public void setContainer(Container container);
public DefaultContext getDefaultContext();
public void setDefaultContext(DefaultContext defaultContext);
public boolean getDistributable();
public void setDistributable(boolean distributable);
public String getInfo();
public int getMaxInactiveInterval();
public void setMaxInactiveInterval(int interval);
public void add(Session session);
public void addPropertyChangeListener(PropertyChangeListener listener);
public Session createSession();
public Session findSession(String id) throws IOException;
public Session[] findSessions();
public void load() throws ClassNotFoundException, IOException;
public void remove(Session session);
public void removePropertyChangeListener(PropertyChangeListener listener);
public void unload() throws IOException;
}

首先,Manager接口用getContainer 和setContainer方法把Manager的实现和一个context相关联起来。createSession方法创建一个Session对象。add方法把一个Session实例添加到session池中。remove方法把Session对象从session池中移除。getMaxInactiveInterval和setMaxInactiveInterval方法返回和指定Manager将要等待用户拥有一个与该用户相关联的session的指定秒数。超过这个时间秒数,Manager将销毁这个session,即该session失效了。

最后,在Manager实现里支持一种持久化机制。load和unload方法支持把session持久化存储到辅助存储器。通过这个Manager实现,unload方法把当前活动的session存储到指定的存储地方。load方法把已被持久化的session重新加载到内存中去。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值