支援対象地域:札幌、仙台、関東、愛知、関西、広島、福岡


はじめに

Springは、Javaでアプリケーションを作成する上で欠かすことのできないフレームワークです。 Springの中心的な機能であるDIxAOPのうちDIについてご紹介します。。

以下の内容をご紹介します。



(1)DI

DIは、「依存性の注入」と呼ばれ、インターフェースを利用した部品化を実現するものです。
依存性のある外部プログラムを取り入れることで、オブジェクト間の依存を取り除くということです。



DIを実現するには、次の3種類があります。

《DIの実現方法》
  1. アノテーションを用いたDI
  2. XML形式のBean定義ファイルを用いたDI
  3. Javaプログラムを用いたDI

1-1 アノテーションを用いたDI

DIコンテナに登録したいクラス宣言の前に@Componentアノテーションを追加します。また、DIコンテナに注入したいインスタンス(変数、メソッド、コンストラクタ)宣言の前に@Autowiredを記述します。
ただし、DIを有効にするには、XML形式のBean定義ファイルJavaプログラムと併用する必要があります。

1-2 XML形式のBean定義ファイルを用いたDI

「1-1 アノテーションを用いたDI」は、小規模開発で非常に便利です。しかし、大規模開発ではXML形式のBean定義ファイルを利用してDI管理を行います。XML形式のBean定義ファイル名は、「applicationContext.xml」とするのが慣習です。
XML形式でBean定義を行うことで、アノテーションをクラスやインスタンスに記述しなくてもDIを実現できるようになります。
また、「1-1 アノテーションを用いたDI」と「Bean定義ファイルを用いたDI」を併用することもよくあります。

1-3 Javaプログラムを用いたDI

DIを実現するためのJavaプログラムをJavaConfigといいます。 「1-2 XML形式のBean定義ファイル」と比べて、JavaConfigはJavaプログラムなので、タイプセーフ(クラス名などの誤りをコンパイルで検知できる)です。
JavaConfigは、1人で開発を行う場合に便利ですが、大規模開発でも使えます。XML形式によるBean定義ファイルかJavaConfigかは、コードの可読性や保守性を考えて選択することが重要です。

「1-1 アノテーションを用いたDI」のサンプルコードをご紹介します。 各クラスの階層関係は、次のようになります。

【各クラスの階層関係】


<!-- applicationContext.xml 
		アノテーションを有効にするためのxml形式のBean定義ファイル-->

<?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">
  <context:annotation-config />
  <context:component-scan base-package="sample.di.business" />
  <context:component-scan base-package="sample.di.dataaccess" />
</beans>	

//プレゼンテーション層パッケージ
package sample;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import sample.di.business.domain.DataRegister;
import sample.di.business.service.DataCall;

//コントローラの代わとしてmain()メソッドを実行する
public class SampleRun {

	public static void main(String[] args) {
		SampleRun sampleRun = new SampleRun();
		sampleRun.execute();
	}

	@SuppressWarnings("resource") //DIを実現するアノテーションではない
	public void execute() {
		String path = "/sample/config/applicationContext.xml";
		BeanFactory ctx = new ClassPathXmlApplicationContext(path);

		DataCall dataCall = ctx.getBean(DataCall.class);
		dataCall.addProduct(new DataRegister("ペン", 100));
		DataRegister dataRegister_Pen = dataCall.findByProductName("ペン");

		System.out.println(dataRegister_Pen);
	}
}

//ビジネスロジック層(サービス)パッケージ
package sample.di.business.service;

import sample.di.business.domain.DataRegister;

//インタフェース
//プレゼンテーション層からサービスを呼び出す
public interface DataCall {
	void addProduct(DataRegister dataRegister);
	DataRegister findByProductName(String name);
}

//ビジネスロジック層(サービス)パッケージ
package sample.di.business.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import sample.di.business.domain.DataRegister;

//DataCallインタフェースの実装クラス
@Component //DIコンテナに登録
public class DataCallImpl implements DataCall {
	@Autowired //DIコンテナに注入したいインスタンス
	private DataMap dataMap;

	@Override
	public void addProduct(DataRegister dataRegister) { dataMap.addProduct(dataRegister); }

	@Override
	public DataRegister findByProductName(String name) { return dataMap.findByProductName(name); }
}	

//ビジネスロジック層(サービス)パッケージ

package sample.di.business.service;

import sample.di.business.domain.DataRegister;

//インタフェース
//データアクセス層とやり取りする
public interface DataMap {
	void addProduct(DataRegister dataRegister);
	DataRegister findByProductName(String name);
}

//ビジネスロジック層(ドメイン)パッケージ
package sample.di.business.domain;

//サービスから呼び出されたらサービスにデータを返す
public class DataRegister {
	private String name;
	private int price;

	public DataRegister(String name , int price) {
		this.name = name;
		this.price = price;
	}

	public String getName() { return name; }

	public int getPrice() { return price; }

	@Override //DIを実現するアノテーションではない
	public String toString(){ return "name=" + name +", price=" + price; }
}

//データアクセス層パッケージ
package sample.di.dataaccess;

import java.util.HashMap;
import java.util.Map;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import sample.di.business.domain.DataRegister;
import sample.di.business.service.DataMap;

//データベースの代わりとしてMapを利用
@Component //DIコンテナに登録
public class DataMapImpl implements DataMap {
	private Map<String, DataRegister> storage = new HashMap<String , DataRegister>();

	@Override
	public DataRegister findByProductName(String name) { return storage.get(name); }

	public void addProduct(DataRegister dataRegister) { storage.put(dataRegister.getName(), dataRegister); }
}
実行結果
name=ペン, price=100


まとめ

DI概要」についてご紹介しました。
お役に立てると幸いです。