レベルエンター山本大のブログ

面白いプログラミング教育を若い人たちに

BLOCKVROCKリファレンス目次はこちら

Guice vs. SpringJavaConfig (3) A Knight's tour of Spring JavaConfig

A Knight's tour of Spring JavaConfigSpring JavaConfigにおける騎士ツアー

Like Guice, Spring JavaConfig enables you to configure an application's objects in Java code using annotations. But their approaches to dependency injection are vastly different.

To get started, I needed to create a configuration class. In Spring JavaConfig, any class that is annotated with @Configuration can serve as a JavaConfig configuration. Here's the knight example's KnightConfig.java:


GuiceやSpringJavaConfigなどでは、アノテーションをつかったJavaコードで、アプリケーションのオブジェクトを設定することができます。しかしながら、それらDependency Injectionのアプローチは、まったく異なります。では、騎士のサンプルのKnightConfig.javaファイルを見て行きましょう。

package com.springinaction.chapter01.knight;

import org.springframework.beans.factory.annotation.Bean;
import org.springframework.beans.factory.annotation.Configuration;
import org.springframework.beans.factory.annotation.SpringAdvice;
import org.springframework.context.ApplicationContext;
import org.springframework.context.java.AnnotationApplicationContext;

@Configuration
public class KnightConfig {
  @Bean
  public Knight knight() {
    KnightOfTheRoundTable knight = 
        new KnightOfTheRoundTable("Bedivere");
    knight.setQuest(quest());
    return knight;
  }

  @Bean
  public Quest quest() {
    return new HolyGrailQuest();
  }
  
  @Bean
  @SpringAdvice("execution(* *.embarkOnQuest(..))")
  public MinstrelInterceptor minstelAdvice() {
    return new MinstrelInterceptor();
  }
  
  public static void main(String[] args) throws Exception {
    ApplicationContext ctx = 
        new AnnotationApplicationContext(KnightConfig.class);
    Knight knight = (Knight) ctx.getBean("knight");
    knight.embarkOnQuest();
  }
}

