`
dicmo
  • 浏览: 66898 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

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

    博客分类:
  • j2ee
阅读更多
The ManagerBase Class

ManagerBase类是一个从所有Manager抽取出来到的抽象类。这个类给它的子类提供了常见的方法。ManagerBase有createSession方法来创建一个Session对象。每一个session都有一个唯一的标识符,ManagerBase类的protected方法generateSessionId返回一个唯一的标识符。

注意:一个活动状态下的session是一个session仍然是valid对象,而不是expired的。这些活动的session被存储在一个叫做sessions的HashMap中的:

protected HashMap sessions = new HashMap();


add方法把一个Session对象添加到sessions中:
  public void add(Session session) { 
     synchronized (sessions) {
       sessions.put(session.getId(), session); 
     } 
   }

remove方法从sessions中移除一个Session对象。
   public void remove(Session session) { 
     synchronized (sessions) { 
       sessions.remove(session.getId()); 
     } 
   }

没有参数的findSession方法返回在sessions中的活动的所有session对象的实例数组。findSession方法接收一个session标识符作为一个参数返回给出的标识符的Session实例。
   public Session[] findSessions() { 
     Session results[] = null; 
     synchronized (sessions) { 
       results = new Session[sessions.size()]; 
       results = (Session[]) sessions.values().toArray(results); 
     } 
     return (results); 
   } 
   public Session findSession(String id) throws IOException { 
     if (id == null) 
       return (null); 
     synchronized (sessions) { 
 
     Session session = (Session) sessions.get(id); 
     return (session); 
   } 
}

StandardManager

StandardManager类是Manager的标准实现,它用来把Session对象存储到内存中。它实现了Lifecycle接口,所以它可以被启动和停止。stop方法的实现调用unload方法,为每一个context把合法的Session实例以串行化方式存入一个叫做SESSION.ser的文件中。SESSION.ser文件可以在CATALINA_HOME目录下找到。当StandardManager再次启动的时候,使用load方法把这些Session对象被重新加载到内存中去。

一个manager也负责销毁那些不再合法的session对象。Tomcat 4中的StandardManager,它拥有一个指定的线程来实现。所以,StandardManager它实现了java.lang.Runnable接口。
public void run() { 
   // Loop until the termination semaphore is set 
   while (!threadDone) { 
     threadSleep(); 
     processExpires(); 
   } 
}

ThreadSleep方法让这个线程处于睡眠等待checkInterval变量指定的秒数。默认是60秒。你可以调用setCheckInterval方法来设置这个变量值。

ProcessExpire方法循环地把所有的被StandardManager管理的Session对象中的每一个Session对象的lastAccessedTime值和当前的时间值比较。如果这两个时间的差值超过了maxInactiveInterval值,这个方法就调用Session接口的expire方法把这个Session实例设置为超时。maxInactiveInterval值可以通过调用setMaxInactiveInterval方法来改变。StandardManager下默认的maxInactiveInterval变量值是60。不要简单地认为这个值是在Tomcat部署时用到的值,setContainer方法org.apache.catalina.core.ContainerBase 类的setManager方法被调用,重写这个值:
setMaxInactiveInterval(((Context) 
this.container).getSessionTimeout()*60 ); 

注意:在org.apache.catalina.core.StandardContext类的sessionTimeOut变量的默认值是30。

在Tomcat 5中,StandardManager类没有实现java.lang.Runnable.。在Tomcat 5中的StandardManager中的processExpires方法被backgroundprocess方法直接调用。
public void backgroundProcess() { 
   processExpires(); 
}

在StandardManager中的backgroundProcess方法通过org.apache.catalina.core.StandardContext实例的backgroundProcess方法调用,这个容器和这个manager相关联。每隔一段时间StandardContext调用它的backgroundProcess方法。

PersistentManagerBase

PersistentManagerBase类是所有持久化管理器的父类。StandardManager和一个持久化manager主要的不同是:后面有一个store。一个store代表一个辅助存储器用来管理session对象。PersistentManagerBase类使用一个private的叫做store的对象引用。
private Store store = null;

在一个持久化manager中,session对象可以被备份和被清理。当一个session对象被备份,这个session对象被复制到一个store中,原来的session对象还在内存中。如果服务器down掉了,活动的session对象可以在store中重新获取。当一个session对象它被因为活动的session对象的数量超过了指定的数量或者session对象已经空闲了很长一段时间,清理的目的是为了节省内存空间。

在Tomcat 4中PersistentManagerBase实现了java.lang.Runnable来持有一个单独的线程来定期备份和清理活动的session。
public void run() { 
   // Loop until the termination semaphore is set 
   while (!threadDone) { 
     threadSleep(); 
     processExpires(); 
     processPersistenceChecks(); 
   } 
}

processExpired方法,就像在StandardManager中的一样,是检查session对象是否超时。processPersistenceChecks方法调用了其他三个方法:
public void processPersistenceChecks() { 
   processMaxIdleSwaps(); 
   processMaxActiveSwaps(); 
   processMaxIdleBackups(); 
}

在Tomcat 5中,PersistentManagerBase没有实现java.lang.Runnable接口。备份和清理工作是由backgroundProcess manager处理的。它由与它相关联的StandardContext实例定期地调用。
Swap Out

PersistentManagerBase类采用一系列规则来清理session对象。一个session对象在超过最大活动session的maxActiveSessions变量值或者session已经空闲了一段很长时间时被清理。

这种有太多的session对象的情况下,一个PersistentManagerBase实例简单地清理任何一个session知道活动session对象的值等于maxActiveSessions。

在一个session对象空闲了很长一段时间这种情况,PersistentManagerBase类使用两个变量来决定是否这个session对象被清理:minIdleSwap和maxIdleSwap。一个session对象在它的lastAccessedTime超过minIdleSwap和maxIdleSwap时,会被清理掉。为了保护被清理掉,你可以设置maxIdleSwap为负数。

因为一个活动的session可以被清理,它可以被重新加载到内存和存储到一个store中。findSession (String id)方法首先在内存中寻找Session实例,如果没有,就在store中搜索。下面是PersistentManagerBase类方法的实现。
public Session findSession(String id) throws IOException { 
   Session session = super.findSession(id); 
   if (session != null) 
     return (session); 
   // not found in memory, see if the Session is in the Store 
   session = swapIn(id); // swapIn returns an active session in the Store 
   return (session); 
}

Back-up

不是所有活动的session对象会被备份。一个PersistentManagerBase实例只会备份空闲时间比maxIdleBackup的值大的session对象。processMaxIdleBackups方法负责备份session对象。

PersistentManager

PersistentManager继承了PersistentManagerBase:
Listing 9.5: The PersistentManager class   
 
package org.apache.catalina.session; 
public final class PersistentManager extends PersistentManagerBase { 
   // The descriptive information about this implementation. 
   private static final String info = "PersistentManager/1.0"; 
   // The descriptive name of this Manager implementation (for logging). 
   protected static String name = "PersistentManager"; 
   public String getInfo() { 
     return (this.info); 
   } 
   public String getName() { 
     return (name); 
   } 
} 


DistributedManager

Tomcat 4中提供了DistrubutedManager类。是PersistentManagerBase的一个子类,DistributedManager被用在一个集群环境,有两个或更多节点。一个节点代表一个Tomcat的部署。在一个集群中的节点可以存在于不同的计算机中或在同一台计算机中。在集群环境中,
每一个节点必须使用一个DistributedManager实例作为它的Manager来支持session的复制。这个是DistributedManager的主要工作。

为了达到复制的目的,DistributedManager发送通知给其它节点。不管说么么时候一个session对象被创建或销毁。此外,一个节点必须能够接收到其它节点的通知。一个HTTP请求可以在集群中的任何一个节点得到服务。

发送和接收其它节点的DistributedManager实例的通知,Catalina提供org.apache.catalina.cluster包的类。ClusterSender类用来发送通知给其它节点,ClusterReceiver类用来接收通知。

DistrbutedManager的createSession方法必须创建一个session对象存储到当前实例,使用ClusterSender实例发送通知给其它节点。
Listing 9.6: The createSession method   
 
public Session createSession() { 
   Session session = super.createSession(); 
   ObjectOutputStream oos = null; 
   ByteArrayOutputStream bos = null; 
   ByteArraylnputStream bis = null; 
 
   try { 
     bos = new ByteArrayOutputStream(); 
     oos = new ObjectOutputStream(new BufferedOutputStream(bos)); 
 
     ((StandardSession)session).writeObjectData(oos); 
     oos.close(); 
     byte[] obs = bos.toByteArray(); 
     clusterSender.send(obs); 
     if(debug > 0) 
       log("Replicating Session: "+session.getId()); 
   }
   catch (IOException e) { 
     log("An error occurred when replicating Session: " + session.getId()); 
   } 
 
   retun (session); 
} 

首先createSession方法调用父类的createSession方法来创建一个session对象。它发送session对象作为一个字节数组。

DistribubedManager类也实现了java.lang.Runnable,它有一个独立的线程把session对象超时,接收其它节点来的通知。
public void run() { 
   // Loop until the termination semaphore is set 
   while (!threadDone) { 
     threadSleep(); 
     processClusterReceiver(); 
     processExpires(); 
     processPersistenceChecks(); 
   } 
}


Stores

一个store由一个org.apache.catalina.Store接口表示,它是一个提供永久存储session的组件。
Listing 9.7: The Store interface   
 
package org.apache.catalina; 
import java.beans.PropertyChangeListener; 
import java.io.IOException; 
 
public interface Store { 
   public String getInfo(); 
   public Manager getManager(); 
   public void setManager(Manager manager); 
   public int getSize() throws IOException; 
   public void addPropertyChangeListener(PropertyChangeListener  listener); 
   public String[] keys() throws IOException; 
   public Session load(String id) throws ClassNotFoundException, IOException; 
   public void remove(String id) throws IOException; 
   public void clear() throws IOException; 
   pubiic void removePropertyChangeListener(PropertyChangeListener listener); 
   public void save(Session session) throws IOException; 
} 

Store接口中两个最重要的方法:save和load。save方法存储指定的session对象要一个永久存储器。load方法用给出的指定标识符从存储器中加载session对象。keys方法返回一个字符串数组,这个数组包含所有的session标识符。

类图:


StoreBase

StoreBase类是一个抽象类,它为它的两个子类提供了常用的方法:FileStore和JDBCStore。StoreBase类没有实现Store接口的save和load方法,因为这个方法的实现依赖存储类型来存储session。

Tomcat 4中的StoreBase类持有一个单独的线程来定期地检查超时的session和移除活动session集合中超时的session。
public void run() { 
   // Loop until the termination semaphore is set 
   while (!threadDone) { 
     threadSleep(); 
     processExpires(); 
   } 
}

processExpires方法获取所有的活动的session和检查每一个lastAccessedTime的值,移除session对象空闲了很长时间。
Listing 9.7: the processExpires method   
 
protected void processExpires() { 
   long timeNow = System.currentTimeMillis(); 
   String[] keys = null; 
   if (!started) 
     return; 
   try { 
     keys = keys(); 
   } 
   catch (IOException e) { 
     log (e.toString()); 
     e.printStackTrace(); 
     return; 
   }
   for (int i = 0; i < keys.length; i++) { 
     try { 
       StandardSession session = (StandardSession) load(keys[i]); 
       if (!session.isValid()) 
         continue;
       int maxInactiveInterval = session.getMaxInactiveInterval(); 
       if (maxInactiveInterval < 0) 
         continue; 
       int timeIdle = // Truncate, do not round up 
         (int) ((timeNow - session.getLastAccessedTime()) / 1000L); 
       if (timeIdle >= maxInactiveInterval) { 
         if ( ( (PersistentManagerBase) manager).isLoaded( keys[i] )) { 
           // recycle old backup session 
           session.recycle(); 
         } 
         else { 
           // expire swapped out session 
           session.expire(); 
         } 
         remove(session.getId()); 
       } 
     }
     catch (IOException e) { 
       log (e.toString()); 
       e.printStackTrace(); 
 
     } 
     catch (ClassNotFoundException e) { 
       log (e.toString()); 
       e.printStackTrace(); 
     } 
   } 
} 


在Tomcat 5中没有特别的线程来调用processExpires方法。这个方法定期地被与它相关联的PersistentManagerBase实例的backgroundProcess方法调用。

FileStore

FileStore方法把session对象存储到文件中。文件是以session对象的标识符为名字,以.session为后缀名。这个文件位于临时的工作目录中。你可以调用Filestore类的setDirectory方法来更改临时目录。

java.io.ObjectOutputStream类是在sava方法中用来串行化session对象。存储在一个Session实例的所有对象都必须实现java.lang.Serializable。反序列化一个session对象是在load方法,java.io.ObjectInputStream类调用。

JDBCStore

JDBCStore类存储session对象到一个数据库中,是通过JDBC来传输的,使用JDBCStore你需要设置驱动名字和链接URL,通过调用各自的setDriverName和setConnectionURL方法。

The Application

本章的应用程序,使用默认连接器,它有一个context作为它的主容器。
这个应用程序有两个包:ex09.pyrmont.core和ex09.pyrmont.startup,在Catalina中使用不同的类。在ex09.pyrmont.core包下有四个类:SimpleContextConfig, SimplePipeline, SimpleWrapper和SimpleWrapperValve.
ex09.pyrmont.startup包下有一个类:Bootstrap。


The Bootstrap Class

main方法开始是设置catalina.base系统属性和初始化默认连接器。
System.setProperty("catalina.base", 
System.getProperty("user.dir")); 
Connector connector = new HttpConnector();

SessionServlet,它创建一个wrapper,命名为: wrapper1.
Wrapper wrapper1 = new SimpleWrapper(); 
wrapper1.setName("Session"); 
wrapper1.setServletclass("SessionServlet");

然后创建一个StandardContext对象,设置它的路径和docBase属性,添加wrapper到context。
Context context = new StandardContext(); 
context.setPath("/myApp"); 
context.setDocBase("myApp"); 
context.addChild(wrapper1); 

接下来start方法添加一个servlet映射。这个映射和第八章的不同。/Session,我们使用myApp/Session作为。
context.addServletMapping("/myApp/Session", "Session")

请求的url:http://localhost:8080/myApp/Session.

context需要一个监听器和一个加载器。
LifecycleListener listener = new SimpleContextConfig(); 
((Lifecycle) context).addLifecycleListener(listener);
// here is our loader 
Loader loader = new WebappLoader(); 
// associate the loader with the Context 
context.setLoader(loader); 
connector.setContainer (context);

现在我们使用一个StandardManager实例,并把它传递给context。
Manager manager = new StandardManager(); 
context.setManager(manager);


最后,我们初始化和启动链接诶器和启动context。
connector.initialize(); 
((Lifecycle) connector).start(); 
((Lifecycle) context).start();


The SimpleWrapperValve Class

Listing 9.8: The invoke method of the SimpleWrapperValve class   
 
public void invoke(Request request, Response response, 
   ValveContext valveContext) throws IOException, ServletException { 
 
   SimpleWrapper wrapper = (SimpleWrapper) getContainer(); 
   ServletRequest sreq = request.getRequest(); 
   ServletResponse sres = response.getResponse(); 
   Servlet servlet = null; 
   HttpServletRequest hreq = null; 
   if (sreq instanceof HttpServletRequest) 
     hreq = (HttpServletRequest) sreq; 
   HttpServletResponse hres = null; 
   if (sres instanceof HttpServletResponse) 
     hres = (HttpServletResponse) sres;
   // pass the Context to the Request object so that 
   // the Request object can call the Manager 
   Context context = (context) wrapper.getparent(); 
   request.setcontext(context);

   // Allocate a servlet instance to process this request 
   try { 
     servlet = wrapper.allocate(); 
     if (hres!=null && hreq!=null) { 
       servlet.service(hreq, hres); 
     } 
     else { 
       servlet.service(sreq, sres); 
     } 
   } 
   catch (ServletException e) { 
   } 
} 


你要访问wrapper,你可以调用Container接口的getParent方法获取这个context。注意:wrapper被添加到context中了。一旦你有一个context,你可以调用Request接口的setContext方法。

org.apache.catalina.connector.HttpRequestBase类的private的doGetSession方法调用Context接口的getManager方法来获取manager。
// Return the requested session if it exists and is valid 
Manager manager = null; 
if (context != null) 
manager = context.getManager();

当有了一个manager,就可以直接获取一个session对象或创建一个新的session对象。

总结:本章讨论manager,它是在session管理里面的一个管理session的组件。组件类型和一个manager怎么持久化session对象到store中。
  • 大小: 39.7 KB
1
7
分享到:
评论

相关推荐

    How tomcat works 中文版

    � jsp / servlet 开发人员,想了解 tomcat 内部机制的 coder ; � 想加入 tomcat 开发团队的 coder ; � web 开发人员,但对软件开发很有兴趣的 coder ; � 想要对 tomcat 进行定制的 coder 。 在阅读之前,希望...

    tomcat原理解析书(how-tomcat-works)中文版

    适合读者 1.jsp/servlet 开发人员,想了解 tomcat 内部机制的 coder;...2.想加入 tomcat 开发团队的 coder; 3.web 开发人员,但对软件开发很有兴趣的 coder; 4.想要对 tomcat 进行定制的 coder。

    Bad Programming Practices 101 Become a Better Coder by Learning How (Not) epub

    Bad Programming Practices 101 Become a Better Coder by Learning How (Not) to Program 英文epub 本资源转载自网络,如有侵权,请联系上传者或csdn删除 查看此书详细信息请在美国亚马逊官网搜索此书

    The Clean Coder

    Martin, "The Clean Coder: A Code of Conduct for Professional Programmers" Prentice Hall | 2011 | ISBN: 0137081073 | 256 pages | PDF | 6 MB Programmers who endure and succeed amidst swirling ...

    phpcoder.rar

    phpcoder安装包。 直接下载安装即可。

    HDL-Coder详细教程

    HDL-Coder详细教程,有详细例子,源于官方例程,中文教程

    php coder编辑器

    PHPCoder用于快速开发和调试PHP应用程序,它很容易扩展和定制,完全能够符合开发者的个性要求.PHPCoder是一个非常实用的,功能强大的编程环境,而且它是免费的!

    simulink hdl coder 用户手册pdf

    HDL CODER 的用户手册,学习hdl coder参考用书,详细介绍了用simulink开发fpga的过程

    MediaCoder答题器

    MediaCoder答题器

    Embedded Coder.rar

    texasinstrumentsc2000.mlpkginstall 支持TI的C2000系列工具包,要求MATLAB R2017a及其以上版本。 安装方法:打开matlab,调整路径到mlpkginstall文件所在目录;在current folder窗口里双击mlpkginstall文件即可开始...

    coder的建表语句

    coder的建表语句

    mediacoder专业版

    mediacoder 5685专业版,无普通版的限制

    MediaCoder使用说明文档

    MediaCoder使用说明文档, mediaCoder usermanual,

    range coder.pdf

    range coder, algorithm, compressing.

    MediaCoder.5755专业破解版

    MediaCoder行业版一款针对VOD及KTV视频点播行业开发的,用于转换和处理带有多音轨内容的视频节目的软件。它具备业界领先的视频编码引擎,在高性能转码的同时保持高画质,并通过丰富的视频滤镜增强画面视觉效果。作为...

    matlab Embedded Coder Getting Started Guide.pdf

    Embedded Coder用于产生嵌入式处理器、目标快速原型板和大规模生产中使用的微处理器的可读的、紧凑的、快速的C和C++代码。Embedded Coder支持附加的MATLAB Coder™和Simulink Coder™配置选项,以及对生成代码的功能...

    MediaCoder64位专业破解版

    MediaCoder-Premium-x64 MediaCoder是最早开始使用GPU进行视频编码加速的影音转码软件之一。通过将原本完全依赖CPU的计算工作转移到GPU上进行,H.264和H.265编码所需的时间被大幅缩短。

    AI自动生成SQL语句的开源代码 sqlcoder-main.zip

    开源的AI自动生成SQL语句源代码,这款...SQLCoder2和SQLCoder-7B模型已经向公众开放,大家可以直接拿来嵌入到你的业务开发应用中。大家到这个地址来下载模型:https://huggingface.co/defog/sqlcoder-7b-2,即可使用。

    Mediacoder 使用帮助文档

    Mediacoder 入门使用说明+各种编码常用参数设置。

Global site tag (gtag.js) - Google Analytics