1. 程式人生 > >自己實現一個SpringIOC——(1)

自己實現一個SpringIOC——(1)

Spring框架中最重要也是最廣為人知的就是AOP和IOC了吧,AOP我已經講過了,今天我們就講講IOC,對於一些基本概念我就不贅述了,而且講了也很難深刻的理解,今天我們就自己編寫一個簡易的框架來實現IOC,至於我是怎麼知道的,嘿嘿,我是看了這裡的視訊:https://segmentfault.com/l/1500000013061317 , 所以如果有些小夥伴覺得我下面的內容比較看不懂的話,你們就看看這裡的視訊吧!

首先我們先看看程式碼的框架:

我們這就講講DispatcherServlet部分,不懂的可以看我github程式碼和視訊。

我們這個框架主要分為三個部分,流程也是按這三個部分走的:

  1. 找到bean
  2.  載入並註冊bean
  3. 注入bean

1 找到bean

找到bean在什麼地方,是對BeanDefinition的資源定位,是由ResourceLoader通過統一的Resource介面來完成,這個介面對各中形式的Resource都提供了統一介面,比如Xml,比如annotation。而這些都是由ResourceLoader來完成的

   /**
     *
     * 找到bean
     *
     * */
    private void scanBase(String basePackages) {  //"com.yy"
        //file:/D:/IdeaProject/springIoc/springIoc/springioc/target/springioc/WEB-INF/classes/com/yy/
        URL url = this.getClass().getClassLoader().getResource("/" + replacePath(basePackages));//getResource全部是帶斜槓的,所以我們要把點換成斜槓
        String path = url.getFile();    ///D:/IdeaProject/springIoc/springIoc/springioc/target/springioc/WEB-INF/classes/com/yy/
        File file = new File(path);  //生成一個檔案
        String [] strFiles = file.list();  //得到檔案底下的所有的檔名
        for(String strFile: strFiles) {
            File eachFile = new File(path + strFile);
            if(eachFile.isDirectory()) {            //如果是目錄,就遞迴繼續向裡面查詢
                scanBase(basePackages +"."+eachFile.getName());
            }else {
                System.out.println("class name" + eachFile.getName());
                classNames.add(basePackages +"." + eachFile.getName());
            }
        }
    }
    //將字串中的.換成/
    String replacePath(String path) {
        return path.replaceAll("\\.","/");
    }

2 載入並註冊bean

找到bean後,將bean註冊到我們的IOC容器中。Spring是通過一些ApplicationContext來完成的,比如FileSystemXmlApplicationContext, ClassPathXmlApplicationContext以及我們最常見的XmlWebApplicationContext,讀取之後將bean註冊到IOC容器中,簡單來說,就是把讀取的bean都放到一個map中。

    /**
     *
     * 載入並註冊bean
     *
     * */
    //把classNames迴圈一遍,看裡面有哪些類,然後把它生成出來載入進去
    private void filterAndInstance() throws Exception {
        if( classNames.size() == 0) {
            return;
        }
        //迴圈獲取類名
        for(String className : classNames) {
            Class clazz = Class.forName(className.replace(".class", ""));
            if(clazz.isAnnotationPresent(Controller.class)) {  //如果clazz位元組碼上面帶了一個Annotation,並且Annotion是controller,就例項化一個controller物件出來
                //獲取bean例項
                Object instance = clazz.newInstance();
                //獲取註解的value---將controller上的名字取出來(fish)
                String key = ((Controller)clazz.getAnnotation(Controller.class)).value();
                //將bean交付給IOC
                instanceMap.put(key, instance);  //eg:(fish , FishController)
            }else if(clazz.isAnnotationPresent(Service.class)) { //如果clazz位元組碼上面帶了一個Annotation,並且Annotion是Service
                //獲取bean例項
                Object instance = clazz.newInstance();
                //獲取註解的value
                String key = ((Service)clazz.getAnnotation(Service.class)).value();
                //將bean交付給IOC
                instanceMap.put(key, instance);
            }else {
                continue;
            }
        }
    }

3 注入bean

當我們要用bean時,由IOC容器自動的注入進去。

    /**
     *
     * 注入bean
     *
     * */
    //把ioc容器裡的bean注入到指定地方(instanceMap中的值注入到@qualifier)p--DI
    //把instanceMap迴圈一遍,把它每一個物件位元組碼中的file取出來,看看裡面有沒有Qualifier的註解,如果有的話,把qualifier中的value取出來,然後把value對應的物件注入到這裡
    private void springDi() throws IllegalArgumentException, IllegalAccessException {

        if(instanceMap.size() == 0) {
            return;
        }
        /**
         * 迴圈獲取例項
         * */
        for(Map.Entry<String, Object> entry: instanceMap.entrySet()) {
            //獲取所有的類變數
            Field[] fields = entry.getValue().getClass().getDeclaredFields();
            //檢視上面有沒有qualifer的標識,如果有qualifer的標識,把它的value取出來,通過這個值我們就可以拿到它的例項
            for(Field  field: fields) {
                //包含Qualifer註解
                if(field.isAnnotationPresent(Qualifier.class)){
                    String key = ((Qualifier)field.getAnnotation(Qualifier.class)).value();
                    field.setAccessible(true);
                    field.set(entry.getValue(), instanceMap.get(key));    //注入qualifier----即把fishService注入進去了
                }//autowired
            }
        }


    }