JAvaフレームワーク編---spring IOC実現原理

15035 ワード

IOC(DI):実はこのSpringアーキテクチャの核心の概念はこんなに複雑ではなく、一部の本で説明されているように難解ではありません.javaプログラマーはjavaプログラムの各業務ロジックには少なくとも2つ以上のオブジェクトが協力して完成する必要があることを知っています.通常、各オブジェクトは彼の協力オブジェクトを使用するとき、自分でnew objectのように使用します.()このような文法は、協力対象者の申請作業を完了するために用いられる.オブジェクト間の結合度が高くなっていることがわかる.IOCの考えは、Springコンテナがこれらの相互依存対象者の作成・協調作業を実現することである.オブジェクトは関係業務ロジックそのものであればよい.この点から、オブジェクトがどのように協力対象者を得るかの責任は逆転される(IOC、DI).SpringのIOCに対する私の体験です.DIは実はIOCのもう一つの言い方です.DIはMartin Fowlerが2004年初頭の論文で初めて提出したものです.彼は、コントロールの何が逆転されたのかということをまとめました.依存対象を得る方法が逆転したということです.この核心概念がまだ理解されていない場合は、ここではブロモンというブログで見つけた浅い表現を引用しますわかりやすい答え:
IoCとDI
まずIoCについてお話ししたいと思います(Inversion of Control、制御逆転).これはspringの核心であり、一貫して貫かれている.IoCとは、springフレームワークにとって、springが対象のライフサイクルと対象との関係を制御することである.これはどういう意味なのか、簡単な例を挙げると、私たちはどのように彼女を探しているのか.よく見られるのは、どこがきれいで体がきれいで、はいmm、それから彼女たちの趣味、qq号、電話番号、ip号、iq号......、方法を考えて彼女たちを知って、その好きなものを送って、それからへへ......この過程は複雑で奥深くて、私たちは自分で設計してすべての一環に直面しなければなりません.従来のプログラム開発でも、1つのオブジェクトで別のオブジェクトを使用する場合は(自分でnewするか、JNDIから1つ検索する)、使用後はオブジェクトを破棄(Connectionなど)し、オブジェクトは常に他のインタフェースやレンコンと結合しています.
ではIoCはどのようにして作られたのでしょうか.結婚相談で彼女を探しているように、私と彼女の間に第三者:結婚紹介所を導入しました.婚介は多くの男女の資料を管理して、私は婚介に1つのリストを提出することができて、それに私がどんな彼女を探したいかを教えて、例えば李嘉欣に似ていて、体は林熙雷のようで、歌は周杰倫のようで、スピードはカルロスのようで、技術はジダンのようで、それから婚介は私たちの要求に従って、mmを提供して、私达は彼女と恋をするだけで、結婚すればいい.簡単明瞭で、結婚紹介者が私たちに与えた人選が要求に合わなければ、私たちは異常を投げ出すことになります.全体の過程は私自身がコントロールするのではなく、結婚仲介のような容器のような機構がコントロールしています.Springが提唱している開発方式は、すべてのクラスがspringコンテナに登録され、springに何が必要なのか、何が必要なのかを教え、springはシステムが適切に動作している間に、あなたが望んでいるものを自分から渡し、同時に他のあなたが必要なものに渡します.すべてのクラスの作成、破棄はspringによって制御されます.つまり、オブジェクトのライフサイクルを制御するのは、参照されるオブジェクトではなくspringです.特定のオブジェクトでは、以前は他のオブジェクトを制御していたが、現在はすべてのオブジェクトがspringによって制御されているため、制御反転と呼ばれています.もしあなたがまだ分からないなら、私は諦めることにしました.
IoCの1つのポイントは、システムの実行中に、あるオブジェクトに必要な他のオブジェクトを動的に提供することです.この点はDI(Dependency Injection、依存注入)で実現されます.たとえば、オブジェクトAはデータベースを操作する必要があります.以前は、常にAでコードを自分で作成してConnectionオブジェクトを得る必要がありました.springがあれば、springに伝えるだけです.AにはConnectionが必要です.このConnectionがどのように構築され、いつ構築されるかは、Aは知る必要はありません.システムの実行時、spring適切なタイミングでConnectionを作り、注射のようにAに注射することで、各オブジェクト間の関係の制御が完了します.Aは正常に動作するにはConnectionに依存する必要がありますが、このConnectionはspringによってAに注入され、依存注入の名前はこのように来ています.ではDIはどのように実現したのでしょうか.Java 1.3以降の重要な特徴は反射です(reflection)は、プログラムが実行されている間に動的にオブジェクトを生成したり、オブジェクトを実行したりする方法、オブジェクトの属性を変更したりすることを可能にし、springは反射によって注入を実現します.反射に関する資料はjava docを参照してください.IoCとDIの概念を理解すると、すべてが簡単に明らかになり、残りの作業はspringのフレームワークに木を積み上げるだけです.まだ分からないならjavaをあきらめろ!
 
スプリングがどのように動いているのかをご紹介します.
public static void main(String[] args) {   
        ApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml");   
        Animal animal = (Animal) context.getBean("animal");   
        animal.say();   
}

