本文在建立類的實例時,是直接操做的屬性,而沒有用setter或者constructor方法,這是不合理的(違背了JavaBean封裝的思想)。故建議在閱讀本文時,僅關注實現的思路,不要參考具體實現過程,而應該使用spring的setter/constructor兩種方法java
本文繼java的springMvc框架簡單實現後,就Service-ServiceImpl
及Dao--DaoImpl
之間的依賴關係進行解耦,簡單實現@AutoWired
有關此部分的依賴注入(DI)。spring
@XxgAutoWired private UserDao userDao;
UserDaoImpl
類上面加入@XxgComponent
註解@XxgComponent public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao { ... }
3.1 掃描包過程當中,加入:判斷類中是否有@XxgComponent
註解,若是有,則加入咱們指定的容器segmentfault
3.2 掃描結束以後,給MethodDefinition
建立所在類的實例。服務器
所在類的實例說明:框架
主要將該實例中有@AutoWired
註解的屬性,賦予初值,每次調用方法都使用該實例,就達到了預想的效果。spa
賦初值的方式:code
Map<Class, ComponentDefinition> componentMap
容器的key存放依賴類實現的接口的class
,value存放該類的相關屬性。@AutoWired
註解的屬性時,獲取該屬性的類型class做爲key,在容器中查找該key這種實現模式,有一個最大的問題:component
一個Dao的接口,只能有一個對應的實現類。xml
其次:對象
依賴注入僅在Controller類中使用了纔有效
能夠使用xml文件來存儲接口與其實現類的依賴關係。
一個接口有多個實現類時,只在須要的實現類上添加@XxgComponent註解
/** * @Auther dbc * @Date 2020/10/15 14:40 * @Description */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface XxgAutoWired { }
/** * @Auther dbc * @Date 2020/10/16 15:48 * @Description */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface XxgComponent { }
private Object parentInstance; // 所屬類的實例
private static Map<Class, ComponentDefinition> componentMap = new ConcurrentHashMap<>(); // component類容器
/** * @Auther dbc * @Date 2020/10/16 16:03 * @Description 對有@XxgComponent註解的類 進行包裝 */ @Data @NoArgsConstructor @AllArgsConstructor public class ComponentDefinition { private Class typeClazz; // 類對象 private String typeName; // 類名 private XxgComponent component; // component註解 private Class implClazz; // 實現的父類 }
private void dealClass(Class clazz) throws Exception { // 一開始就添加 if (clazz.isAnnotationPresent(XxgComponent.class)) { // 將實現類添加到容器中 addComponent(clazz); return ; } ... }
/** * 將Component類添加到容器中 */ private void addComponent(Class clazz) throws Exception { ComponentDefinition componentDefinition = new ComponentDefinition(); componentDefinition.setComponent((XxgComponent) clazz.getAnnotation(XxgComponent.class)); componentDefinition.setTypeClazz(clazz); componentDefinition.setImplClazz(clazz.getInterfaces()[0]); componentDefinition.setTypeName(clazz.getName()); if (componentMap.get(componentDefinition.getImplClazz()) != null) { throw new Exception("已存在相同的實現類" + componentDefinition.getImplClazz().getName()); } componentMap.put(componentDefinition.getImplClazz(), componentDefinition); } /** * 處理controller的屬性,自動注入值, 返回該類的一個實例 */ private Object dealClassField(Class clazz) { Field[] fields = clazz.getDeclaredFields(); Object instance = null; try { instance = clazz.newInstance(); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } for(Field field : fields) { if (field.isAnnotationPresent(XxgAutoWired.class)) { // 給有XxgAutoWired註解的屬性,自動注入值 field.setAccessible(true); try { ComponentDefinition componentDefinition = componentMap.get(field.getType()); if (componentDefinition != null) { // 處理@XxgComponent 的自動注入 field.set(instance, dealClassField(componentDefinition.getTypeClazz())); } } catch (Exception e) { e.printStackTrace(); } } } return instance; }
在DispatcherServlet
中,當獲取到請求執行的方法,以及裝配好參數以後,調用該方法時,傳遞建立好的實例
try { Object result = methodDefinition.getMethod().invoke( methodDefinition.getParentInstance(), // 所屬類的實例 params.toArray()); sendResponse(result, req, resp); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); sendResponse(e.getMessage(), req, resp); }
真正的@AutoWired
太強大了,能夠用在屬性上,還能夠用在方法上等,博主就再也不深究了。
下文博主將使用XML配置文件的方式實現依賴注入,並對單例模式、依賴的值類型等進行處理。