BeanManagerでCDIコンテナにアクセスする

CDI拡張モジュールを作る上でコンテナが管理する情報を取得・操作できたら便利です。今回はそれを可能にするBeanManagerについて紹介します。これは、今までCDI拡張モジュールのインタフェースでたびたび登場していたけど、説明をさぼっていたものです。

BeanManagerとは

BeanManagerは拡張モジュールからコンテナにアクセスするときに使うもので、これを使うことでBean、インターセプタ、デコレータを取得することができます。

BeanManagerを取得するには、Beanのクラス内において

@Inject BeanManager manager;

のようにインジェクションするだけです。

BeanManagerは次のような機能を提供します。

メタデータ関連

  • AnnotatedTypeを生成する
  • InjectionTargetを生成する

イベント関連

  • イベントを発行する

Bean関連

  • Beanを取得する
  • Beanリファレンスを取得する
  • CreationalContextを生成する
  • コンテキストを取得する

アノテーション関連

  • アノテーション定義を取得する
  • インターセプタバインディング定義
  • ステレオタイプ定義
  • 各種アノテーションの判別(限定子か否か、NormalScopeか否か, etc.)

依存性解決関連

  • Beanを特定する
  • デコレータを特定する
  • インターセプタを特定する
  • デコレータを特定する

メソッドの概要を表1にまとめます。正確な定義はJavaDocを参照してください。

表1:CDI 1.0 BeanManager
戻り値 メソッド 概要
AnnotatedType<T> createAnnotatedType(Class<T> type) 指定されたクラスまたはインタフェースのアノテーションを読むために利用できるAnnotatedTypeを取得する
CreationalContext<T> createCreationalContext(Contextual<T> contextual) 指定されたcontextualタイプまたは非contextualオブジェクトのためにcreationalContextを取得する
InjectionTarget<T> createInjectionTarget(AnnotatedType<T> type) 指定されたAnnotatedTypeのためのInjectionTargetを取得する
void fireEvent(Object event, Annotation… qualifiers) イベントを発火し、オブザーバに通知する
Set<Bean<?>> getBeans(String name) EL名レゾリューション規則に従って、指定されたEL名に対応するBeanのセットを返す
Set<Bean<?>> getBeans(Type beanType, Annotation… qualifiers) タイプセーフ・レゾリューション規則に従って、指定されたタイプと限定子に対応するBeanのセットを返す
Context getContext(Class<? extends Annotation> scopeType) 指定されたスコープタイプのアクティブなコンテキストを取得する
javax.el.ELResolver getELResolver() EL名によってBeanを特定するELResolverを返す
Object getInjectableReference(InjectionPoint ij, CreationalContext<?> ctx) 指定されたインジェクションポイントのためにインジェクション可能なリファレンスを取得する
Set<Annotation> getInterceptorBindingDefinition(Class<? extends Annotation> bindingType) 指定されたインターセプタバインディングタイプのためのメタアノテーションのセットを取得する
Bean<?> getPassivationCapableBean(String id) 指定されたIDを持つPassivationCapableBeanを返す
Object getReference(Bean<?> bean, Type beanType, CreationalContext<?> ctx) 指定されたBeanとBeanタイプのためのコンテキスト参照を取得する
Set<Annotation> getStereotypeDefinition(Class<? extends Annotation> stereotype) 指定されたステレオタイプのメタアノテーションを取得する
boolean isInterceptorBinding(Class<? extends Annotation> annotationType) 指定されたアノテーションがインターセプタバインディングか否か
boolean isNormalScope(Class<? extends Annotation> annotationType) 指定されたアノテーションがNormalScopeか否か
boolean isPassivatingScope(Class<? extends Annotation> annotationType) 指定されたアノテーションがPassivatingScopeか否か
boolean isQualifier(Class<? extends Annotation> annotationType) 指定されたアノテーションが限定子か否か
boolean isScope(Class<? extends Annotation> annotationType) 指定されたアノテーションがScopeか否か
boolean isStereotype(Class<? extends Annotation> annotationType) 指定されたアノテーションがステレオタイプか否か
Bean<? extends X> resolve(Set<Bean<? extends X>> beans) 曖昧な依存性解決規則を指定されたBeanのセットに対して適用する
List<Decorator<?>> resolveDecorators(Set<Type> types, Annotation… qualifiers) タイプのセットと限定子のセットのためのデコレータのリストを返す
List<Interceptor<?>> resolveInterceptors(InterceptionType type, Annotation… interceptorBindings) インターセプタバインディングとインターセプションのタイプのためのインターセプタのリストを返す
Set<ObserverMethod<?super T> resolveObserverMethods(T event, Annotation… qualifiers) イベントのためのオブザーバのリストを返す
void validate(InjectionPoint injectionPoint) 指定されたインジェクションポイントの妥当性を検証する
javax.el.ExpressionFactory wrapExpressionFactory(javax.el.ExpressionFactory expressionFactory) 指定されたExpressionFactoryのラッパーを返す。それはMethodExpressionとValueExpressionの生成をExpressionFactoryに移譲する。

