JavaEE6のCDIのProducer Methodで動的DI

以前からJSR-330(Dependency Injection for Java)を勉強しようと思っていて、何かサンプル的なものがないか探していたのですが・・・結局のところ、JSR-330をいちばん手っ取り早く覚えられるのはJSR-299(Contexts and Dependency Injection for the JavaTM EE platform)略してCDIのようです。
てなわけで、CDIのRIであるJBoss Weldを少し触ってみました。
http://docs.jboss.org/weld/reference/1.0.0/en-US/html/index.html
のWeldのドキュメントが詳しくてとても解りやすいです。
読んでいく中で興味を引かれたのが、CDIのProducer Methodという機能。これは大雑把に言うと、管理対象Bean上で、気軽に他の管理対象Beanを生成するメソッドを実装できるという機能です。

@SessionScoped
@Named
public class Login implements Serializable {

    private User user;
    
    public void login() {
      user = ...
    }
    
    public void logout() {
      user = null;
    }
    
    public boolean isLoggedIn() {
       return user != null;
    }
    
    @Produces
    public User getCurrentUser() {
        return user;
    }

}

これはWeldのサンプルを簡単に略したものですが、このようにLoginオブジェクトでユーザオブジェクトを作成し、そのユーザを返すgetterメソッドに対して@Producesを定義した場合、このuserオブジェクトを他のオブジェクトにDIできるようになります。

@RequestScoped
@Named
public class Hoge {

	@Inject
	private User user;
	
	public User getUser() {
		return user;
	}
}

みたいな形で。
これの何が良いかというと、動的にDI対象オブジェクトを決定するロジックをかなり簡単に定義できるようになるってことですね。この例ではユーザ情報をDIしていますが、例えばログインユーザの種別毎に何か違ったロジックを動かしたい場合、JPAの継承を使ってユーザのクラスを変えたりとか、ユーザ情報から動的に利用したいストラテジーを決定してそれをDIしたりとか・・・みたいな処理を容易く実装できるようになります。
今までのDIコンテナは、実装とインターフェイスを分離して、実装を決定する部分をファイルに外出ししたりすることで「実装の切り替えが容易になる」と謳っていました。・・・が実際には、実装をソース上でnewするのと、ファイルに書き出すのとでは「コンパイルしなくても切り替えられる」以外にあまり利点を見出すことが出来ませんでした。Webアプリケーションの場合、その外出ししたファイルもwar内に固めて一緒にデプロイするので、単にコンパイルチェックできない記述が増えただけになってしまい、逆にデメリットが増えてしまった感すらありました。
そういった設定ファイル地獄を解消する為に、規約を利用したDI対象オブジェクトの自動決定機能が使われるようになりましたが、規約通りに定義しないとめんどくさい→複数実装を登録すると自動決定出来なくなって規約から外れる→基本的に実装を一つしか登録しなくなる・・・という流れが起こってしまいました。またファイルにしろ規約による自動定義にしろ、どちらも「デプロイ時には対象オブジェクトは決定されている」ことが前提であって、動的に実装を切り替えるにはDI対象から外してFactoryを使うか、ファイル上で簡易言語を記述して何とかする・・・ぐらいしか主な手段がありませんでした。これらによってDIコンテナの利用者は益々「実装を切り替える」という理想からは遠ざかってしまい・・・結局のところ、今までのDIコンテナ利用者の多くは、DI機能だけでメリットを見出すことは難しく、AOP機能の土台として利用していただけに過ぎなかった気がします。
でもこのCDIなら、開発者が手軽にオブジェクトのファクトリーを定義してどんどん使っていくことが出来るため、元々DIコンテナで謳っていた「オブジェクトを手軽に切り替える」ことがとても容易に実現できます。本当の意味で、DIによってJavaのプログラミングを大きく変えることが出来る時代がやってきた・・・のかもしれません。
このProducer Method機能以外にも、気になる機能としてはDisposer Method機能があります。これはProducer Method機能で作成した管理Beanが属するスコープが終了するときに、後処理を呼び出すことが出来る機能です。これを上手く使えば、今のJavaの言語にはない、RubyC#のブロックによる終了処理のようなリソースの開放処理を、もっと気軽に管理できるようになるかも・・・
正直言って今まであまり期待していなかったCDIですが、実際調べてみると結構使えそうな気がします。少なくとも今現在DIコンテナを利用した開発を行っている人なら、CDI利用を検討してみる価値は十分あるんじゃないかと感じました。