1. 程式人生 > 其它 >Spring原始碼簡易手寫實現(學習過程記錄)(四)

Spring原始碼簡易手寫實現(學習過程記錄)(四)

4.1Aware回撥模擬實現

在createBean的時候,我們想在加了Component註解的類裡面加一個欄位beanName,該欄位儲存bean物件的name屬性

spring會提供一個介面BeanNameAware來實現

package com.rainwood.spring;

public interface BeanNameAware {

    void setBeanName(String name);
}

我們在UserService類裡可以繼承該介面重寫setBeanName方法

package com.rainwood.liming.service;

import com.rainwood.spring.*;

@Component("userService")
//@Scope("prototype")
public class UserService implements BeanNameAware{
    @Autowired
    private OrderService orderService;

    private  String beanName;

    public void test() {

        System.out.println(orderService);
        System.out.println(beanName);
    }

    @Override
    public void setBeanName(String name) {
        beanName = name;
    }
}

設想如果沒有setBeanName方法的話,在自動注入時候,僅有一個beanName欄位是無法將Bean的name屬性傳進來賦給beanName

我們這裡利用set方法,在spring容器createBean方法中呼叫setBean方法就可以實現將beanName傳入。

public  Object createBean(String beanName, BeanDefination beanDefination) {
    Class clazz = beanDefination.getClazz();
    try {
        //首先看getDeclaredConstructor(Class<?>... parameterTypes)
        //這個方法會返回制定引數型別的所有構造器,包括public的和非public的,當然也包括private的。
        //getDeclaredConstructors()的返回結果就沒有引數型別的過濾了。
        Object instance = clazz.getDeclaredConstructor().newInstance();

        //依賴注入
        //getDeclaredFields():獲得某個類的所有宣告的欄位,即包括public、private和proteced,但是不包括父類的申明欄位。
        for (Field declaredField : clazz.getDeclaredFields()) {
            if(declaredField.isAnnotationPresent(Autowired.class)) {
                //spring在依賴注入時候會去是spring容器池裡去根據型別和名字來找對應的bean
                //這裡我們簡化用名字來找
                Object bean = getBean(declaredField.getName());
                declaredField.setAccessible(true);//功能是啟用或禁用安全檢查
                declaredField.set(instance, bean);
            }
        }

        //Aware回撥
        //判斷instance是否實現了BeanNameAware介面,如果實現了就呼叫setBeanName將當前bean的名字beanName傳進去
        if(instance instanceof BeanNameAware) {
            ((BeanNameAware)instance).setBeanName(beanName);
        }

        return instance;
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
    return null;
}

我們和之前不同,我們在createBean時候,再加一個引數beanName傳入createBean方法,

 //Aware回撥
        //判斷instance是否實現了BeanNameAware介面,如果實現了就呼叫setBeanName將當前bean的名字beanName傳進去
        if(instance instanceof BeanNameAware) {
            ((BeanNameAware)instance).setBeanName(beanName);
        }

檢驗instance物件是否是繼承了BeanNameAware介面,如果繼承了,就可以利用重寫的setBeanName方法將beanName注入進去

4.2初始化模擬實現

和Aware回撥類似,我們需要一個InitializingBean介面,該介面有afterPropertiesSet方法

package com.rainwood.spring;

public interface InitializingBean {

    void afterPropertiesSet() throws Exception;

}

讓UserService繼承InitializingBean

package com.rainwood.liming.service;

import com.rainwood.spring.*;

@Component("userService")
//@Scope("prototype")
public class UserService implements BeanNameAware, InitializingBean {
    @Autowired
    private OrderService orderService;

    private  String beanName;

    public void test() {

        System.out.println(orderService);
        System.out.println(beanName);
    }

    @Override
    public void setBeanName(String name) {
        beanName = name;
    }

    //初始化時候呼叫這個方法想做啥就做啥
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("初始化");
    }
}

同樣的在createBean的時候

//初始化
if(instance instanceof InitializingBean) {
    try {
        ((InitializingBean)instance).afterPropertiesSet();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

繼續判斷instance是否繼承了InitializingBean介面

繼承了的話就呼叫afterPropertiesSet方法進行各種初始化操作