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"));
}