beginning java ee 6 勉強会(3) #bje_study

57
Beginning JavaEE6 勉勉勉 (3) -Enterprise JavaBean- Hiroki Inagaki @inatus http://github.com/inatus

Upload: inatus

Post on 11-Jun-2015

4.520 views

Category:

Documents


4 download

DESCRIPTION

JavaEE 6のEJB (Enterprise JavaBean) についての説明

TRANSCRIPT

Page 1: Beginning Java EE 6 勉強会(3) #bje_study

Beginning JavaEE6 勉強会 (3)-Enterprise JavaBean-

Hiroki Inagaki@inatus

http://github.com/inatus

Page 2: Beginning Java EE 6 勉強会(3) #bje_study

2

目次

5/16/2012 Beginning JavaEE6 勉強会 (1)

6. Enterprise JavaBeans

7. セッション Beanとタイマーサービス

8. コールバックとインターセプタ

9. トランザクションとセキュリティ

Page 3: Beginning Java EE 6 勉強会(3) #bje_study

3

第6章Enterprise JavaBeans

5/16/2012 Beginning JavaEE6 勉強会 (3)

Page 4: Beginning Java EE 6 勉強会(3) #bje_study

4

EJBとは トランザクションとセキュリティを扱うサーバサイドのコンポーネント

ビジネスロジックをカプセル化 メッセージング、スケジューリング、リモートアクセス、 SOAP/REST、 DI、 AOPを扱う

JDBC、 JavaMail、 JPA、 JTA、 JMS、 JAAS、 JNDI、 RMIと統合

5/16/2012 Beginning JavaEE6 勉強会 (1)

Page 5: Beginning Java EE 6 勉強会(3) #bje_study

5

第7章セッションBeanとタイマーサービス

5/16/2012 Beginning JavaEE6 勉強会 (3)

Page 6: Beginning Java EE 6 勉強会(3) #bje_study

6

セッション Bean

EJBの核 ビシネスロジックをカプセル化する 以下の種類がある

ステートレス対話状態を保持しない 1つのメソッドで完結

ステートフル対話状態を保持する複数のメソッドにまたがって利用

シングルトン複数のクライアントが同時にアクセス

5/16/2012 Beginning JavaEE6 勉強会 (1)

Page 7: Beginning Java EE 6 勉強会(3) #bje_study

7

ステートレス Bean

最も良く使用される 単一のメソッド呼び出しでタスクが完了するビジネスプロセスを実行する

一定の数のインスタンスがプール内に格納される複数のクライアント間で再利用できるため、最も効率が良い

5/16/2012 Beginning JavaEE6 勉強会 (3)

インスタンスプールインスタンス インスタン

スインスタンス

クライアントクライアント

EJBコンテナ

Page 8: Beginning Java EE 6 勉強会(3) #bje_study

8

ステートレス Bean

5/16/2012 Beginning JavaEE6 勉強会 (3)

@Statelesspublic class MemberEJB {

@PersistenceContext(unitName = "sample") private EntityManager em;

public Member findMemberById(Long id) { return em.find(Member.class, id); } public Member createMember(Member member) { em.persist(member); return member; }}

Page 9: Beginning Java EE 6 勉強会(3) #bje_study

9

ステートフル Bean

前のステップの状態に依存する複数ステップを含むタスクに使用できる

例えば、ショッピングサイトのように、商品を選択してから決済が完了するまでショッピングカートの中身が保持されなければならないといった場合に使用する

Beanインスタンスとクライアントは一対一で紐付けられる

5/16/2012 Beginning JavaEE6 勉強会 (3)

EJBコンテナ

インスタンス インスタン

スクライアントクライアント

①要求②生成

③呼出し

Page 10: Beginning Java EE 6 勉強会(3) #bje_study

10

ステートフル Bean

5/16/2012 Beginning JavaEE6 勉強会 (3)

@Stateful@StatefulTimeout(value = 15, unit = TimeUnit.MINUTES)public class CartEJB {

private Set<Item> cart = new LinkedHashSet<Item>();

public void addItem(Item item) { cart.add(item); } public void removeItem(Item item) { cart.remove(item); }}

Page 11: Beginning Java EE 6 勉強会(3) #bje_study

11

アプリケーションごとに 1つのインスタンスが生成される

各クライアントは 1つのインスタンスを共有する

同時実行の制御を行う必要がある 初期化の次期や、複数のシングルトン Beanを初期化する順序を考慮する必要がある

EJBコンテナ

シングルトン Bean

5/16/2012 Beginning JavaEE6 勉強会 (3)

インスタンス

クライアント

クライアント

クライアント

