序文
Java開発者のために、J2EE仕様のセッションに精通している必要があります。 TomcatをWebコンテナとして使用するほとんどの開発者にとって、Tomcatはユーザーをマークしてセッション情報を管理するためにセッションをどのように実装しますか?
まとめ
セッション
Tomcatは、セッションに関連するインターフェイスとhttpsessionを内部的に定義します。クラス継承システムを図1に示します。
図1セッションクラス継承システム
図1には、セッションのクラス継承システムをリストすると、ここで1つずつ導入されています。
セッション:Tomcatのセッションの基本的なインターフェイス仕様は、これらのメソッドを紹介しています。
表1セッションインターフェイスの説明
方法 | 説明する |
getCreationTime()/setCreationTime(時間:ロング) | セッションの作成時間を取得して設定します |
getId()/setID(id:string) | セッションのIDを取得して設定します |
getthisaccessedtime() | 最後のリクエストの開始時間を取得します |
getLastAccesSedTime() | 最後のリクエストの完了時間を取得します |
getManager()/setManager(マネージャー:マネージャー) | セッションマネージャーを取得してセットアップします |
getMaxinActiveInterval()/setMaxinActiveInterval(interval:int) | セッションの設定の間に最大アクセス間隔を取得します |
getsession() | httpsessionを取得します |
isvalid()/setValid(isvalid:boolean) | セッションの有効なステータスを取得して設定します |
access()/endaccess() | セッションアクセスを開始して終了します |
期限切れ() | セッションの有効期限を設定します |
HTTPSESSION:HTTPクライアントとHTTPサーバーが提供するセッションのインターフェイス仕様は、定義する主なメソッドを示し、表2にこれらのメソッドを紹介します。
表2 HTTPSESSIONインターフェイスの説明
方法 | 説明する |
getCreationTime() | セッションの作成時間を取得します |
getId() | セッションのIDを取得します |
getLastAccesSedTime() | 最後のリクエストの完了時間を取得します |
getservletcontext() | 現在のセッションが属するServletContextを取得します |
getMaxinActiveInterval()/setMaxinActiveInterval(interval:int) | セッションの設定の間に最大アクセス間隔を取得します |
getAttribute(name:string) /setattribute(name:string、value:object) | セッションスコーププロパティを取得して設定します |
Removeattribute(name:string) | クリアセッションスコーププロパティ |
Invalidate() | セッションを無効にし、このセッションに縛られたオブジェクトを元に戻す |
クラスター:クラスター展開の下でのセッションインターフェイス仕様は、その主要な方法をリストし、表3にこれらの方法を紹介します。
表3クラスターセッションインターフェイスの説明
方法 | 説明する |
isprimarysession() | クラスターのメインセッションですか? |
SetPrimarySession(ブールプライマリセッション) | クラスターマスターセッションをセットアップします |
標準:標準のHTTPセッションの実装では、この記事ではこの実装を例として使用します。
Tomcatクラスターを展開する場合、クラスター内の各ノードのセッションステータスは現在同期しておく必要があります。
複製セッション:毎回、セッションオブジェクト全体がクラスター内の他のノードに同期され、他のノードはセッションオブジェクト全体を更新します。この実装は比較的単純で便利ですが、大量の無効な情報の送信を引き起こします。
Deltasession:セッション内の増分変更されたプロパティを同期します。この方法は増分であるため、ネットワークI/Oのオーバーヘッドを大幅に削減しますが、セッション属性操作プロセスの管理が含まれるため、実装はより複雑になります。
セッションマネージャー
Tomcatは、図2に示すように、セッションマネージャーのインターフェイス仕様を策定するためのマネージャーインターフェイスを内部的に定義しています。
図2セッションマネージャーのクラス継承システム
以下の図2の対応するコンテンツについて説明します。
マネージャー:セッションマネージャーによって定義されたインターフェイス仕様のTomcatは、図2にマネージャーインターフェイスで定義された主な方法をリストし、表4はこれらの方法の役割を詳細に説明しています。
表4マネージャーインターフェイスの説明
方法 | 説明する |
getContainer()/setContainer(コンテナ:コンテナ) | セッションマネージャーに関連付けられたコンテナを取得または設定します。通常、コンテキストコンテナ |
getDistributable()/setDistributable(分散可能:boolean) | セッションマネージャーが分散をサポートするかどうかを取得または設定します |
getMaxinActiveInterval()/setMaxinActiveInterval(interval:int) | セッションマネージャーによって作成されたセッションの最大の非アクティブ間隔を取得または設定します |
GetSessionIdlength()/setSessionIdLength(adlength:int) | セッションマネージャーによって作成されたセッションIDの長さを取得または設定します |
GetSessionCounter()/SetSessionCounter(SessionCounter:Long) | セッションマネージャーによって作成されたセッションの総数を取得または設定します |
getMaxactive()/setMaxactive(maxactive:int) | 現在アクティブ化されているセッションの最大数を取得または設定します |
getActivesEssions() | 現在アクティブ化されているすべてのセッションを取得します |
getExpiredSessions()/setExpiredsessions(expiredsessions:long) | 現在期限切れになっているセッションの数を取得または設定します |
getRejectEdSessions()/setRejectedsessions(拒否:int) | 作成されたことが拒否されたセッションの数を取得または設定する |
GetSessionMaxalivetime()/setSessionMaxalivetime(sessionmaxalivetime:int) | 期限切れのセッションで最大アクティビティ期間を取得または設定します |
GetSessionAveragealivetime()/setSessionAveragealivetime(sessionaveragealivetime:int) | 期限切れのセッションの平均アクティビティ期間を取得または設定する |
追加(セッション:セッション)/削除(セッション:セッション) | セッションマネージャーにアクティブセッションを追加または削除します |
ChangesSessionID(セッション:セッション) | セッションに新しく生成されたランダムセッションIDを設定します |
createssession(sessionid:string) | セッションマネージャーのデフォルト属性構成に基づいて新しいセッションを作成する |
FindSession(ID:文字列) | SessionIDパラメーターの一意のマークでセッションを返します |
findsessions() | セッションマネージャーが管理するすべてのアクティビティを返します |
load()/unload() | 持続メカニズムまたは書き込みセッションから永続メカニズムへのロードセッション |
backgroundprocess() | コンテナインターフェイスは、バックグラウンドで特定のコンテナ処理関連作業の実装として定義されます。 |
マネージャーベース:マネージャーインターフェイスによって一般的に実装されている抽象クラスをカプセル化します。すべてのセッションマネージャーは、マネージャーベースから継承されます。
ClusterManager :マネージャーインターフェイスに基づいて、クラスター展開の下にいくつかのインターフェイスを追加しました。
PersistentManagerbase:セッションの持続性の基本的な実装を提供します。
PersistentManager:PersistentManagerBaseから継承され、server.xmlで<Store>要素を構成することで使用できます。 PersistentManagerは、メモリ内のセッション情報をファイルまたはデータベースにバックアップできます。セッションオブジェクトがバックアップされると、セッションオブジェクトはメモリ(ファイルまたはデータベース)にコピーされ、元のオブジェクトはメモリに残ります。したがって、サーバーがダウンしても、アクティブなセッションオブジェクトをメモリから取得できます。アクティブなセッションオブジェクトが上限を超えている場合、またはセッションオブジェクトのアイドルが長すぎる場合、セッションはメモリに交換されてメモリスペースを保存します。
StandardManager: <Store>要素を構成する必要はありません。Tomcatが正常に閉じられている場合、Webアプリケーションがリロードされます。 。 Tomcatが再起動するか、アプリケーションがロードされると、Tomcatはファイル内のセッションをメモリに復元します。サーバーが突然終了した場合、StandardManagerには保存処理を実装する機会がないため、すべてのセッションが失われます。
ClusterManagerbase:セッションにクラスター管理の実装を提供します。
Deltamanager:ClusterManagerbaseから継承。このセッションマネージャーは、クラスターのノードがセッションを生成または変更すると、Tomcatのデフォルトマネージャーです。
BackupManager: ClusterManagerbaseを継承するのではなく、ClusterManagerインターフェイスを直接実装します。クラスターのすべてのセッションがバックアップノードに完全に複製されているため、Tomcatのオプションのセッションマネージャーです。クラスター内のすべてのノードは、このバックアップノードにアクセスして、クラスター内のセッションのバックアップ効果を実現できます。
簡単にするために、この記事では、StandardManagerを例として使用して、セッションの管理を説明します。 StandardManagerは、StandardContextの子コンポーネントであり、現在のコンテキストのすべてのセッションの作成とメンテナンスを管理するために使用されます。記事「Tomcatソースコード分析 - ライフサイクル管理」の内容を読んだり精通している場合、StandardContextが正式に起動されると、StandardContextのStartInternalメソッド(リスト1を参照)がStandardContextと呼ばれることがわかります。まだStandardManagerを開始します。
コードリスト1
@Override Protected Synchronized void startinternal()throws lifecycleexception {//セッション管理に関連しないコードを省略します。 && distribution {try {contextmanager = getCluster() StandardManager(); Clusterに分布しているコンテキストがあること、および独自のマネージャーGetCluster()。 if(Manager!= null)&&(Manager Instanceof Lifecyce)){(Lifecycle)getManager()) .Error( "ErrorManager。Start()、e);
リスト1から、標準コンテキストの開始インターナール方法でのセッション管理に関与する実行手順は次のとおりです。
StandardManagerを作成します。
Tomcatが分散型展開のためにApacheを組み合わせた場合、現在のStandardManagerはクラスターに登録されます。
StandardManagerを開始します。
StandardManagerの開始方法はStandardManagerを起動するために使用され、実装はコードのリスト2に示されています。
コードリスト2
@Override public同期最終void start()throws lifecycleexception {//状態検証のコードを省略します(state.equals(lifecyclestate.new)){init()}; !state.equals(stopped) } if(state.equals(lifecyclestate.failed)|| state.equals(lifecyclestate.must_stop)){stop();彼らが想定されていることを行う。
リスト2から、StandardManagerを開始する手順は次のとおりであることがわかります。
INITメソッドを呼び出して、StandardManagerを初期化します。
Startinternalメソッドを呼び出して、StandardManagerを開始します。
StandardManagerの初期化
上記の分析の後、StandardManagerを開始するための最初のステップは、親クラスのライフサイクルベースのINITメソッドを呼び出すことであることがわかります。 StandardManagerの初期を気にする。 StandardManager自体は初期メソッドを実装していませんが、StandardManagerの親クラスマネージャーベースはこの方法を実装しています。その実装については、リスト3を参照してください。
コードリスト3
@Overrideは、lifecycleexceptionを保護します{super.initinternal();
コード3のリスト3を読むと、マネージャーベースの初期メソッドの実行手順を要約します。
コンテナ自体をJMXに登録します(ライフサイクルムンビーンベースの初期方法の実装のための記事「Tomcatソースコード分析 - ライフサイクル管理」を参照)。
Parent Container StandardContextから現在のTomcatを取得し、ManagerBaseのブールプロパティに設定します。
getRandomBytesメソッドを呼び出して、このファイルが存在しない場合、ランダム数のファイル /dev /urandomからランダムなバイト配列を取得します。
注:ここでgetRandombytesメソッドを呼び出すことで生成されるランダムなバイト配列は、ここで呼び出されない理由は、将来のセッションIDを割り当てるときに使用できるように、乱数ジェネレーターの初期化を完了することです。
GetRandomBytesメソッドのコード実装を詳細に読みましょう。コードのリスト4を参照してください。
コードリスト4
保護されたvoid getrandombytes(バイトバイト[]){//セッション識別子を含むバイト配列を生成するif(devrandomsource!= null && randomis == null){set randomfile(devrandomsource); int len = randomis.read(bytes); CATCH(//無視} devrandOmsource = try {exception e){log.warn( " ).nextbytes(バイト);
リスト4のsetrandomfile
方法(コードのリスト5を参照)は、乱数ファイル /dev /urandomからバイトのランダム配列を取得するために使用されます。
コード5のリスト
public void setrandomfile(string s){//ハックとして、静的ファイルを使用し、同じ//セッションIDS(奇妙なデバッグに適しています)を生成できます(globals.is_se curity_enabled){randomis = accesscontroller.doprivileged(new特権randomfile(s); readLong() ){randomis.close();
リスト4(リスト6を参照)のsetrandomfileメソッドは、反射を通じてjava.security.securerandomのインスタンスを生成し、このインスタンスを使用してランダムバイトの配列を生成します。
コードリスト6
public random getrandom(){if(this.random == null){//新しい乱数の種子= system.currenttimemillisを計算します。 )for(int i = 0; i <entropy.length){(byte)entropy [i])<<(i%8) * 8); //新しい乱数のジェネレータークラス<? e){//シンプルなケースに戻ります(シード))if(log.isdebugenabled()){long t2 = currenttimemillis(); ) + " +(t2-t1));
上記の分析によると、StandardManagerの初期化は、主にマネージャーベースの初期方法を実行します。
StandardManagerの開始
startandManagerのstartinternalメソッドを呼び出すことは、StandardManagerを開始するために使用されます。リスト7を参照してください。
コードリスト7
@Overrideが同期したvoid startinternal()スロー{//ランダム数ジェネレーターのファース初期化isdebugenabled())log.debug( "random数の初期化が完了しました"); ManagerLoad ")、t);} setState(lifecyclestate.starting);}
リスト7から、StandardManagerを開始する手順は次のとおりであることがわかります。
ステップ1:GeneratesSessionIDメソッド(リスト8を参照)を呼び出して、新しいセッションIDを生成します。
コードリスト8
Protected Synchronized generatedsessionid(){] = new byte [16]; {int resultlenbytes = 0; ; for (int j = 0; j < random.length && resultLenBytes < this.sessionIdLength; j++) { byte b1 = (byte) ((random[j] & 0xf0) >> 4); byte b2 = (byte) (ランダム[j]&0x0f); if(b1 <10)append( '0' + b1); ;(b2 <10)buffer.(char)( ' +(b2-10)); jvmroute! :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::づ 火::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::づ 火::::: :::::::::::::::::::::::::::::::::::::::..
ステップ2永続的なセッション情報をロードします。なぜセッションを維持する必要があるのですか?すべてのセッションはStandardManagerの同時ハッシュマップで維持されているため、サーバーの再起動またはダウンタイムにより、これらの問題が失われるか無効になります。 StandardManagerのロードメソッドの実装を見てみましょう。コードの9つのリストを参照してください。
コードリスト9
public void load()throws classnotfoundexception、if(securityutil.ispackageProtectionEnabled()) classNotFoundExceptionの例外){classNotFoundException)Else; ;
セキュリティメカニズムをオンにする必要があり、パッケージ保護モードをオンにすると、CODEのリスト10に示すように実装されている特権を作成することにより、永続的なセッションがロードされます。
リスト10
Private Class PrivileGedDoloadは、特権を実装しています。
リスト10から、実際にロードの原因となる方法は、リスト9によると、デフォルトではセッション情報もドロードであることがわかります。したがって、Doloadの実装を確認する必要があります。コードのリスト11を参照してください。
リスト11
保護されたdoload()throws classnotfoundexception、if(log.isdebugenabled())log.debug(start:loading sessions ")指定されたパス名、file = file(); FileInputStream bufferedintStream = null = null = nullコンテナ!= null)container.getLoader();クラスローダーのカスタムオブジェクト入力ストリームの作成 "); ois = new CustomObjectInputStream(bis、classloader);} else {if(log.isdebugenabled())log.debug("標準object入力ストリーム "); ois = new objectinputStream(bis)} catch(log.isdebugenabled())log.debug( "return exection e){log.errまたは(sm .getString( "StandardManager.Loading .ioe"、e)、if(fis!= null){fis.close()} null){bis(); readobject(); count.intvalue(); {Stardnadys.sessions.sessions.put(session.getidternal(); ){//メモリ漏れを防ぐためにセッションが終了します。 getString(standardmanager.loading.cnfe "、e); .getString( "StandardManager.Loading。Eo"、e); ois.close(); catch(ioexception f){//無視} // if(file.exists())file.delete() Debug( "Finish:Loa Ding Persisted Sessions");
リスト11から、StandardManager Doloadメソッドの実行手順を次のとおりです。
セッションキャッシュによって維持されているセッション情報をクリアします。
ファイルメソッドを呼び出して、次のような現在のコンテキストでセッションの永続的なファイルを返します。
セッションの永続的なファイルの入力ストリームを開き、CustomObjectInputStreamとしてカプセル化します。
セッションの永続的なファイルから永続的なセッションの数を読んでから、セッション情報を1つずつ読んで、セッションキャッシュに入れます。
この時点で、StandardManagerの発売の紹介は、次の記事での配分、追跡、破壊、その他のコンテンツを説明します。