Slide 1

Slide 1 text

1 JJUG(⽇本Javaユーザー会) Java仕様勉強会 2023年9⽉ CDI: Contexts and Dependency Injection ⽇本IBM ⽥中 孝清 (Twitter @TTakakiyo)

Slide 2

Slide 2 text

2 ⾃⼰紹介 2 n ⽥中 孝清 n ⽇本アイ・ビー・エム株式会社 オートメーションソフトウェア テクニカルセールス n WebSphere Application Serverなどの テクニカルセールスを20年以上担当 n Twitter @TTakakiyo

Slide 3

Slide 3 text

3 3 CDIとは Contexts and Dependency Injection

Slide 4

Slide 4 text

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)を付与

Slide 5

Slide 5 text

5 n DI(Dependency injection, 依存性の注⼊)とは – コンポーネント間の依存関係をプログラムのソースコードから排除し, 外部の設定ファイルなどで注⼊できるようにするソフトウェアパターンである – 依存関係がプログラムから外部に取り除かれることで,以下のようなメリットが発⽣する • 結合度の低下によるコンポーネント化の促進 • 単体テストの効率化 • 特定のフレームワークへの依存度低下 – 出典: Wikipedia n 従来のJNDIによるlookupによるオブジェクトの取得や,Factoryクラス経由の取得に⽐べて, より簡潔に記述でき,柔軟に挙動を制御することができる n CDI は,DIの機能に加えて, コンポーネントであるbeanのライフサイクル・コンテキストの管理機能を提供 – Contexts beanのライフサイクルをライフサイクル・コンテキストに関連付ける – Dependency Injection beanのインスタンスをインジェクション(注⼊)する 5 Contexts and Dependency Injectionの役割

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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の基本機能の完成

Slide 8

Slide 8 text

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仕様に分割

Slide 9

Slide 9 text

9 CDIの実装 n Weld(reference implementation) 利⽤しているランタイム – Wildfly / JBoss EAP – Open Liberty / WebSphere Liberty – WebLogic – GlassFish – Payara n Apache OpenWebBeans 利⽤しているランタイム – Apache TomEE 9

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

11 11 CDIによるInjection Dependency Injection

Slide 12

Slide 12 text

12 CDIによる注⼊が⾏われるのは n CDI管理Beanのインスタンスをnewで⽣成しても,注⼊は⾏われない n CDIの注⼊は,以下のタイミングで⾏われる 1. 指定されたJava EEのコンポーネントがロードされるとき 2. 注⼊される管理BeanがCDIコンテナで⽣成されるとき 3. CDI.current()で取得したCDIインスタンス経由で管理Beanのオブジェクトを取得した場合 CDI 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

Slide 13

Slide 13 text

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)

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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 基本的にこれで利用する

Slide 16

Slide 16 text

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で限定されているので注⼊できない ×

Slide 17

Slide 17 text

17 限定⼦(Qualifier) n 注⼊候補が複数あるとき, 限定⼦を付けることで対象を選ぶことができる 17

Slide 18

Slide 18 text

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 は指定していない(サブクラスには継承されないように宣⾔) 限定⼦の定義例

Slide 19

Slide 19 text

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 { ・・・・・・ } 限定⼦の使⽤例

Slide 20

Slide 20 text

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 は除去される

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

22 22 ライフサイクル Life cycle

Slide 23

Slide 23 text

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 注⼊先ごとにインスタンスが作成され、 注⼊先の変数と同じスコープを持つ

Slide 24

Slide 24 text

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の インスタンス

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

26 Conversationスコープの制御 n Conversation (CDI コンテナーが提供する組み込み Bean の1つ)を注⼊ • javax.enterprise.context パッケージ n Conversationのbegin()/end()メソッドを呼び出して、Conversationスコープを開始/停⽌ 26

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

31 31 プロデューサーと ディスポーザー Producer / Disposer

Slide 32

Slide 32 text

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() { ・・・・・・ } プロデューサーが提供する インスタンスを注⼊する

Slide 33

Slide 33 text

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となる

Slide 34

Slide 34 text

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 getQualifiers(); public Bean> getBean(); public Member getMember(); public Annotated getAnnotated(); public boolean isDelegate(); public boolean isTransient(); } InjectionPoint の定義

Slide 35

Slide 35 text

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が付与されている

Slide 36

Slide 36 text

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 products = ....; • スコープが定義された例 • 限定⼦として、@Namedと ユーザー定義の@Catalogが付与されている • Bean TypeはListとなる

Slide 37

Slide 37 text

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;

Slide 38

Slide 38 text

38 38 インターセプターと デコレーター Interceptor / Decorator

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

40 インターセプター (Interceptor) n メソッド呼び出しやライフサイクル・イベントが発⽣した時に、 クロスカティング(横断的)タスクを差し込むための機能 – AOP (Aspect Oriented Programming) で使⽤し、ビジネス・ロジックの実装には使⽤しない – ログ出⼒、監査、プロファイリングなど、アプリケーション内で繰り返し現れる処理を実装するために使⽤する n ライフサイクルとコンテキスト – インターセプターは、関連付けられたオブジェクトと同じライフサイクルを持つ – メソッド呼び出しのインターセプターは、関連付けられたメソッドと同じコンテキストで呼び出される – ライフサイクル・イベントのインターセプターが呼び出されるコンテキストは規定されていない n インターセプターも CDI 管理 Bean なので、@Inject で他の bean を注⼊できる n 複数のインターセプターの優先度は@Priorityで指定する 40

Slide 41

Slide 41 text

41 インターセプターの利⽤ n インターセプターを使⽤する場合は、以下の流れで 開発を⾏う 1. インターセプター・バインディング・タイプを定義する • @InterceptorBindingを利⽤して独⾃アノテーションを定義 2. インターセプターを実装する • @Interceptorアノテーションとバインディング・タイプを指定したクラスを実装 3. インターセプターを対象に関連付ける • インターセプターの対象となるクラスやメソッドにバインディング・タイプを付与 4. インターセプターを有効にする • beans.xmlファイルにインターセプターを登録する n 詳細な実装⽅法は割愛 41

Slide 42

Slide 42 text

42 デコレーター (Decorator) n メソッド呼び出しが発⽣した時に、 ビジネス・ロジックを差し込んだりカスタマイズするための機能 n デコレーターの実装 – @Decorator アノテーションを付与 – デコレートするbeanと同じBean Typeを持つ • デリゲーション・オブジェクトと同じ Bean Type を持つ – @Inject と @Delegate でデコレートする bean を注⼊ • デリゲーション・オブジェクトを1つだけ注⼊ • コンストラクターや初期化メソッドで注⼊することも可能 – 全てのビジネス・ロジックを実装しなくても良い • abstract なクラスでも良い – デコレーターも CDI 管理 Bean なので、他の必要なbeanを注⼊できる n beans.xmlにデコレーターのクラスを登録 42

Slide 43

Slide 43 text

43 43 その他の機能 Others

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

45 その他のCDIの機能(2) n 除外フィルター – 注⼊するbeanの対象から外すクラスを,beans.xmlに指定できる – 指定したクラスが存在する場合,しない場合や,指定したシステムプロパティの値などを条件に設定できる n CDI拡張 – Beanの検索やライフサイクルの管理などを柔軟に拡張することができる – Extensionを実装しMETA-INF/services/javax.enterprise.inject.spi.Extensionに登録して利⽤する n プログラムによるインターセプターの制御 – 通常はbeans.xmlで定義するインターセプターの制御を,アプリケーションからおこなうことができる 45

Slide 46

Slide 46 text

46 以下のURLからお申し込みください https://ibm.biz/ComMeetup2023