Spring ioc 簡單理解

參看資料:《Spring揭祕》

DefaultListableBeanFactory看的糊里糊塗的,這篇博客寫一下我對Spring ioc的理解,肯定有錯誤的地方,希望各位指點,不要噴我哈(o.o)。如果你是小白,你可能需要看一下java的反射機制

首先,如果你想要通過配置文件的方法來給bean配置,
你可以就需要四個類,
第一個是BeanDefinition,這個類中保存有配置文件中的每一個配置的bean的信息,最終會通過BeanDefinition提供的信息來生產bean.
第二個是BeanReader,這個類讀取配置文件,並把相應的信息轉換成BeanDefinition。
第三個是BeanRegist,這個類的作用,就是保存BeanDefinition,BeanDefinition保存bean的信息,BeanRegist保存所有的BeanDefinition(配置文件的每個bean都會有一個相對應的BeanDefinition)。
第四纔是我們的BeanFactory,所有的類最後都是通過BeanFactory跟程序員打交道的。
現在我們可以試着來實現一個簡單的ioc容器:我們用.properties來所配置文件,用java的Properties類來讀取我們的配置文件。
首先是配置文件:

bean_name=com.myioc.Book
book_name=ceshi
book_author=ceshizhe

/*然後是我們的實體類*/
package com.myioc;

public class Book {

    private String book_name;
    private String book_author;
    public String getBook_name() {
        return book_name;
    }
    public void setBook_name(String book_name) {
        this.book_name = book_name;
    }
    public String getBook_author() {
        return book_author;
    }
    public void setBook_author(String book_author) {
        this.book_author = book_author;
    }
    @Override
    public String toString() {
        return "Book [book_name=" + book_name + ", book_author=" + book_author
                + "]";
    }

}

現在需要我們的BeanDefinition

import java.util.Properties;

public class BeanDefinition {

    /*我用一個String來保存bean的名字*/
    private String beanName;

    /*用Properties來保存配置的信息*/
    private Properties propertieslist;

    /*setter,getter方法,用來設置屬性,不然怎麼保存*/

    /*爲了測試,把toString方法重寫*/
    @Override
    public String toString() {
        return "BeanDefinition [beanName=" + beanName + ", propertieslist="
                + propertieslist + "]";
    }
}

BeanReader

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;

public class MyReader {

    public void loadfile(String classpath,MyRegister myRegister) {
        /*這個地方有點繞,reader不但要讀取文件,還要將從文件讀取到的BeanDefinition註冊到Register中,這樣Register才能管理Bean*/


        Properties properties = new Properties();

        /*給定classpath將配置文件讀入*/
        try {
            File file = new File(classpath);
            FileInputStream inStream = new FileInputStream(file);

            /*讀取配置文件*/
            properties.load(inStream);

        } catch(Exception e) {
            System.out.println("配置文件沒找到");
        }

        /*生成一個BeanDefinition*/
        BeanDefinition beanDefinition = new BeanDefinition();

        /*設置Bean的名字*/
        beanDefinition.setBeanName(properties.getProperty("bean_name"));

        /*properties中保存了屬性名字和對應的名字,直接保存就行了*/
        beanDefinition.setPropertieslist(properties);

        /*向傳入的myRegister註冊Beandefinition*/
        myRegister.registerBeanDefinition(beanDefinition);
    }
}

然後是BeanRegister

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

public class MyRegister {

    private Map<String, BeanDefinition> beanDefinitions = new HashMap<>();

    /*將beanDefinition放入自己的Map中管理*/
    public void registerBeanDefinition(BeanDefinition beanDefinition) {

        beanDefinitions.put(beanDefinition.getBeanName(), beanDefinition);
    }

    /*方便測試*/
    public Map<String, BeanDefinition> getBeanDefinitions() {
        return beanDefinitions;
    }

    public void setBeanDefinitions(Map<String, BeanDefinition> beanDefinitions) {
        this.beanDefinitions = beanDefinitions;
    }

/*這個方式是方便BeanFactory從Regist中取得BeanDefinition然後生成實例的*/
    public Object getBeanDefinition(String beanName) {
        return beanDefinitions.get(beanName);
    }   
}

/*Register和BeanFactory的關係,Spring揭祕一書中講的很好,就好比圖書館與圖書館裏面的書架的關係,借書雖然是跟圖書館打交道,但是書本是放在書架上的,這裏我們的BeanFactory充當圖書館的角色,Register充當書架的角色。*/

接下來就是我們的BeanFactory

package com.myioc;

import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;

public class MyBeanFactory {

    /*圖書館裏面肯定有書架放書,Reader也可以有其他的寫法,但是這裏爲了測試方便就放在BeanFactory中了*/
    private MyRegister myRegister = new MyRegister();
    private MyReader myReader = new MyReader();


    public MyBeanFactory(String classpath) {
        myReader.loadfile(classpath,myRegister);
        /*將配置文件的路徑和Rrgister給Reader,Reader就會找到配置文件,並且將讀取到的信息註冊給Register*/
    }

    public Object getBean(String beanName) {

        BeanDefinition beanDefinition = (BeanDefinition)myRegister.getBeanDefinition(beanName);

        if(beanDefinition != null) {    
            try {
                /*得到beanName的Class對象*/
                Class cl = Class.forName(beanDefinition.getBeanName());

                /*得到beanDefinition中保存所有的屬性值*/
                Properties properties = beanDefinition.getPropertieslist();

                /*得到properties的key值*/
                Set<Object> keySet = properties.keySet();

                Iterator<Object> si = keySet.iterator();

                /*生成實例*/
                Object newObject = cl.newInstance();

                String field;

                /*遍歷,通過setter方法給 beanName的屬性賦值*/
                while(si.hasNext()) {

                    /*遍歷keyset中的值*/
                    field = (String)si.next();

                    if( !"bean_name".equals(field) && field != null) {
                        try {

                            Method m = cl.getMethod(makeMethod(field), String.class);
                            m.invoke(newObject, properties.getProperty(field));

                        } catch(Exception e) {
                            System.out.println("沒有"+field+"的set方法");
                        }
                    }
                }
                return newObject;

            } catch(Exception e){
                System.out.println("forname錯誤");
            }
        }
        return null;
    }

    /*得到field的set方法*/
    private String makeMethod(String field) {
        if(field!=null) {
            field = field.substring(0, 1).toUpperCase() + field.substring(1);
            return  "set"+field;
        }
        return null;
    }
}

就這樣 看起來很簡單,那是因爲我們實現的是簡單的ioc更本不能在實際中使用,Sping在實現DefaultListableBeanFactory的時候考慮了很多東西。

現在我們可以測試了

package com.myioc;

public class Test {

    public static void main(String ar[]) {

        MyBeanFactory bf = new MyBeanFactory("src/Myioc.properties");
        Book b = (Book)bf.getBean("com.myioc.Book");
        System.out.println(b);

    }
}

文件結構:
這裏寫圖片描述

運行結果:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章