EJBとデータ構造内のオブジェクトの保存(マップ、リストなど)
質問
App Serverのアップタイムの間、オブジェクトをデータ構造に保存することは可能ですか?基本的に、このデータ構造とインターフェースするEJBが必要ですが、本格的なデータベースソリューションは必要ありません。
例として、このダミー動物オブジェクトを作成しました:
package com.test.entities;
public class Animal implements java.io.Serializable {
private static final long serialVersionUID = 3621626745694501710L;
private Integer id;
private String animalName;
public Integer getId() {
// TODO Auto-generated method stub
return id;
}
public void setId(Integer id){
this.id=id;
}
public String getAnimalName(){
return animalName;
}
public void setAnimalName(String animalName){
this.animalName=animalName;
}
}
これが EJBリモートインターフェースです:
package com.test.beans;
import java.util.Map;
import javax.ejb.Remote;
import com.test.entities.Animal;
@Remote
public interface MapBeanRemote {
public void addAnimal(Animal a);
public void removaAnimal(Integer id);
public Animal getAnimalById(Integer id);
Map<Integer, Animal> getAllAnimals();
}
セッションBeanは次のとおりです。
package com.test.beans;
import java.util.ConcurrentHashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.ejb.Stateless;
import com.test.entities.Animal;
@Stateless(mappedName="ejb/MapBean")
public class MapBean implements MapBeanRemote{
Map<Integer, Animal> animalStore;
@PostConstruct
public void initialize(){
animalStore = new ConcurrentHashMap<Integer,Animal>();
}
@Override
public void addAnimal(Animal a) {
if(a.getId()!=null){
animalStore.put(a.getId(), a);
}
}
@Override
public Animal getAnimalById(Integer id) {
return animalStore.get(id);
}
@Override
public void removaAnimal(Integer id) {
animalStore.remove(id);
}
@Override
public Map<Integer, Animal> getAllAnimals() {
return animalStore;
}
}
したがって、基本的には、動物マップを操作するクライアントはこのEJBを通過し、各クライアントが同じオブジェクトの正確なマップにアクセスするようにします。
この例では十分に機能しません。しばらくすると、すべての動物が消去されます(EJBがBeanプールから置き換えられると想定しています)これを何らかの形でリソースとして注入できますか?
解決
これは、マップをシングルトンに配置し、Beanからこのシングルトンにアクセスすることで実現できます。この方法では、すべてのEJBインスタンスに対して単一のインスタンスが存在します(それらは同じクラスローダーを共有するため)。異なるEARの異なるセッションBeanは、それぞれ独自のクラスローダーを持っているため機能しませんが、それはシナリオではないようです。
ConcurrentHashMapの既存の使用法はほとんどのケースを十分に処理しますが、2つのメソッド呼び出し間でマップの一貫性が必要なため、addAnimalメソッドの周りの同期が必要です。
他のヒント
新しいEJB 3.1仕様では、まさに必要な新しいタイプのBean(シングルトンBean)が提供されます。私が知っているEJB 3.1を部分的にサポートしている唯一の実装はApache OpenEJB 3.1です。これにはシングルトンBeanが含まれていますが、まだ使用していません。
これはステートレスセッションBeanです。名前が示すように、このようなBeanにはどのような状態も保持すべきではありません。 EJBコンテナは、Beanの複数のインスタンスと連携して、同時リクエストに対応できます。すべてのインスタンスのリストのデータをどのように同期しますか?私はこれを行う方法がないということです。
このようなリストをセッションBeanに保持すると、ビジネスロジックが提供され、ビジネスレイヤーの概念に違反することさえあります。自分でトランザクションと同時書き込みを処理する必要があります。
クライアント側で動物のリストを保持しないのはなぜですか?これがより良い方法だと思います。
データ構造をEJBから完全に移動し、静的データ構造として保存するのが最善の方法だと思います。 EJBがプールされているためにオブジェクトが消去されているという事実はおそらく正しいでしょう。
データ構造へのアクセスの実装方法によっては、スレッドの安全性を確保するためにアクセスを同期する必要がある場合が多いことに注意してください。
EJB内で状態を維持する場合は、ステートフルセッションBeanを確認することを検討してください。また、Beanがいつ破棄されるかを確認したい場合は、ejbremoveメソッドをオーバーライドできます。Java5の注釈を忘れてしまいます。
カール