(Again, I've placed the main() method in KnightConfig as a convenience. You may or may not want to do this in a real-world application.)

At first glance, you may think that KnightConfig is analogous to the Guice example's KnightModule. It's true, that both serve as the central configuration artifact for both resources. But take a look a little closer and you'll see that they're quite different. More specifically, KnightConfig is more explicit in its configuration than the Guice example's KnightModule.


(またまた、便利さのためにKnightConfigクラスにmain()メソッドを置くことにしました。実際のアプリケーションではそんなことはやらないかもしれませんが。。。)

まずは一見して、KnightConfigは、GuiceのサンプルにあったKnightModuleと似てると思われることでしょう。確かに、それらは共にそれぞれの情報の設定を集中管理するためのものです。
しかし、すこしじっくりと見てみると、まったく違うことがわかります。もっと正確にいえば、KnightConfigは、その設定がGuiceのサンプルのKnightModuleに比べて、より明示的です。

For example, notice the first method in KnightConfig is simply called knight() and it returns a Knight. This method is annotated with @Bean and is, in fact, the complete set of instructions for how Spring JavaConfig should create and inject a bean named "knight" in the Spring container. In short, it will create a new instance of KnightOfTheRoundTable, passing in "Bedivere" as its constructor argument. Then it will call the setQuest() method to wire a Quest into the quest property. The actual quest used is a reference to the quest() method.


たとえば、KnightConfigの最初のメソッドは、単純にknight()メソッドをコールしていて、Knightを返していることに注意してみてください。この@Beanによってアノテートされているメソッドは、実はSpringのコンテナのなかで、Spring JavaConfigがどのように"knight"というBeanを作り、インジェクトするかを完全な指示のセットといえます。ようするに、KnightOfTheRoundTableのインスタンスを作ろうとした場合、コンストラクター引数として"Bedivere" を引き渡すようにできます。それから、Questをそのquestプロパティに紐付けるためにsetQuest()メソッドを呼び出します。

Similarly, the quest() method is also annotated with @Bean and simply returns an instance of HolyGrailQuest.

The method names give the bean its ID, while the value returned is the type. Everything that happens in the method defines how the bean is configured. Therefore, taken together, the knight() and quest() methods are roughly equivalent to the following Spring XML configuration:


同様に、quest()メソッドも、@Beanでアノテートされており単純にHolyGrailQuestのインスタンスを返します。

メソッドは、Beanに与えられた自身のIDで名づけられます。その上、値を返すのはその型です。メソッドで発生するすべては、Beanがどのように設定されるかを定義しています。それゆえ、それらをもとに
knight()とquest()メソッドは Spring XMLコンフィグレーションとおおよそ同じといえます。

<bean id="knight" class="com.springinaction.chapter01.knight.KnightOfTheRoundTable"> 
    <constructor-arg value="Bedivere" />
    <property name="quest" ref="quest" /> 
</bean>
<bean id="quest" class="com.springinaction.chapter01.knight.HolyGrailQuest" /> 

I should also mention that because all of the configuration takes place directly in Java code, it's quite easy to inject references into regular methods...not just constructors and setters. Similarly, it's no problem to add conditional and looping logic in your configuration, which is something that pure Spring XML cannot do.


すべての設定は直接Javaコードで置き換えることができるということにも言及するべきでしょう。コンストラクタやセッターだけではなく、通常のメソッドを参照してインジェクトする事は、とても簡単です。
同様に、設定の中に条件や繰り返し処理を追加することもまったく問題がありません。これらは純粋なSpringXMLではできないことです。

It's also important to realize that Spring JavaConfig is not mutually exclusive to Spring XML configuration. You can easily use both in the same application by configuring the @Configuration-annotated classes as beans in Spring XML and then wiring an org.springframework.beans.factory.java.ConfigurationPostProcessor in your Spring XML. In trying to create an XML-free example, however, I've not exploited the mix-n-match of JavaConfig with XML here.


Spring JavaConfigとSpring XMLコンフィグレーションは、互いに排他的な関係ではないことも知って置くべき重要なことです。両方の方法を同じアプリケーションで利用するのも簡単です。
@ConfigurationアノテーションでアノテートされたクラスをSpringXMLでのBeanとし、それからSpringXMLの中で、org.springframework.beans.factory.java.ConfigurationPostProcessorと紐付けします。
ためしに、XMLフリーのサンプルを作ってみましょう。しかしながら、ここではJavaConfigとXMLを混合して不当に使うことはしません。

And, in case you're wondering, Spring's special wiring features, such as autowiring, lazy-loading, init-methods, etc, are all still available as attributes to the @Bean and @Configuration annotations. It's beyond the scope of this article to go into any great detail, but the knight() method could be redefined as follows to be autowired by type:


それから念のため、Springの特別な紐付けの機能(自動紐付けや、レイジーローディングや、初期化メソッドなどのようなもの)は、@Beanと@Configurationアノテーションの属性としても、すべて利用可能です。それについての詳細を深追いするのは、この記事の範囲を超えてしまいますが、 knight()メソッドは型によって自動的に紐付けするために、以下のように再定義できます。

@Bean(autowire=Autowire.BY_TYPE)
public Knight knight() {
  KnightOfTheRoundTable knight = 
      new KnightOfTheRoundTable("Bedivere");

  // no need to wire in a Quest...it'll be auto-wired
  return knight;
}


As with the Guice example, I'll come back to see how the minstrel advice is wired in. First, however, let's see what else needs to be done with KnightOfTheRoundTable and HolyGrailQuest for Spring JavaConfig to wire them together.


Guiceサンプルのように、minstrel(吟遊詩人)のAOPアドバイスを紐付ける方法を見るために戻りましょう。しかしながら、初めにKnightOfTheRoundTable とHolyGrailQuest をSpring JavaConfigによって結びつけるのに、その他に何が必要であるかについてみてみましょう。

Oh wait...actually, there's nothing special that needs to be done with either of those classes. They're perfectly suitable for wiring with Spring JavaConfig, just as they would be using Spring XML. Unlike Guice, Spring JavaConfig keeps its annotations confined to the configuration classes. So I guess I can go ahead and talk about how to use AOP with Spring JavaConfig.


ちょっとまって、実施に、それらのクラスで処理される必要がある特別なものは何もありません。それらはSpring JavaConfigを使って紐付けするのに完璧に適しています。ちょうど、Spring XMLと使うのと同じように。Guiceとは異なり、Spring JavaConfigはアノテーションをコンフィグレーションクラスに閉じ込めたままにしておきます。なので、Spring JavaConfigを使ってAOPを使う方法の説明にすすみましょう。