金曜日, 4月 05, 2013

Spring 基本のキホン

Spring

Springを上手く使いこなすことができれば,DI/IOCをエレガントにこなすことが出来る.オブジェクトの初期化やインスタンス生成でぐちゃぐちゃしたコードを書きたくない,テスト用DIをスマートに行いたい,JDBCやHibernate等をもう少し綺麗に書きたい,と思っておれば是非Springを試してみてほしい.

Spring サンプル

Springの基礎を丁寧に解説しているページはネットにゴマンとあるので,ここでは基本のキホンのサンプルと簡略な説明にとどめておく.

このサンプルでは4つのクラス,1つのインターフェース,1つのコンテクストxmlを使用する.

まずは土台となるBeanIFインタフェースとSpringSampleクラス.
DIに適用するクラスはテスト用・実働用に別のクラスを注入できるようにするため,インターフェース又は抽象クラスであるべき.

BeanIF.java 

public interface BeanIF {

int getInstanciationCounter();
String getMessage();

}

SpringSample.java


import javax.annotation.Resource;

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

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

@Component("sample")
@Scope("prototype")
public class SpringSample implements BeanIF {

private static int instanciationCounter = 0;

@Autowired
private Injectee inject;

@Resource
private Injectee2 inject2;

public SpringSample() {
instanciationCounter++;
}

public int getInstanciationCounter() {
return instanciationCounter;
}

public void getMessage() {
return inject.showMessage() + ":" + inject2.showMessage();
}

}


上記クラスでは4つのアノテーションを使っている.
Component .. Spring Bean Management Frameworkで管理されるPojoに汎用的に使われる.
                   Controller,Repository,ServiceもSpring Mojoとしてクラスをマークするが用途は違う. 
Scope .. Singletonは最初のPojo登録の時にのみクラスは初期化される.prototypeはgetBean()されるたびに別のインスタンスが帰ってくる.
Autowired .. 型が合致又は継承又はインターフェース実現クラスであれば自動的に注入.requiredパラメータを使えばautowiringが失敗した場合の挙動も制御できる.Spring由来.
Resource .. Autowiredの条件+PojoのIdが合致する場合に注入.JSR250由来.Autowired + QualifierはResourceとほぼ同様の振る舞いになる.

次にInjecteeとinjectee2 - それぞれautowired又はResourceでDIされる - を見てみる.


@Component("inject")
public class Injectee {

public void showMessage() {
                return "Injected.";
}

}


@Component("inject2")
public class Injectee2 {

public String showMessage() {
        return "injectee2";
}

}



Componentアノテーションによりこれら2つのクラスもまたSpringにより管理化に置かれる.
ではどのようにこのアノテーションドリブンによるPojoの検索・登録がおこなわれるのか.
キーはcontext.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">

    <context:annotation-config/>
    <context:component-scan base-package="myapp.package" />

</beans>


context:annotation-configでautowired等のアノテーションを有効にし,context:component-scanにて指定されたパッケージ以下をSpringがスキャンし,Componentアノテーション等でマークアップされたクラスを登録し,autowiring等も行う.contextネームスペースを使う際,xmlns.contextをbeansタグに追加することを忘れないこと.

これでPojoの用意及び依存性注入も出来たはずなので,実際以下のテストクラスを使って試してみる.


import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import static org.hamcrest.CoreMatchers.*;

/**
 * Unit test for simple App.
 */
public class SpringSampleTest {

static ApplicationContext ctx = null;

@BeforeClass
public static void prep() {
ctx = new ClassPathXmlApplicationContext( "spring/context.xml" );
}

@Test
public void testBase() {
SpringSample sample = (SpringSample)ctx.getBean( "sample" );
sample = (SpringSample)ctx.getBean( "sample" );
assertThat( sample.getMessage(), is( "injectee:injectee2" ) );
assertThat( sample.getInstanciationCounter(), is( 2 ) );
}

}

テストが成功すれば,依存性注入も成功し,prototypeの挙動も確認できていることとなる.
Springは結構丁寧なロギングをしているので,もしその情報を見たければlog4j又はslf4j api + slf4j-log4j12を使う必要がある.

0 件のコメント: