- 該系列,其實是對《架構探險》這本書的實踐。本人想記錄自己的學習心得所寫下的。
- 從一個簡單的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 層請求方法的封裝了