DI/AOP

DI:Dependency Injection 別名:IoC(Inversion of Control) DI = インタフェース指向 + Reflection

コンテナの主な目的:インスタンスのサイクルの管理(作成・廃棄)

DI種類:

Constructor Injection

Property Injection

Method Injection

AOP:Aspect Oriented programming

AOP応用

1.Authentication

2.Cache

3.Context passing

4.Error handling

5.Lazy loading

6.Debug

7.Log

8.tracing, profiling and monitoring

9.Performance optimization

10.Persistence

11.Resource pooling

12.Synchronization

13.Transactions

14.Exception

15.Security

AOP説明図

DI/AOPコンテナ

Java系:Spring, Seaserなど

C#系:Spring.NET, Seaer.NET, Ninjectなど

※懸念:性能が落ちるのを意識。

★DIコンテナの注意点

複数のリクエストでインスタンスが共有されるクラスには、インスタンス変数を書いていけない

インスタンス変数を書くならば、そのインスタンスはリクエストごとに生成しよう

SpringもSeasar2も、デフォルトではクラスのインスタンスをSingletonになる

リクエストごとに異なるインスタンスを生成する設定:

Spring 2.x

<bean id="sample" class="jp.co.sample" scope="prototype" />

Seasar2

<component name="sample" class="jp.co.sample" instance="prototype" />

DI方法(Java)

●コンストラクタ インジェクション

public Person{

private Car car;

public Person(Car car){

this.car = car;

}

public void drive(){

this.car.something();

}

}

//------------------------------------------------

CarImpl car = new CarImpl();

Person p = new Person(car);

p.drive();

Springを使う場合

beam.xml

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN"

"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<bean id="oneCar" class="CarImpl">

</bean>

<bean id="onePerson" class="Person">

<constructor-arg>

<ref bean="oneCar" /> ※引用

或いは

<bean class="CarImpl" /> ※新規new

</constructor-arg>

複数引数の場合

<constructor-arg index="0" value="123" />

<constructor-arg index="1" value="abc" />

</bean>

</beans>

//------------------------------------------------

BeanFactory factory=new XmlBeanFactory("bean.xml");

Person boy=(Person)factory.getBean("onePerson");

boy.drive();

以下はSeaser.NETによるDI/AOPの説明ですが、伝える思想が大事。

・「DI」サンプル

改善前

namespace Test

{

interface IHello

{

string HelloMessage();

}

class Hello : IHello

{

private string name;

public Hello(string name)

{

this.name = name;

}

#region IHello Members

public string HelloMessage()

{

return "Hello " + this.name;

}

#endregion

}

class Program

{

IHello hello;

public Program()

{

hello = new Hello("Mike");

}

public void ShowHello()

{

Console.WriteLine(hello.HelloMessage());

}

}

}

・「AOP」サンプル

改善前

namespace Test

{

class Sample

{

private string prefix;

public Sample(string prefix)

{

this.prefix = prefix;

}

public string GetHelloMessage(string name)

{

string preName = prefix + "." + name;

return "Hello " + preName;

}

}

class Program

{

public Program()

{

Sample sample = new Sample("Mr");

Console.WriteLine("Pre Process");

Console.WriteLine(sample.GetHelloMessage("Mike"));

Console.WriteLine("Post Process");

}

}

}

●属性 インジェクション

public Person{

private Car car;

public Person(){ }

public void drive(){

this.car.Something();

}

public void setCar(Car car){

this.car = car;

}

public Car getCar(){

return this.car;

}

}

//------------------------------------------------

CarImpl car = new CarImpl();

Person p = new Person();

p.setCar(car);

p.drive();

Springを使う場合

beam.xml

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN"

"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<bean id="oneCar" class="CarImpl">

</bean>

<bean id="onePerson" class="Person">

<property name="car">

<ref bean="oneCar" />

</property>

或いは

<property name="car" ref="oneCar" />

</bean>

</beans>

//------------------------------------------------

BeanFactory factory=new XmlBeanFactory("bean.xml");

Person boy=(Person)factory.getBean("onePerson");

boy.drive();

改善後

Injection.dicon

<?xml version="1.0" encoding="utf-8" ?>

<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd">

<components>

<component name="hello" class="Test.Hello">

<arg>"Mike"</arg>

</component>

</components>

コードの改善箇所

public Program()

{

Seasar.Framework.Container.IS2Container container

= Seasar.Framework.Container.Factory.S2ContainerFactory.Create("Injection.dicon");

hello = (IHello)container.GetComponent("hello");

}

改善後

追加クラス

public class SampleInspector

: Seasar.Framework.Aop.Interceptors.AbstractInterceptor

{

public override object Invoke

(Seasar.Framework.Aop.IMethodInvocation invocation)

{

string methodName = invocation.Method.DeclaringType.Name

+ "." + invocation.Method.Name;

Console.WriteLine("Pre Process");

Console.WriteLine("開始 " + methodName);

object ret = invocation.Proceed();

Console.WriteLine("終了 " + methodName);

Console.WriteLine("Post Process");

return ret;

}

}

Aspect.dicon

<?xml version="1.0" encoding="utf-8" ?>

<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN" "http://www.seasar.org/dtd/components.dtd">

<components>

<component name="SampleInspector" class="Test.SampleInspector" />

<component class="Test.Sample">

<arg>"Mr"</arg>

<aspect pointcut="GetHelloMessage">SampleInspector</aspect>

</component>

</components>

コードの改善箇所

public Program()

{

Seasar.Framework.Container.IS2Container container

= Seasar.Framework.Container.Factory.S2ContainerFactory.Create("Aspect.dicon");

Sample sample = (Sample)container.GetComponent(typeof(Sample));

Console.WriteLine(sample.GetHelloMessage("Mike"));

}