3.13. Additional Capabilities of the ApplicationContext

概要

ApplicationContextは、BeanFactoryの機能に以下が追加されている

  • MessageSource (リソースバンドル)
  • ResourceLoader (URLやファイルリソース)
  • ApplicationListener (イベント配信)
  • HierarchicalBeanFactory (コンテナ間の連携?)

3.13.1 Internationalization using MessageSource

ApplicationContextは自分に登録されているbeanをなめてMessageResourceを実装したものからリソースを集めてくる。Springのデフォルトでの実装は、ResourceBundleMessageSource とStaticMessageSource。

ResourceBundleMessageSource
リソースバンドルです。


<beans>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>format</value>
<value>exceptions</value>
<value>windows</value>
</list>
</property>
</bean>
</beans>

basenameに指定したリソース名でリソースバンドルが読み込まれる。こんな感じだね。


# in exceptions.properties
argument.required=The '{0}' argument is required.

StaticMessageSource
殆ど使わない。プログラムから指定

MessageSourceは外からはこう使う。


public static void main(String[] args) {
MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
String message = resources.getMessage("message", null, "Default", null);
System.out.println(message);
}

MessageSourceをインジェクションもできます。当然。ちなみにReloadableResourceBundleMessageSource というのもあるらしい。リロードするんだろうね・・

3.13.2 Standard and Custom Events

ApplicationContextにイベントが配信されると、該当するコンテナに登録されたApplicationListenerを実装するBeanが全部呼び出される。
#これ強力だなぁ。。。

基本的なイベント:

  • ContextRefreshedEvent :コンテキストが初期化もしくはrefleshされたあと。ちなみに厳密にはsingletonのBean初期化フックが呼ばれたあとくらい?
  • ContextStartedEvent  :コンテキスト開始後。Lifecycleが呼ばれた後くらい?
  • ContextStoppedEvent  :コンテキスト終了後。
  • ContextClosedEvent  :コンテキスト破棄後。singletonが全部破棄された後。
  • RequestHandledEvent  :HTTPリクエストの処理が終わった後で呼ばれる。

#TODO:ライフサイクルをもうちょっと掘り下げること

自分独自のカスタムイベントも作れます!


public class BlackListEvent extends ApplicationEvent {
private final String address;
private final String test;

public BlackListEvent(Object source, String address, String test) {
super(source);
this.address = address;
this.test = test;
}

// accessor and other methods...
}

イベント配信はこんな感じでApplicationEventPublisherを使う。


public class EmailService implements ApplicationEventPublisherAware {

private List blackList;
private ApplicationEventPublisher publisher;

public void setBlackList(List blackList) {
this.blackList = blackList;
}

public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}

public void sendEmail(String address, String text) {
if (blackList.contains(address)) {
BlackListEvent event = new BlackListEvent(this, address, text);
publisher.publishEvent(event);
return;
}
// send email...
}
}

リスナーはこんな感じ。


public class BlackListNotifier implements ApplicationListener {

private String notificationAddress;

public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}

public void onApplicationEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
}

ApplicationEventPublisherを使うと、すべてのイベント処理は同期的に実施される。つまりシングルスレッドで実施される。マルチスレッドで配信する場合はApplicationEventPublisherを使ってください。

3.13.3 Convenient access to low-level resources

Chapter 4, Resourcesをみれ。

3.13.4 Convenient ApplicationContext instantiation for web applications

ContextLoaderを使うと、ApplicationContextを宣言的に生成できる。ContextLoaderの仕組みは以下の二つに分かれる。

  • ContextLoaderListener
  • ContextLoaderServlet

やることはどっちも一緒。サーブレットバージョンの下位互換のためにサーブレットがあるだけ。理想的なのはContextLoaderListenerを使うやり方。まぁ具体的にはこうするわけだ



contextConfigLocation
/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml


org.springframework.web.context.ContextLoaderListener

3.13.5 Deploying a Spring ApplicationContext as a J2EE RAR file

RAR(リソースアダプタ?)としてデプロイすることができる。うーん、、、そもそもRARって良く解らん