コンテナが管理するBeanの取得

BeanManagerを使ってデプロイされたBeanにアクセスしてみましょう。以下のコードではすべてのBeanを集めてプリントします。


 @Inject

 private BeanManager beanManager;

 // ...

 Set<Bean<?>> beans = beanManager.getBeans(Object.class, new AnnotationLiteral<Any>(){});

 for (Bean<?> bean: beans) {

 System.out.println("bean=" + bean.getBeanClass().getSimpleName() +

 ", scope=" + bean.getScope().getSimpleName());

 }

これをWeldのexamples/jsf/login内で実行した結果は次の通り。このブログの過去の記事で作成したMyBeanやMyApplicationContext、それからContextRegistrationのような拡張モジュールまでWeld実装内部ではBeanとして管理されていることがわかります。
22:50:39,042 INFO  [stdout] (http--127.0.0.1-8080-1) bean=InjectionPoint,scope=Dependent
22:50:39,043 INFO  [stdout] (http--127.0.0.1-8080-1) bean=MyBean2,scope=Dependent
22:50:39,043 INFO  [stdout] (http--127.0.0.1-8080-1) bean=Validator,scope=Dependent
22:50:39,043 INFO  [stdout] (http--127.0.0.1-8080-1) bean=ValidatorFactory,scope=Dependent
22:50:39,044 INFO  [stdout] (http--127.0.0.1-8080-1) bean=MyApplicationContext,scope=Dependent
22:50:39,044 INFO  [stdout] (http--127.0.0.1-8080-1) bean=MyBean,scope=MyApplicationScoped
22:50:39,044 INFO  [stdout] (http--127.0.0.1-8080-1) bean=ContextRegistration,scope=ApplicationScoped
22:50:39,045 INFO  [stdout] (http--127.0.0.1-8080-1) bean=ManagedBeanUserManager,scope=RequestScoped
22:50:39,045 INFO  [stdout] (http--127.0.0.1-8080-1) bean=InstanceImpl,scope=Dependent
22:50:39,046 INFO  [stdout] (http--127.0.0.1-8080-1) bean=Resources,scope=Dependent
22:50:39,046 INFO  [stdout] (http--127.0.0.1-8080-1) bean=Conversation,scope=RequestScoped
22:50:39,046 INFO  [stdout] (http--127.0.0.1-8080-1) bean=Principal,scope=Dependent
22:50:39,047 INFO  [stdout] (http--127.0.0.1-8080-1) bean=EventImpl,scope=Dependent
22:50:39,047 INFO  [stdout] (http--127.0.0.1-8080-1) bean=UserTransaction,scope=Dependent
22:50:39,048 INFO  [stdout] (http--127.0.0.1-8080-1) bean=ManagedBeanUserManager,scope=RequestScoped
22:50:39,048 INFO  [stdout] (http--127.0.0.1-8080-1) bean=Login,scope=Dependent
22:50:39,049 INFO  [stdout] (http--127.0.0.1-8080-1) bean=BeanManagerImpl,scope=Dependent
22:50:39,049 INFO  [stdout] (http--127.0.0.1-8080-1) bean=Resources,scope=Dependent
22:50:39,049 INFO  [stdout] (http--127.0.0.1-8080-1) bean=User,scope=Dependent
22:50:39,050 INFO  [stdout] (http--127.0.0.1-8080-1) bean=Login,scope=SessionScoped
22:50:39,050 INFO  [stdout] (http--127.0.0.1-8080-1) bean=Resources,scope=Dependent
22:50:39,050 INFO  [stdout] (http--127.0.0.1-8080-1) bean=Credentials,scope=RequestScoped