Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JJUG Java仕様勉強会「CDI」

JJUG Java仕様勉強会「CDI」

2023/09/05に開催されたJJUG(日本Javaユーザーグループ)Java仕様勉強会「CDI: Contexts and Dependency Injection」の発表資料です。

https://jjug.doorkeeper.jp/events/162534

当日のプレイバックはこちらから
https://www.youtube.com/watch?v=7VV-zIsNA5I

Takakiyo Tanaka

September 05, 2023
Tweet

More Decks by Takakiyo Tanaka

Other Decks in Technology

Transcript

  1. 2 ⾃⼰紹介 2 n ⽥中 孝清 n ⽇本アイ・ビー・エム株式会社 オートメーションソフトウェア テクニカルセールス

    n WebSphere Application Serverなどの テクニカルセールスを20年以上担当 n Twitter @TTakakiyo
  2. 4 Contexts and Dependency Injectionとは n アノテーションで指定することによって, Beanの型に従ったタイプセーフな注⼊(インジェクション)を⾏うAPI 4 @Named

    @RequestScoped public class OrderOperation { ・・・・・・ @Inject private BookShop shop; ・・・・・・ } @Stateless public class BookShopBean extends Business implements ShopBook { ・・・・・・ @Inject @ShopDb private DataSource shopDb; ・・・・・・ } @Dependent public class Resources { @Produces @Resource(lookup="jdbc/ShopDB") @ShopDb public DataSource ds; } CDI管理Bean Session Bean • アノテーション「@Inject」でBookShop型のbeanを注⼊ • CDI管理Beanとして実装されたものや JAX-WSのエンドポイントなどがCDI管理Beanとして利⽤可能 • ServletなどのJava EEコンポーネントにも@Injectをサポート • アノテーション「@Inject」でデータソースを注⼊ • 限定⼦(Qualifie)で⽬的のデータソースを指定 • データソースを提供(@Produces)するクラス • 限定⼦(Qualifie)を付与
  3. 5 n DI(Dependency injection, 依存性の注⼊)とは – コンポーネント間の依存関係をプログラムのソースコードから排除し, 外部の設定ファイルなどで注⼊できるようにするソフトウェアパターンである – 依存関係がプログラムから外部に取り除かれることで,以下のようなメリットが発⽣する

    • 結合度の低下によるコンポーネント化の促進 • 単体テストの効率化 • 特定のフレームワークへの依存度低下 – 出典: Wikipedia n 従来のJNDIによるlookupによるオブジェクトの取得や,Factoryクラス経由の取得に⽐べて, より簡潔に記述でき,柔軟に挙動を制御することができる n CDI は,DIの機能に加えて, コンポーネントであるbeanのライフサイクル・コンテキストの管理機能を提供 – Contexts beanのライフサイクルをライフサイクル・コンテキストに関連付ける – Dependency Injection beanのインスタンスをインジェクション(注⼊)する 5 Contexts and Dependency Injectionの役割
  4. 6 CDIの歴史(1) 6 CDI 1.0 (JSR 299: Contexts and Dependency

    Injection for the Java EE platform) CDI 1.1/1.2 (JSR 346: Contexts and Dependency Injection for the Java EE platform) CDI 2.0 (JSR 365: Contexts and Dependency Injection for the Java EE platform) CDI 3.0 (Jakarta Contexts and Dependency Injection) CDI 2.0 (Jakarta Contexts and Dependency Injection) CDI 4.0 (Jakarta Contexts and Dependency Injection) Java EE 8 Java EE 7 Java EE 6 Jakarta EE 8 Jakarta EE 9 Jakarta EE 10
  5. 7 CDIの歴史(2) 7 CDI 1.0 (JSR 299: Contexts and Dependency

    Injection for the Java EE platform) CDI 1.1/1.2 (JSR 346: Contexts and Dependency Injection for the Java EE platform) Java EE 7 Java EE 6 Java EEへの Dependency Injection機能の取り込み Bean Discovery Modeの改善や各種仕様の明確化など CDIの基本機能の完成
  6. 8 CDIの歴史(3) CDI 2.0 (JSR 365: Contexts and Dependency Injection

    for the Java EE platform) CDI 3.0 (Jakarta Contexts and Dependency Injection) CDI 2.0 (Jakarta Contexts and Dependency Injection) CDI 4.0 (Jakarta Contexts and Dependency Injection) Java EE 8 Jakarta EE 8 Jakarta EE 9 Jakarta EE 10 Java SE環境での使⽤にあわせて仕様を分割 「Core CDI」「CDI in Java SE」「CDI in Java EE」 javax名前空間からjakarta名前空間への移⾏ Jakarta EE Core Profileの新設にあわせて CDI仕様とCDI lite仕様に分割
  7. 9 CDIの実装 n Weld(reference implementation) 利⽤しているランタイム – Wildfly / JBoss

    EAP – Open Liberty / WebSphere Liberty – WebLogic – GlassFish – Payara n Apache OpenWebBeans 利⽤しているランタイム – Apache TomEE 9
  8. 10 Injectionの仕組み n CDIでは多くの場合オブジェクトを直接代⼊するのではなく, Proxyを動的に⽣成して代⼊する – beanのメソッド呼出しはProxyによってdelegateされて実⾏される – これによりコンテクスチュアルな動作やライフサイクルの管理を実現している n

    この動的にProxyを作成する機能がGraalVMでは使⽤できないため,CDI liteが作成された – 動的機能を使わない範囲でCDIと同等の機能を可能な限り提供するのがCDI lite 10 Beanのインスタンス Beanのインスタンス Inject先の変数 Inject先の変数 Beanを継承したProxy ×直接代⼊するのではない Proxy経由で代⼊ 作成したManaged Bean
  9. 12 CDIによる注⼊が⾏われるのは n CDI管理Beanのインスタンスをnewで⽣成しても,注⼊は⾏われない n CDIの注⼊は,以下のタイミングで⾏われる 1. 指定されたJava EEのコンポーネントがロードされるとき 2.

    注⼊される管理BeanがCDIコンテナで⽣成されるとき 3. CDI.current()で取得したCDIインスタンス経由で管理Beanのオブジェクトを取得した場合 CDI<Object> cdi = CDI.current(); MyService service = cdi.select(MyService.class).get(); @Inject private HttpSession session; Servlet HttpSession @Inject private MyService service; Servlet @Inject private DataSource ds; 管理Bean DataSouce @Inject private DataSource ds; 管理Bean DataSouce
  10. 13 CDIで注⼊が⾏われるJava EE/Jakarta EEのコンポーネント 13 仕様 コンポーネント Servlet • servlet

    • servlet filter • event listener • HTTP upgrade handler JSP • tag handler • tag library event listener JSF • managed class (詳細は JSF の仕様の "JSF Managed Classes and Java EE Annotations" を参 照) JAX-WS • service endpoint • handler JAX-RS • JAX-RS component (CDI管理の場合) 仕様 コンポーネント WebSocket • endpoint EJB • bean Interceptor • interceptor Java Persistence • entity listener Managed Beans • managed bean CDI • CDI-style managed bean • decorator Java EE Platform • main class (static) • login callback handler * 仕様名はJava EEのもの 例︓ JAX-RS(Java EE) → Jakarta RESTful Web Service(Jakarta EE)
  11. 14 CDI管理Bean n CDI管理Bean (CDI-style Managed Bean) は, 以下の全て条件を満たすJavaクラスである –

    コンクリートなJavaクラス(インターフェスや,abstractクラスでない)であるか または,@Decorator が付与されている – パラメーターなしのコンストラクターを持つ,または@Inject が付与されたコンストラクターを持つ – non-static なインナー・クラスでない – EJB として定義されていない – javax.enterprise.inject.spi.Extension を実装し ていない – @Vetoed が付与されていない, @Vetoed が付与されたパッケージ内に存在しない n CDI管理Beanは,特殊なJavaのクラスではない 14
  12. 15 beanの発⾒︓Bean Discovery Mode n CDIが,アーカイブ(JAR/WAR)からBeanを発⾒するためのモード – JARファイル︓ META-INF/beans.xmlで指定 –

    WARファイル︓ WEB-INF/beans.xmlまたはWEB-INF/classes/META-INF/beans.xmlで指定 n annotatedモード(デフォルト,推奨) – 以下の場合,annotatedモードでbeanの検索が⾏われる • アーカイブ内にbeans.xmlが存在しない • アーカイブ内にバージョン1.1以降のbeans.xmlが存在し,bean-discovery-modeがannotated – セッションBeanとBean定義アノテーションが付与されたCDI管理Beanがbeanとして認識される • Bean定義アノテーション: スコープを指定するアノテーション,@Dependent,@Interceptor,@Decorator,ステレオタイプのアノテーション n allモード – 以下の場合,allモードでbeanの検索が⾏われる • アーカイブ内に空のbeans.xmlが存在する • アーカイブ内にバージョン指定のないbeans.xmlファイルが存在する • アーカイブ内にバージョン1.1以降のbeans.xmlが存在し,bean-discovery-modeがall – セッションBeanと全てのCDI管理Beanがbeanとして認識される(意図しないクラスもbeanとして扱われる危険が) n noneモード – 以下の場合,noneモードになり,beanの検索は⾏われない • アーカイブ内にバージョン1.1以降のbeans.xmlが存在し,bean-discovery-modeがnone 15 基本的にこれで利用する
  13. 16 注⼊は,まずBean Typeの⼀致によって⾏われる n CDI管理BeanのデフォルトのBean Type – ⾃⾝のタイプ – 親クラスのタイプ

    – 実装したインターフェースのタイプ – Object タイプ n セッションBeanのデフォルトのBean Type – 実装したインターフェースのタイプ – Object タイプ n @TypedアノテーションでBean Typeを限定できる – 例:@Typed({ BookShop.class, Business.class } ) 16 @Dependent @Typed(BookShop.class) public class BookShopImpl extends Business implements BookShop { ・・・・・・ } @Inject private BookShop shop; @Inject private Business business; 型が合うので注⼊できる 親クラスなのでデフォルトでは注⼊できるが @Typedで限定されているので注⼊できない ×
  14. 18 限定⼦(Qualifier)の定義⽅法(1) n 限定⼦は@Qualifierアノテーションを使⽤して定義する 18 import static java.lang.annotation.ElementType.FIELD; import static

    java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; @Qualifier @Retention(RUNTIME) @Target({METHOD, FIELD, PARAMETER, TYPE}) public @interface Synchronous {} 限定⼦ Synchronous を定義している例 • @Qualifier で,限定⼦であることを宣⾔ • @Target で, METHOD, FIELD, PARAMETER および TYPE に付与できるアノテーションであることを宣⾔ • @Retention(RUNTIME) で,実⾏時までアノテーション情報が残ることを宣⾔ • @Inherited は指定していない(サブクラスには継承されないように宣⾔) 限定⼦の定義例
  15. 19 限定⼦(Qualifier)の定義⽅法(2) n メンバー(プロパティー)を持つ限定⼦も定義できる 19 import static java.lang.annotation.ElementType.FIELD; import static

    java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; @Qualifier @Retention(RUNTIME) @Target({METHOD, FIELD, PARAMETER, TYPE}) public @interface PayBy { PaymentMethod value(); } メンバーを持つ限定⼦の定義例 限定⼦ PayBy を定義している例 • メンバー(プロパティー)にアクセスするための メソッド value() を追加 • この例では,メンバーの型を enum を利⽤して定義 • その他はメンバーを持たない限定⼦と同様 public enum PaymentMethod { CASH, CREDIT_CARD, CHEQUE } @Dependent @Asynchronous @PayBy(PaymentMethod.CASH) class AsynchronousCachPaymentProcessor implements PaymentProcessor { ・・・・・・ } 限定⼦の使⽤例
  16. 20 組み込みの限定⼦︓@Any, @Default, @New n @Any • javax.enterprise.inject パッケージ –

    全ての bean に暗黙的に付与される限定⼦ – @New 限定⼦が付与された場合のみ消える n @Default • javax.enterprise.inject パッケージ – 全ての bean に暗黙的に付与される限定⼦ (デフォルト限定⼦) – @Named以外の限定⼦が付与されると消える n @New • javax.enterprise.inject パッケージ – CDI 1.1 以降では⾮推奨(deprecated) – CDI 1.1 以降では @Dependent が付与されていると解釈される 20 @Dependent public class Order { ・・・・・・ } @Dependent @Asynchronous public class AsynchronousPaymentProcessor implements PaymentProcessor { ・・・・・・ } • @Anyと@Defaultの2つの限定⼦が 付与されて いることになる • @Anyと@Asynchronousの2つの 限定⼦が付与されていることになる • @Default は除去される
  17. 21 組み込みの限定⼦︓ @Named n @Named • javax.inject パッケージ – bean

    名を指定する限定⼦ (bean に名前を付ける限定⼦) • 例:@Named("userInfo") – bean 名は,JSF faceletsやJSPからbeanにアクセスするため に使⽤(EL から bean にアクセスするために使⽤) – ユーザー定義の限定⼦と違い,型チェックが⾏われないため タイプミスなどをコンパイル時に検出できないので注意 (そのため,あまり利⽤は推奨されない) n デフォルトのbean名 (@Named のみを指定した場合の bean 名) – CDI 管理 Bean 最初を⼩⽂字にしたクラス名 – セッション Bean 最初を⼩⽂字にしたクラス名 – プロデューサー・メソッド メソッド名 (getter の場合はプロパティー名) – プロデューサー・フィールドフィールド名 – 注⼊操作の場合 注⼊先のフィールド名, パラメーター名 21
  18. 23 スコープ n beanのスコープを定義することで、 beanをコンテキストに関連付け、bean のライフサイクルを管理できる – 必要な時に⾃動的にbeanを作成し、コンテキストが終了する時に⾃動的にbeanを破棄する – 同じコンテキスト内では、同じbeanが共有される

    / 異なるコンテキストでは異なるbeanが⽤意される – コンテクスチュアル(Contextual)な動作が実現できる n 以下の4つのスコープが定義されている • javax.enterprise.context パッケージ内のアノテーションで指定する – @Dependentは疑似スコープ(pseudo scope)で,コンテクスチュアルな動作にならない 23 アノテーション スコープ java.io.Serializable @RequestScoped 1回の HTTP リクエストの範囲 @ConversationScoped 複数回の HTTP リクエストの範囲 開発者が開始と終了を制御 実装が必要 @SessionScoped 1つの HTTP セッションの範囲 実装が必要 @ApplicationScoped 1つのアプリケーションの範囲 @Dependent 注⼊先ごとにインスタンスが作成され、 注⼊先の変数と同じスコープを持つ
  19. 24 コンテクスチュアルな動作 n 例えば,HttpServletのインスタンス変数は, 複数ユーザーの複数リクエスト間で共有されるが, この変数に注⼊された@SessionScopedのbeanは,CDIコンテナによって ユーザーのHTTPセッションごとに異なるインスタンスが作成されて, Proxyが正しいインスタンスにメソッド実⾏をdelegateする n また逆に,異なるクラスの異なる変数に注⼊が⾏われても,

    同⼀スコープであれば同⼀のインスタンスが利⽤される 24 public class PaymentServlet extends HttpServlet { @Inject ShoppingCart cart; …… } @SessionScoped public class ShoppingCart implements Serializable { …… } cart Proxy ShoppingCartの インスタンス ShoppingCartの インスタンス ShoppingCartの インスタンス
  20. 25 スコープの制限 n セッション Bean の場合は、使⽤できるスコープが限定される – StatefulセッションBean 任意のスコープ –

    StatelessセッションBean @Dependentのみ – SingletonセッションBean @ApplicationScopedまたは@Dependent n スコープを持つCDI管理Beanの実装では、コンテクスチュアルな動作を実現するための Client Proxyを⽣成するために以下の制約が追加される – パラメーターを持たない、private 以外のデフォルト・コンストラクターを持つ – クラスがfinalでない (サブクラスが作成できる) – public, protectedまたはdefault-accessの⾮staticなメソッドがfinalでない (メソッドがオーバーライドできる) – publicなフィールドが存在しない (フィールド値の変更はメソッド経由でのみ実⾏できる) 25
  21. 26 Conversationスコープの制御 n Conversation (CDI コンテナーが提供する組み込み Bean の1つ)を注⼊ • javax.enterprise.context

    パッケージ n Conversationのbegin()/end()メソッドを呼び出して、Conversationスコープを開始/停⽌ 26
  22. 27 beanのインスタンス⽣成 n CDI コンテナーは管理Beanのコンストラクターを 呼び出して bean のインスタンスを作成する n 管理

    Bean のコンストラクター – default-access, public, protected または private なコンストラクターが使⽤される – @Inject アノテーションが付与された コンストラクターが優先的に使⽤される – 存在しない場合は、デフォルト・コンストラクター (パラメーターなしのコンストラクター)が使⽤される n パラメーターの注⼊ – パラメーターを持つ場合は CDIコンテナーが呼び出し時に注⼊する – パラメーターには限定⼦を付与できる 27
  23. 28 初期化メソッド (Initializer Methods) n CDI コンテナーはbeanのインスタンスを作成し、 フィールドに注⼊を⾏った後に、 初期化メソッドを呼び出す –

    初期化メソッド内では、 注⼊されたフィールドを使⽤できる n 初期化メソッド – @Inject を付与して定義 – 複数個定義できる (定義しなくても良い) – default-access, public, protectedまたはprivateで、 non-abstract, non-static, non-generic なメソッド – セッション Bean の場合は、interfaceに公開された ビジネス・メソッドである必要はない n パラメーターの注⼊ – パラメーターを持つ場合は CDIコンテナーが呼び出し時に注⼊する – パラメーターには限定⼦を付与できる 28
  24. 29 コールバック・メソッド: PostConstruct n 「Dependency Injection for Java」で規定 n @PostConstruct

    アノテーションを付与して定義 • javax.annotation パッケージ n CDI コンテナーは bean の初期化メソッドの実⾏後に、 PostConstructメソッドを呼び出す n PostConstructメソッド – default-access, public, protected または private で、 non-abstract, non-static なメソッド – 「void <メソッド名>() 」の形式 – @PostConstruct を付与できるメソッドは1つのみ n パラメーターの注⼊は⾏われない 29
  25. 30 コールバック・メソッド: PreDestroy n 「Dependency Injection for Java」で規定 n @PreDestroyアノテーションを付与して定義

    • javax.annotation パッケージ n CDIコンテナーはbeanを破棄する直前に、 PreDestroy メソッドを呼び出す n PreDestroy メソッド – default-access, public, protected または private で、 non-abstract, non-static なメソッド – 「void <メソッド名>() 」の形式 – @PreDestroy を付与できるメソッドは1つのみ n パラメーターの注⼊は⾏われない 30
  26. 32 プロデューサーとディスポーザー n プロデューサー – コンストラクターで⽣成できないオブジェクトなどを CDIのbeanとして扱いたい時に使⽤する • オブジェクトはCDI管理Beanで無くても良い •

    オブジェクトの実装型が動的に変わっても良い • 特殊な初期化処理が必要なオブジェクトでも良い – beanのファクトリーとしての役割を持つ – Java EE のリソースやコンポーネントを @Inject で注⼊する場合にも使⽤する n ディスポーザー – プロデューサーが返したオブジェクトの クリーンナップ処理を⾏いたい時に使⽤する 32 @Inject private BookShop shop; @ ApplicationScoped public class BookShopImpl extends Business implements BookShop { ・・・・・・ } CDIコンテナが インスタンスを⽣成して注⼊する public class BusinessFactory { @Produces @ApplicationScoped public BookShop createShopBook() { ・・・・・・ } プロデューサーが提供する インスタンスを注⼊する
  27. 33 プロデューサー・メソッド n 注⼊されるオブジェクトを返すメソッド n プロデューサー・メソッドの定義 – @Producesアノテーションを付与 • javax.enterprise.inject

    パッケージ – スコープを定義するアノテーションや, @Namedなどの限定⼦を付与可能 – CDI管理BeanまたはセッションBeanのメソッド • default-access, public, protected または private で,static または non-static なメソッド – メソッドの戻り値の型で Bean Type が決まる n プロデューサー・メソッドのパラメーターの注⼊ – パラメーターを持つ場合は CDIコンテナーが呼び出し時に注⼊する – パラメーターには限定⼦を付与できる 33 public class OrderFactory { @Produces @ConversationScoped public Order createCurrentOrder( Shop shop, @Selected Product product ) { Order order = new Order(product, shop); return order; } } • スコープが定義されたオブジェクトを返す例 • パラメーターshopとproductが注⼊される • Bean TypeはOrderとなる
  28. 34 注⼊ポイントのメタデータ (Injection Point Metadata) n CDIコンテナーは,beanが注⼊されたポイントのメタデーターを提供 – メタデータの型はInjectionPoint •

    javax.enterprise.inject.spi パッケージ n プロデューサー・メソッドの引数に指定すると, CDIコンテナから提供される – 通常のCDI管理Beanでも,InjectionPoint型の変数に @Injectさせることで利⽤可能 – ただし,注⼊先のBeanのスコープは@Dependentでないと いけない n ⽤途の例 34 @Produces Logger createLogger( InjectionPoint injectionPoint ) { return Logger.getLogger( injectionPoint.getMember().getDeclaringClass().getName() ); } ログ出⼒⽤の bean を返す,プロデューサー・メソッドでの利⽤例 public interface InjectionPoint { public Type getType(); public Set<Annotation> getQualifiers(); public Bean<?> getBean(); public Member getMember(); public Annotated getAnnotated(); public boolean isDelegate(); public boolean isTransient(); } InjectionPoint の定義
  29. 35 ディスポーザー・メソッド n プロデューサー・メソッドやフィールドが返した オブジェクトのクリーンナップ処理を実装できるメソッド n ディスポーザー・メソッドの定義 – CDI管理BeanまたはセッションBeanのメソッド •

    default-access, public, protectedまたはprivateで,staticまたはnon-staticなメソッド – パラメーターにクリーンナップするオブジェクトを1つだけ指定する • プロデューサー・メソッドの戻り値の型やプロデューサー・フィールドの型に合致する必要がある • 限定⼦も加味される – パラメーターに @Disposes アノテーションを付与 • javax.enterprise.inject パッケージ 35 public class UserDatabaseEntityManager { @Produces @ConversationScoped @UserDatabase public EntityManager create(EntityManagerFactory emf) { return emf.createEntityManager(); } public void close(@Disposes @UserDatabase EntityManager em ) { em.close(); } } • プロデューサー・メソッドと ディスポーザー・メソッドの例 • 両者とも,EntityManager型の オブジェクトを処理する • 両者とも,ユーザー定義の限定⼦ @UserDatabaseが付与されている
  30. 36 プロデューサー・フィールド n 注⼊されるオブジェクトを⽰すフィールド – プロデューサー・メソッドの簡易版 n プロデューサー・フィールドの定義 – @Producesアノテーションを付与

    • javax.enterprise.inject パッケージ – スコープを定義するアノテーションや、 @Named など の限定⼦を付与可能 – CDI管理Beanまたは セッションBeanのフィールド • default-access, public, protected または private フィールド • セッション Bean の場合は、 static なフィールドでなければならない – フィールドの型でBean Typeが決定 36 public class Shop { @Produces @ApplicationScoped @Catalog @Named("catalog") List<Product> products = ....; • スコープが定義された例 • 限定⼦として、@Namedと ユーザー定義の@Catalogが付与されている • Bean TypeはList<Product>となる
  31. 37 Java EE リソースやコンポーネントの注⼊ n Java EE リソースやコンポーネントを注⼊する場合 – プロデューサー・フィールドに

    Java EE リソースやコンポーネントを注⼊するためのアノテーションを付与する – 同じ型のリソースなどは、限定⼦を付与して区別する 37 public class AppResources { @Produces @WebServiceRef( lookup="java:app/service/PaymentService" ) PaymentWebService paymentWebService; @Produces @EJB( ejbLink="../their.jar#PaymentService" ) PaymentEjbService paymentEjbService; @Produces @Resource( lookup="jdbc/CustomerDatasource" ) @CustomerDatabase Datasource customerDatabase; @Produces @PersistenceContext( unitName="CustomerDatabase" ) @CustomerDatabase EntityManager customerPersistenceContext; @Produces @PersistenceUnit( unitName="CustomerDatabase" ) @CustomerDatabase EntityManagerFactory customerPersistenceUnit; } @Inject PaymentWebService paymentWeb; @Inject PaymentEjbService paymentEjb; @Inject @CustomerDatabase Datasource custDb; @Inject @CustomerDatabase EntityManager custEm; @Inject @CustomerDatabase EntityManagerFactory custEmf;
  32. 39 インターセプター (Interceptor) と デコレーター(Decorator) n 両者とも処理を差し込むために使⽤できるが、 ⽤途が異なる n インターセプター

    (Interceptor) – メソッド呼び出しやライフサイクル・イベントが 発⽣した時に、クロスカティング(横断的)タスクを 差し込むための機能 – AOP (Aspect Oriented Programming)で使⽤し、 ビジネス・ロジックの実装には使⽤しな い n デコレーター(Decorator) – メソッド呼び出しが発⽣した時に、 ビジネス・ロジックを差し込んだり カスタマイズするための機能 – ビジネス・ロジックの実装に使⽤する 39
  33. 40 インターセプター (Interceptor) n メソッド呼び出しやライフサイクル・イベントが発⽣した時に、 クロスカティング(横断的)タスクを差し込むための機能 – AOP (Aspect Oriented

    Programming) で使⽤し、ビジネス・ロジックの実装には使⽤しない – ログ出⼒、監査、プロファイリングなど、アプリケーション内で繰り返し現れる処理を実装するために使⽤する n ライフサイクルとコンテキスト – インターセプターは、関連付けられたオブジェクトと同じライフサイクルを持つ – メソッド呼び出しのインターセプターは、関連付けられたメソッドと同じコンテキストで呼び出される – ライフサイクル・イベントのインターセプターが呼び出されるコンテキストは規定されていない n インターセプターも CDI 管理 Bean なので、@Inject で他の bean を注⼊できる n 複数のインターセプターの優先度は@Priorityで指定する 40
  34. 41 インターセプターの利⽤ n インターセプターを使⽤する場合は、以下の流れで 開発を⾏う 1. インターセプター・バインディング・タイプを定義する • @InterceptorBindingを利⽤して独⾃アノテーションを定義 2.

    インターセプターを実装する • @Interceptorアノテーションとバインディング・タイプを指定したクラスを実装 3. インターセプターを対象に関連付ける • インターセプターの対象となるクラスやメソッドにバインディング・タイプを付与 4. インターセプターを有効にする • beans.xmlファイルにインターセプターを登録する n 詳細な実装⽅法は割愛 41
  35. 42 デコレーター (Decorator) n メソッド呼び出しが発⽣した時に、 ビジネス・ロジックを差し込んだりカスタマイズするための機能 n デコレーターの実装 – @Decorator

    アノテーションを付与 – デコレートするbeanと同じBean Typeを持つ • デリゲーション・オブジェクトと同じ Bean Type を持つ – @Inject と @Delegate でデコレートする bean を注⼊ • デリゲーション・オブジェクトを1つだけ注⼊ • コンストラクターや初期化メソッドで注⼊することも可能 – 全てのビジネス・ロジックを実装しなくても良い • abstract なクラスでも良い – デコレーターも CDI 管理 Bean なので、他の必要なbeanを注⼊できる n beans.xmlにデコレーターのクラスを登録 42
  36. 44 その他のCDIの機能(1) n bean の Programmatic Lookup – オブジェクトTを直接注⼊するのではなくInstance<T>を注⼊ –

    注⼊された側でInstance<T>から条件にあわせたオブジェクトを取得 n 代替(Alternative)実装と特殊化(Specialization) – 通常は使⽤せず,テストでのみ使⽤するbeanを代替(Alternative)として定義できる – beans.xmlの記述で切り替えることが可能 – 多くのクラスを⼀⻫に代替実装に切り替える⽅法として,特殊化(Specialization)が利⽤可能 n イベント通知 – bean間でイベントの送受信を⾏う – CDI が提供する Event<?>を注⼊して,それ経由でイベントの送信を⾏う – オブサーバーメソッドを定義してイベントの受信を⾏う n ステレオタイプ – 共通の役割を持つ(同じアノテーションを付与される)beanに対して, カプセル化された共通のアノテーションを提供する
  37. 45 その他のCDIの機能(2) n 除外フィルター – 注⼊するbeanの対象から外すクラスを,beans.xmlに指定できる – 指定したクラスが存在する場合,しない場合や,指定したシステムプロパティの値などを条件に設定できる n CDI拡張

    – Beanの検索やライフサイクルの管理などを柔軟に拡張することができる – Extensionを実装しMETA-INF/services/javax.enterprise.inject.spi.Extensionに登録して利⽤する n プログラムによるインターセプターの制御 – 通常はbeans.xmlで定義するインターセプターの制御を,アプリケーションからおこなうことができる 45