從零寫一個Java WEB框架(五)IOC建立

  • 該系列,其實是對《架構探險》這本書的實踐。本人想記錄自己的學習心得所寫下的。
  • 從一個簡單的Servlet項目開始起步。對每一層進行優化,然後形成一個輕量級的框架。
  • 每一篇,都是針對項目的不足點進行優化的。
  • 項目已放上github

本篇

在這篇,主要是建立一個Bean容器,實現IOC 控制反轉。這樣只需要註解就可以實現依賴注入了。

整體實現思路
- 建立一個Bean容器,Map類型的,映射關係是key—class value—-實例
- 遍歷過濾出基礎包下類註解中有Controller或者Service和Entity 等註解的類,然後實例化他們,把他們存到Bean容器中。
- 然後遍歷Bean容器中的每一組映射。遍歷每個class下的成員遍歷,檢查出具有Inject註解的成員遍歷,然後對其進行賦值操作,從Bean容器中查找出實例並將該實例賦予這個變量

框架實現

BeanHelper類
建立一個Bean 容器

/*
*  Bean 助手類
*  加載類,建立Bean容器
* */
public final class BeanHelper {

    private static final Logger log = LoggerFactory.getLogger(BeanHelper.class);

    /*
     *  建立一個Bean容器,(存放Bean類與Bean實例的映射關係)
     * */
    private static final Map<Class<?>, Object> BEAN_MAP = new HashMap<Class<?>, Object>();


    static {
        /*
        *  調用getBeanClassSet 方法
        *  獲取bean類方法,也就是有Controller 或Service 等註解的類
        * */
        Set<Class<?>> classSet = ClassHelper.getBeanClassSet();
        classSet.forEach(s-> {
            try {
                BEAN_MAP.put(s,s.newInstance());
            } catch (Exception e) {
                log.error("創建類失敗",e);
                e.printStackTrace();
            }
        });

    }

    /*
     *  獲取Bean容器
     * */
    public static Map<Class<?>, Object> getBeanMap() {
        return BEAN_MAP;
    }

    /*
     *  獲取Bean 實例
     * */
    public static <T> T getBean(Class<T> cls) {
        if (!BEAN_MAP.containsKey(cls)) {
            log.error("沒有獲取到{0}實例",cls.getSimpleName());
            throw new RuntimeException("沒有獲取到實例"+cls.getSimpleName());
        }
        return (T)BEAN_MAP.get(cls);
    }
}

IOCHelper 實現依賴注入
查找出具有Inject註解的成員變量並賦值

/*
*  依賴注入助手類
* */
public final class IOCHelper {

    /*
    * 思路:
    * 從BeanHelper Bean容器裏獲取到所有Bean的映射關係。
    * 然後遍歷這個容器。獲取 類--key,實例--value
    * 檢查類的成員變量是否有Inject註解,如果有,那麼就對該變量注入實例
    *
    * */

    static {
        //獲取到容器
        Map<Class<?>, Object> beanMap = BeanHelper.getBeanMap();
        if (MapUtils.isNotEmpty(beanMap)) {
            for (Map.Entry<Class<?>,Object> beanEntity:beanMap.entrySet()) {
                Class<?> key = beanEntity.getKey();
                Object value = beanEntity.getValue();
                //獲取Bean 類定義的所有成員變量(簡稱Bean Field)
                Field[] declaredFields = key.getDeclaredFields();
                if (ArrayUtils.isNotEmpty(declaredFields)) {
                    for (Field field : declaredFields) {
                        if (field.isAnnotationPresent(Inject.class)) {

                            Class<?> type = field.getType();
                            //在容器中獲取該實例
                            Object o = beanMap.get(type);
                            if (o != null) {
                                ReflectionUtil.setField(value,field,o);
                            }                        }                  }                }          }       }
    }
}

測試

將CustomerService 添加個成員變量並加上註解

  public class CustomerService {

    @Inject
    public Customer customer;

測試類

 @Test
    public void testInject() {
        try {
            Class.forName("com.smart.mysimpleframework.Helper.IOCHelper");
            //從容器裏獲取customerService 的實例查看
            CustomerService bean = BeanHelper.getBean(CustomerService.class);
            if (bean.customer!=null) {
                System.out.println("Inject is ok!!");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

輸出
Inject is ok!!

總結:

  • 想理解是怎麼實現IOC的,還是去github 上clone 整個項目細看一下。
  • 到目前爲止,我們可以實現依賴注入來了。
  • 但是對於Controll層業務代碼臃腫的問題還沒解決,所以接下來是針對Controller 層請求方法的封裝了
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章