このコードはよく知っているでしょうが、まずアプリケーションContext.を分析しましょう.xml
<bean id="animal" class="phz.springframework.test.Cat">
        <property name="name" value="kitty" />
    </bean>

彼には類phzがある.springframework.test.Cat
public class Cat implements Animal {
    private String name;
    public void say() {
        System.out.println("I am " + name + "!");
    }
    public void setName(String name) {
        this.name = name;
    }
}

phzを実現した.springframework.test.Animalインタフェース
public interface Animal {
    public void say();
}

明らかに上のコード出力I am kitty!では、スプリングはどうやってやったのでしょうか.次にSpringを自分で書いて、Springがどのように動いているのかを見てみましょう.まず、Beanが持つプロパティを格納するためのBeanクラスを定義します.
/* Bean Id */
    private String id;
    /* Bean Class */
    private String type;
    /* Bean Property */
    private Map<String, Object> properties = new HashMap<String, Object>();

1つのBeanにはid,type,Propertiesが含まれます.次にSpringは私たちのプロファイルをロードし始めました.私たちの構成情報をHashMapに保存します.HashMapのkeyはBeanのIdです.HasMapのvalueはこのBeanです.そうすればcontextを通過することができます.getBean(「animal」)という方法でAnimalというクラスを得る.Spirngは基本タイプを注入できることはよく知られていますが、リストやMapのようなタイプを注入できることはよく知られています.次に、Mapを例にSpringがどのように保存されているかを見てみましょう.Map構成は次のようになります.
<bean id="test" class="Test">
        <property name="testMap">
            <map>
                <entry key="a">
                    <value>1</value>
                </entry>
                <entry key="b">
                    <value>2</value>
                </entry>
            </map>
        </property>
    </bean>

Springはどのようにして上の構成を保存しますか?コードは次のとおりです.
if (beanProperty.element("map") != null) {
                    Map<String, Object> propertiesMap = new HashMap<String, Object>();
                    Element propertiesListMap = (Element) beanProperty
                            .elements().get(0);
                    Iterator<?> propertiesIterator = propertiesListMap
                            .elements().iterator();
                    while (propertiesIterator.hasNext()) {
                        Element vet = (Element) propertiesIterator.next();
                        if (vet.getName().equals("entry")) {
                            String key = vet.attributeValue("key");
                            Iterator<?> valuesIterator = vet.elements()
                                    .iterator();
                            while (valuesIterator.hasNext()) {
                                Element value = (Element) valuesIterator.next();
                                if (value.getName().equals("value")) {
                                    propertiesMap.put(key, value.getText());
                                }
                                if (value.getName().equals("ref")) {
                                    propertiesMap.put(key, new String[] { value
                                            .attributeValue("bean") });
                                }
                            }
                        }
                    }
                    bean.getProperties().put(name, propertiesMap);
                }

次に、Springがどのように注入に依存しているのかを見てみましょう.実は注入に依存する考えも簡単です.反射メカニズムによって実現され、クラスをインスタンス化する際に、HashMapに保存されていたクラス属性を反射呼び出しクラスセット法によってクラスに注入します.具体的にどうやって作ったのか見てみましょう.まずクラスをインスタンス化します
public static Object newInstance(String className) {
        Class<?> cls = null;
        Object obj = null;
        try {
            cls = Class.forName(className);
            obj = cls.newInstance();
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return obj;
    }

そしてこのクラスの依存を注入します
public static void setProperty(Object obj, String name, String value) {
        Class<? extends Object> clazz = obj.getClass();
        try {
            String methodName = returnSetMthodName(name);
            Method[] ms = clazz.getMethods();
            for (Method m : ms) {
                if (m.getName().equals(methodName)) {
                    if (m.getParameterTypes().length == 1) {
                        Class<?> clazzParameterType = m.getParameterTypes()[0];
                        setFieldValue(clazzParameterType.getName(), value, m,
                                obj);
                        break;
                    }
                }
            }
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
}

最後に、このクラスのインスタンスを返してくれれば、使えます.私が書いたコードにはHashMapを作成し、このHashMapを注入する必要があるクラスに注入します.
if (value instanceof Map) {
                Iterator<?> entryIterator = ((Map<?, ?>) value).entrySet()
                        .iterator();
                Map<String, Object> map = new HashMap<String, Object>();
                while (entryIterator.hasNext()) {
                    Entry<?, ?> entryMap = (Entry<?, ?>) entryIterator.next();
                    if (entryMap.getValue() instanceof String[]) {
                        map.put((String) entryMap.getKey(),
                                getBean(((String[]) entryMap.getValue())[0]));
                    }
                }
                BeanProcesser.setProperty(obj, property, map);
            }

Springで作成したクラスを使うことができますが、難しくないのではないでしょうか.もちろんSpringができることはこれだけではありませんが、この例のプログラムはSpringの最も核心的な依存注入機能の一部を提供しています.
変換元:http://blog.csdn.net/it_man/article/details/4402245