Page 12: Beginning Java EE 6 勉強会(3) #bje_study

12

シングルトン Bean

5/16/2012 Beginning JavaEE6 勉強会 (3)

@Singletonpublic class CacheEJB {

private Map<Long, Object> cache = new HashMap<Long, Object>(); public void addToCache(Long id, Object target) { if (!cache.containsKey(id)) { cache.put(id, target); } } public void removeFromCache(Long id) { cache.remove(id); }}

Page 13: Beginning Java EE 6 勉強会(3) #bje_study

13

セッション Beanモデル Beanクラスの定義にインタフェースを用いる方法と用いない方法があるリモート・インタフェース

EJBコンテナが動作している JVMインスタンスの外部にクライアントが存在する場合に使用

RMIを利用するローカル・インタフェース

同じ JVM内の別の EJBやWebコンポーネントを呼び出すインタフェースのないビュー

ローカルビューの一種すべてのパブリックメソッドをローカルに公開する

5/16/2012 Beginning JavaEE6 勉強会 (3)

Page 14: Beginning Java EE 6 勉強会(3) #bje_study

14

アプリケーションサーバ 2EJBコンテナ

EJBコンテナコンポーネント

Bean

Bean

アプリケーションサーバ 1EJBコンテナ

EJBコンテナ

セッション Beanモデル

5/16/2012 Beginning JavaEE6 勉強会 (3)

コンポーネント

クライアント

ローカル リモート

Bean

Bean

Page 15: Beginning Java EE 6 勉強会(3) #bje_study

15

ローカル&リモート・インタフェース

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Localpublic interface MemberEJBLocal { Member findMemberById(Long id);}

@Remotepublic interface MemberEJBRemote { Member createMember(Member member);}

@Statelesspublic class MemberEJB implements MemberEJBLocal,

MemberEJBRemote { ...}

Page 16: Beginning Java EE 6 勉強会(3) #bje_study

16

インタフェースのないビュー

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Stateless@LocalBeanpublic class MemberEJB { ...}

Page 17: Beginning Java EE 6 勉強会(3) #bje_study

17

クライアントからの Bean呼び出し リモート&ローカル・インタフェースの場合インタフェースオブジェクトに@EJBで DIする

インタフェースのないビューの場合クラスのオブジェクトに@EJBで DIする

5/9/2012 Beginning JavaEE6 勉強会 (3)

@EJB MemberEJBRemote memberEJBRemote;@EJB MemberEJBLocal memberEJBLocal;

@EJB MemberEJB memberEJB;

Page 18: Beginning Java EE 6 勉強会(3) #bje_study

18

DI(依存性注入)

以下のような方法がある @EJB

EJBのリモート&ローカル・インタフェース、インタフェースのないビューの参照を注入

@PersistenceContext, @PersistenceUnit EntityManager, EntityManagerFactoryの依存関係を表す

@WebServiceRef Webサービスへの参照を注入

@Resource JDBCデータソース、セッション・コンテキスト、ユーザ・トランザクション等の参照を注入

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 19: Beginning Java EE 6 勉強会(3) #bje_study

19

非同期呼び出し 印刷やメール送信などの処理が終了するまで待たずに、続く処理を続行する

セッション Beanのメソッドまたはクラスに@Asynchronousを付加する

非同期呼び出しからの戻り値を用いる場合は戻り値の型に Future<V>を使用する

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 20: Beginning Java EE 6 勉強会(3) #bje_study

20

