放課後プログラミング

調べたことや考えたことなどを忘れないために書きます。

Spring Framework 4.0によるDI

pom.xml

Mavenを使えば必要なjarファイルをサイトからダウンロードしてclasspathの通っているディレクトリに置いたりといった作業をxmlを書くという作業で済ませられる。そのMavenの設定ファイルであるpom.xmlに必要なspring frameworkのjarをダウンロードするように書くには以下のようにすればよい。
今回はSpring Framework 4.0.3を使った例です。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>di_example</groupId>
    <artifactId>di_example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <spring.version>4.0.3.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

</project>

beans.xml

DIの設定はbeans.xmlに書く。このファイルはsrc/main/resourcesの下のどこかに置けば問題ない。
アノテーションを使って自動で注入する実装クラスを探させたいので、各beanの設定をbeans.xmlに記述する必要はなく、コンポーネントスキャンするパッケージのルートを書くだけでいい。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- base-package=""の中は要編集 -->
    <context:component-scan base-package="diexample"/>
    <context:annotation-config/>

</beans>

DependencyInjectionExample.java

beans.xmlの読み込んでbeanを取得してsayHello()を呼び出してる。

public class DependencyInjectionExample {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        HelloWorld helloWorld = ctx.getBean(HelloWorld.class);
        helloWorld.sayHello();
    }
}

HelloWorld.java

component-scanの対象パッケージ以下のクラスで@Componentと書くとSpringのDIコンテナにbeanが登録される。beanが登録されるとは要するにSpringがそのクラスのインスタンスを管理下に置くようなものだと思う。
@Qualifierによって注入させる実装クラスを指定していて、コンポーネントスキャンされるパッケージ以下にIHelloインターフェースの実装クラスが複数あるときは@Qualifierで指定しないとエラーが出る。一つしかない場合は自動で検出してくれるので@Qualifierアノテーションは必要ない。

@Component
public class HelloWorld {

    @Autowired
    @Qualifier(value = "HelloImpl2")
    private IHello hello;

    public void sayHello() {
        hello.sayHello();
    }
}

IHello.java

このインターフェースを変数宣言の型に使うことで(HelloWorld.java6行目の話)実装クラスとの依存性が解消される。
これがDIによって実装クラスを注入させて嬉しいところだと思う。

public interface IHello {
    public void sayHello();
}

HelloImpl1.java

一つ目の実装クラスで、今回はこの実装クラスは使っていない。
HelloWorld.java@Qualifier(value = "HelloImpl1")と書けば使える。

@Component
@Qualifier(value = "HelloImpl1")
public class HelloImpl1 implements IHello {

    public void sayHello() {
        System.out.println("Hello");
    }
}

HelloImpl2.java

今回はこの実装クラスがIHello型の変数に注入される。

@Component
@Qualifier(value = "HelloImpl2")
public class HelloImpl2 implements IHello {

    public void sayHello() {
        System.out.println("another Hello");
    }
}

必要なコードは以上。

DependencyInjectionExample.main

の実行結果は

another Hello

となる。

このようにDIを使うと、使いたい実装クラスが変わったとしてもHelloWorld.javaのロジック自体を編集する必要がなくなる。
ひとまず適当な実装を作っておいて(スタブや少しバグってる実装等)あとで本番に使う実装を切り替えるときなどに楽になると思います。