非同期呼び出し

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Stateless@Asynchronouspublic class OrderEJB {

public void sendEmailConfirmation(Order order) {// Emailの送信処理

}

public void printOrder(Order order) {// 注文書の印刷処理

}

public Future<Integer> CalcShippingCost(Order order) {int shippingCost = 0;// 送料計算処理return AsyncResult<Integer>(shippingCost);

}

Page 21: Beginning Java EE 6 勉強会(3) #bje_study

21

タイマサービス 特定の時間に特定の処理を起動する

毎晩在庫レポートを出力毎月売上を集計毎年ユーザの誕生日にメールを送信

起動対象のメソッドに@Scheduleアノテーションとタイマを設定

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 22: Beginning Java EE 6 勉強会(3) #bje_study

22

タイマサービス

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Statelesspublic class TimerEJB {

// 毎日 0時 0分 0秒に実行 @Schedule(second = "0", minute = "0", hour = "0") public void outputReport() { // 日次レポート出力処理 }

// 毎月の最終日の 22時に実行 @Schedule(hour = "22", dayOfMonth = "Last") public void addUpSales() { // 月次の売上を集計 }}

Page 23: Beginning Java EE 6 勉強会(3) #bje_study

23

タイマサービス

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Statelesspublic class MemberEJB {

@Resource TimerService timerService; // Memberの誕生日にタイマを設定 public Member createMember(Member member) { em.persist(member); ScheduleExpression membersBirthday

= new ScheduleExpression().dayOfMonth(member.getBirthDay()).month(member.getBirthMonth());

timerService.createCalendarTimer(membersBirthday, new TimerConfig(member, true));

return member; }// 次頁へ続く

Page 24: Beginning Java EE 6 勉強会(3) #bje_study

24

タイマサービス

5/9/2012 Beginning JavaEE6 勉強会 (3)

// 前頁から続き // タイマが切れたときに Eメールを送信 @Timeout public void sendBirthdayEmail(Timer timer) { Member member = (Member) timer.getInfo(); // Eメール送信処理 }}

Page 25: Beginning Java EE 6 勉強会(3) #bje_study

25

第8章コールバックとインターセプタ

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 26: Beginning Java EE 6 勉強会(3) #bje_study

26

コールバックとインターセプタ コールバック

Beanの状態遷移が起きる際に任意のメソッドを呼び出すこと

Beanごとに設定する

インターセプタ AOPと同様の機能 Beanのメソッドを呼び出す際に、別のメソッドを呼び出し割り込み処理を行う

複数の Beanに対して横断的に設定できる

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 27: Beginning Java EE 6 勉強会(3) #bje_study

27

コールバック ステートレス Bean、シングルトン Beanのライフサイクル

5/9/2012 Beginning JavaEE6 勉強会 (3)

存在しない状態

準備状態

5.@PreDestroy呼出し1.インスタンス生成2.依存性注入3.@PostConstruct呼出し

4.メソッド呼出し

Page 28: Beginning Java EE 6 勉強会(3) #bje_study

28

コールバック ステートフル Beanのライフサイクル

5/9/2012 Beginning JavaEE6 勉強会 (3)

存在しない状態

準備状態

1.インスタンス生成2.依存性注入3.@PostConstruct  呼出し 6.@PostActive呼出し

4.メソッド呼出し

非活性化状態

5.@PrePassive呼出し

7.タイムアウト

8.@Removeおよび @PreDestroy呼出し

Page 29: Beginning Java EE 6 勉強会(3) #bje_study

29

コールバック

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Statefulpublic class CartEJB { @Resource private DataSource ds; private Connection conn; @PostConstruct @PostActivate private void init() throws SQLException { conn = ds.getConnection(); } @PreDestroy @PrePassivate private void close() throws SQLException { conn.close(); }

Page 30: Beginning Java EE 6 勉強会(3) #bje_study

30

コールバックメソッド 引数なしの voidメソッドであること チェック例外のスロー不可、実行時例外は可 アクセス修飾子はすべて使用可 static、 finalは不可 1メソッドに複数のアノテーションを指定可 同じアノテーションを 2度以上指定不可

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 31: Beginning Java EE 6 勉強会(3) #bje_study

31

インターセプタ AroundInvokeインターセプタ

Beanごとに適用 Bean内のすべてのメソッドに対して適用される

クラス・インターセプタ 複数の Beanに横断的に適用 インターセプト用のクラスを定義

ライフサイクル・インターセプタ コールバックの機能を複数の Beanに横断的に適用

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 32: Beginning Java EE 6 勉強会(3) #bje_study

32

AroundInvokeインターセプタ

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Statelesspublic class MemberEJB { public Member findMemberById(Long id) { ... } public Member createMember(Member member) { ... }

@AroundInvoke private Object recordLog(InvocationContext ic) throws Exception { // メソッド呼び出し前ログ書き込み処理 try { return ic.proceed(); finally { // メソッド呼び出しログ書き込み処理 {

Page 33: Beginning Java EE 6 勉強会(3) #bje_study

33

AroundInvokeインターセプタの定義@AroudInvokeObject <メソッド名 >(InvocationContext ic) throws Exception;

引数は javax.interceptor.InvocationContext型

戻り値は Object型 チェック例外をスロー可 アクセス修飾子はすべて使用可 static、 finalは不可 proceedメソッドでビジネスメソッドを呼び出し、結果を返すただしチェーン内に次のインターセプタメソッドがある場合はそのインターセプタメソッドを呼び出す

5/9/2012 Beginning JavaEE6 勉強会 (3)

@AroudInvokeObject <メソッド名 >(InvocationContext ic) throws Exception;

Page 34: Beginning Java EE 6 勉強会(3) #bje_study

34

クラス・インターセプタ

5/9/2012 Beginning JavaEE6 勉強会 (3)

public class LoggingInterceptor { @AroundInvoke private Object recordLog(InvocationContext ic) throws Exception { // メソッド呼び出し前ログ書き込み処理 try { return ic.proceed(); finally { // メソッド呼び出しログ書き込み処理 {{

Page 35: Beginning Java EE 6 勉強会(3) #bje_study

35

クラス・インターセプタ

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Statelesspublic class MemberEJB { @Interceptors(LoggingInterceptor.class) public Member findMemberById(Long id) { ... } public Member createMember(Member member) { ... }}

Page 36: Beginning Java EE 6 勉強会(3) #bje_study

36

クラス・インターセプタ インターセプタとする任意のクラスのメソッドに@AroundInvokeアノテーションを使用

インターセプタを適用したいメソッドまたはクラスに@Interceptorsアノテーションを使用メソッドに指定すると指定したメソッドのみインターセプタを適用する

クラスに指定するとクラス内のすべてのメソッドにインターセプタを適用する

特定のメソッドのみをインターセプタ適用外とする場合は@ExcludeClassInterceptorsアノテーションを用いる

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 37: Beginning Java EE 6 勉強会(3) #bje_study

37

ライフサイクル・インターセプタ

5/9/2012 Beginning JavaEE6 勉強会 (3)

public class LoggingInterceptor { @PostConstruct private void init() { // 初期化処理 {{

Page 38: Beginning Java EE 6 勉強会(3) #bje_study

38

ライフサイクル・インターセプタ

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Stateless@Interceptors(LoggingInterceptor.class)public class MemberEJB { public Member findMemberById(Long id) { ... } public Member createMember(Member member) { ... }}

Page 39: Beginning Java EE 6 勉強会(3) #bje_study

39

ライフサイクル・インターセプタ Beanのライフサイクルに応じたコールバックを複数の Beanを横断的に適用可能

@PostConstruct, @PrePassivate, @PostActivate, @PreDestroyが指定可能

インターセプタを適用したいクラスに@Interceptorsアノテーションを使用

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 40: Beginning Java EE 6 勉強会(3) #bje_study

40

第9章トランザクションとセキュリティ

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 41: Beginning Java EE 6 勉強会(3) #bje_study

41

EJBでのトランザクションサポート コンテナ管理トランザクション( CMT)

トランザクションの開始、コミット、ロールバックをコンテナが自動的に管理

なにも設定しない時のデフォルトの動作 Bean管理トランザクション( BMT)

トランザクションの開始、コミット、ロールバックを Bean内に明示的に記述

04/13/2023 Beginning JavaEE6 勉強会 (3)

Page 42: Beginning Java EE 6 勉強会(3) #bje_study

42

コンテナ管理トランザクション( CMT)

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Statelesspublic class MemberEJB {

@PersistenceContext(unitName = "sample") private EntityManager em; public Member createMember(Member member) { em.persist(member); return member; }}

Page 43: Beginning Java EE 6 勉強会(3) #bje_study

43

CMTの属性 クライアントがトランザクション対応のメソッドを呼び出すときに、そのメソッドがトランザクション内で呼び出されているか否かによって、以下の 4つうちどの動作をするかを設定できるコンテナがクライアントのトランザクションを利用する

新しいトランザクションを開始してメソッドを実行する

トランザクションを使用しないでメソッドを実行する

例外をスローする クラスやメソッドに@TransactionAttributeを付加

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 44: Beginning Java EE 6 勉強会(3) #bje_study

44

CMTの属性CMT属性 トランザクション内でない トランザクション内REQUIRED 新しいトランザクション 呼出し元のトランザクションREQUIRED_NEW 新しいトランザクション 新しいトランザクションSUPPORTS トランザクションを使用し

ない呼出し元のトランザクション

MANDATORY 例外 呼出し元のトランザクションNOT_SUPPORTED トランザクションを使用し

ないトランザクションを使用しない

NEVER トランザクションを使用しない

例外

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 45: Beginning Java EE 6 勉強会(3) #bje_study

45

CMTの属性

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Stateless@TransactionAttribute (TransactionAttributeType.SUPPORTS)public class MemberEJB {

@PersistenceContext(unitName = "sample") private EntityManager em; public Member createMember(Member member) { em.persist(member); return member; }}

Page 46: Beginning Java EE 6 勉強会(3) #bje_study

46

CMTのロールバック デフォルトでは非チェック例外が発生した場合のみトランザクションがロールバックされる

明示的にトランザクションをロールバックするには DIにより SessionContextを取得しsetRollBackOnly()メソッドを呼び出す

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 47: Beginning Java EE 6 勉強会(3) #bje_study

47

CMTのロールバック

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Statelesspublic class MemberEJB {

@PersistenceContext(unitName = "sample") private EntityManager em; @Resource private SessionContext ctx; public Member createMember(Member member) { if (member.isValidMember) { ctx.setRollBackOnly(); } em.persist(member); return member; }}

Page 48: Beginning Java EE 6 勉強会(3) #bje_study

48

例外処理 デフォルトでは非チェック例外が発生した場合のみトランザクションがロールバックする

ユーザ例外クラスに@ApplicationExceptionを付加することでチェック例外/非チェック例外に関わらず、ロールバックの有無を設定可能

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 49: Beginning Java EE 6 勉強会(3) #bje_study

49

例外処理

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Statelesspublic class MemberEJB {

@PersistenceContext(unitName = "sample") private EntityManager em; @Resource private SessionContext ctx; public Member createMember(Member member) throws MemberInvalidException { if (member.isValidMember) { throw new MemberInvalidException(); } em.persist(member); return member; }}

Page 50: Beginning Java EE 6 勉強会(3) #bje_study

50

例外処理

5/9/2012 Beginning JavaEE6 勉強会 (3)

@ApplicationException(rollback = true)public class MemberInvalidException extends Exception {

public MemberInvalidException() {

}

public MemberInvalidException(String message) { super(message); }}

Page 51: Beginning Java EE 6 勉強会(3) #bje_study

51

Bean管理トランザクション( BMT) Beanのメソッド内に明示的にトランザクションの開始・コミット・ロールバックを記述

@TransactionManagementアノテーションを Beanクラスに付加すると Bean管理のトランザクションとなる

DIにより UserTransactionのインスタンスを生成し、 begin(), commit(), rollback()メソッドによりトランザクションの操作を行う

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 52: Beginning Java EE 6 勉強会(3) #bje_study

52

Bean管理トランザクション( BMT)

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Stateless@TransactionManagement( TransactionManagementType.BEAN)public class MemberEJB {

@PersistenceContext(unitName = "sample") private EntityManager em; @Resource private UserTransaction ut; public Member createMember(Member member) { ut.begin(); em.persist(member); if (member.isValidMember) { ut.rollback(); } ut.commit(); return member; }

Page 53: Beginning Java EE 6 勉強会(3) #bje_study

53

セキュリティ プリンシパルのロールごとに Bean全体または一部メソッドのアクセスを制御することができる

プリンシパル認証を行ったユーザのユーザ名

making kjstylepp inatus など

ロールプリンシパルごとに割り当てられるグループ名

Employee Admin User など

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 54: Beginning Java EE 6 勉強会(3) #bje_study

54

宣言型のセキュリティ アノテーションを Beanクラスまたはメソッドに付加し、アクセスを制御する

@PermitAllすべてのロールにアクセス許可を与える

@DenyAllすべてのロールからのアクセスを拒否する特定の環境でメソッドへのアクセスを拒否する場合などに利用する

@RollsAllowedリストに指定されているロールにアクセス許可を与える

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 55: Beginning Java EE 6 勉強会(3) #bje_study

55

宣言型のセキュリティ

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Stateless@RolesAllowed({“user”, “employee”, “admin”})public class MemberEJB {

@PermitAll public Member findMemberById(Long id) { ... } public Member createMember(Member member) { ... } @RolesAllowed(“admin”) public void deleteMember(Member member) { ... } @DenyAll public Member findConfidentialMember(Long id) { ... }

Page 56: Beginning Java EE 6 勉強会(3) #bje_study

56

プログラムによるセキュリティ 以下の場合に用いる

メソッド内のコードのブロックにアクセスを許可または拒否をする場合

個人へのアクセス許可または拒否をする場合 DIで SessionContextのインスタンスを生成し、以下のメソッドを用いる isCallerInRole():指定したロールであるかを判定し boolean値を返す

getCallerPrincipal(): Principalオブジェクト返す

Principal.getName()でプリンシパルの名前を取得可能

5/9/2012 Beginning JavaEE6 勉強会 (3)

Page 57: Beginning Java EE 6 勉強会(3) #bje_study

57

宣言型のセキュリティ

5/9/2012 Beginning JavaEE6 勉強会 (3)

@Stateless@RolesAllowed({“user”, “employee”, “admin”})public class MemberEJB {

@resource SessionContext ctx;

public Member findMemberById(Long id) { if (ctx.isCallerInRole(“user”) { // 本の検索処理 } if (ctx.getCallerPrincipal().getName() .equals(“inatus”) { return findConfidentialMember(id); } ...}