一起写框架-Ioc内核容器的实现-对象的调用-属性注入容器的对象(十)
實現功能
?
需求:在類的成員屬性使用@Autowirde注解注入容器中的對象。
?
實現思路
要實現這個功能。我們首先要思考一個問題:類與類的關系是在調用的建立的,還是說在創建對象的時候就就將建立了?
?
---我實現的方案是,在在程序啟動后,所有對象創建后直接就將對象的屬性和屬性之間的關系創建了。接下來我就用這個思路來實現,將根據@Autowirde建立對象與對象之間的關系。
?
為什么一定要對象全部創建后再實現對象與對象直接的關系呢?
這個是邏輯問題,如果對象沒有創建完就建立對象與對象之間的關系,人家都還沒有創建,你怎么引用呢?對吧。所有一定在所有對象創建完后建立對象與對象的關系。
?
?
實現步驟
1.Context接口增加一個方法。用于通過Map的和屬性名對象或者對象的類型與屬性的類型對象,給屬性匹配對象。定義如代碼的說明
?
1 /** 2 * 根據類的類型以及設置的對象名返回容器對象 3 * 如果傳入的類型容器中有對應key的對象,而且返回類型是兼容的,直接返回對應的對象。 4 * 如果傳入的類型容器中有沒有對應key的對象,那么判斷傳入的類型是否和容器的對象的找到唯一配置的。 5 * 如果傳入類型唯一匹配,返回對象。如果沒有或者配配多個對象,都報一個RuntimeException異常 6 * @param classType 7 * @return 8 */ 9 Object getObject(Class<?> classType,String key);?
2.在ContextImpl容器實現類實現這個方法
1 @Override 2 public Object getObject(Class<?> classType, String key) { 3 // 1.判斷是否有對應key的對象 4 Object object = objects.get(key); 5 // 2.如果有,而且類型也兼容。直接返回該對象。 6 if (object != null && classType.isAssignableFrom(object.getClass())) { 7 return object; 8 } else { 9 // 3.如果沒有對應key的對象,那么就在容器里檢索,是否有兼容類型的對象。 10 Collection<Object> values = objects.values(); 11 Iterator<Object> iterator = values.iterator(); 12 int count = 0; 13 Object currentObject = null; 14 while (iterator.hasNext()) { 15 Object nextObject = iterator.next(); 16 //判斷classType是否是nextObject.getClass()的兼容類型。 17 boolean from = classType.isAssignableFrom(nextObject.getClass()) ; 18 if (from) { 19 //如果發現有對象,計數加1 20 count++; 21 //并將對象賦予當前對象 22 currentObject = nextObject; 23 } 24 } 25 // 如果兼容類型的對象只有一個,返回這個對象。如果大于一個,返回null 26 if (count == 1) { 27 return currentObject; 28 } else { 29 //如果發現一個類型容器中有多個異常,拋異常 30 throw new RuntimeException("容器中找不到對應的對象或者找到的對象不是唯一的!請確認是否一個接口繼承了多個類"); 31 } 32 33 } 34 35 }3.在AbstractApplicationContext容器操作類實現屬性的注入方法 autowired()
?
1 /** 2 * 給對象的屬性注入關聯的對象 3 * @throws IllegalArgumentException 4 * @throws IllegalAccessException 5 */ 6 private void autowired() throws IllegalArgumentException, IllegalAccessException { 7 // 1.獲得容器 8 Context context = contexts.get(); 9 // 2.獲得容器中的所有對象。 10 Map<String, Object> objects = context.getObjects(); 11 // 3.獲得容器中所有的對象值 12 Collection<Object> values = objects.values(); 13 // 4.獲得對象的迭代器 14 Iterator<Object> iterator = values.iterator(); 15 while (iterator.hasNext()) { 16 Object object = iterator.next(); 17 // 5.獲得對象的表結構 18 Class<? extends Object> classType = object.getClass(); 19 // 6.獲得字段的結構 20 Field[] fields = classType.getDeclaredFields(); 21 for (int i = 0; i < fields.length; i++) { 22 // autowired獲得注解 23 Autowired autowired = fields[i].getAnnotation(Autowired.class); 24 if (autowired != null) { 25 Class<?> fieldType = fields[i].getType(); 26 String fieldName = fields[i].getName(); 27 // 如果容器里面有對應的對象 28 Object fieldObject = context.getObject(fieldType, fieldName); 29 // 允許訪問私有方法 30 if (fieldObject != null) { 31 // 屬性是私有的也可以訪問 32 fields[i].setAccessible(true); 33 // 將屬性值賦予這個對象的屬性 34 fields[i].set(object, fieldObject); 35 } 36 37 } 38 } 39 } 40 }?
4. 在AbstractApplicationContext構造方法最后調用屬性注入方法autowired,注意標紅處
?
1 public AbstractApplicationContext(Class<?> classType) { 2 try { 3 // 判斷配置類是否有Configuration注解 4 Configuration annotation = classType.getDeclaredAnnotation(Configuration.class); 5 if (annotation != null) { 6 // 獲得組件掃描注解 7 ComponentScan componentScan = classType.getDeclaredAnnotation(ComponentScan.class); 8 // 獲得包名 9 this.basePackage = componentScan.basePackages(); 10 // 根據包名獲得類全限制名 11 // Set<String> classNames = 12 // PackageUtils.getClassName(this.basePackage[0], true); 13 // 將掃描一個包,修改為多個包 14 Set<String> classNames = PackageUtils.getClassNames(this.basePackage, true); 15 // 通過類名創建對象 16 Iterator<String> iteratorClassName = classNames.iterator(); 17 while (iteratorClassName.hasNext()) { 18 19 String className = iteratorClassName.next(); 20 // System.out.println(className); 21 22 // 通過類全名創建對象 23 Class<?> objectClassType = Class.forName(className); 24 /* 25 * 判斷如果類權限名對應的不是接口,并且包含有@Component|@Controller|@Service| 26 * 27 * @Repository 才可以創建對象 28 */ 29 if (this.isComponent(objectClassType)) { 30 Object instance = objectClassType.newInstance(); 31 // 修改為,默認對象支持首字符小寫 32 String objectName = null; 33 // 獲得組件注解的name屬性值 34 String componentName = this.getComponentOfName(objectClassType); 35 36 if (componentName == null) { 37 // 如果組件注解的name屬性沒有值,使用默認命名對象 38 objectName = NamingUtils.firstCharToLower(instance.getClass().getSimpleName()); 39 } else { 40 // 如果組件注解的name屬性有值,使用自定義命名對象 41 objectName = componentName; 42 } 43 this.getContext().addObject(objectName, instance); 44 } 45 46 } 47 } 48 //1.注入對象到屬性中。 49 autowired(); 50 } catch (InstantiationException e) { 51 e.printStackTrace(); 52 } catch (IllegalAccessException e) { 53 e.printStackTrace(); 54 } catch (ClassNotFoundException e) { 55 e.printStackTrace(); 56 } 57 58 }?
?測試代碼
測試類目錄結構
?
1.修改UserController代碼,增加注入UserService的代碼
?
1 package ioc.core.test.controller; 2 3 import ioc.core.annotation.Autowired; 4 import ioc.core.annotation.stereotype.Controller; 5 import ioc.core.test.service.UserService; 6 7 @Controller 8 public class UserController { 9 10 /** 11 * 通過@Autowired可以注入UserService的對象。 12 */ 13 @Autowired 14 private UserService userServiceImpl; 15 16 public void login(){ 17 System.out.println("-登錄Controller-"); 18 userServiceImpl.login(); 19 } 20 21 }?
2.調用UserController 對象
1 package ioc.core.test; 2 3 import org.junit.Test; 4 5 import ioc.core.impl.AnntationApplicationContext; 6 import ioc.core.test.config.Config; 7 import ioc.core.test.controller.UserController; 8 9 public class AnntationApplicationContextTest { 10 11 @Test 12 public void login(){ 13 try { 14 AnntationApplicationContext context=new AnntationApplicationContext(Config.class); 15 UserController userController = context.getBean("userController", UserController.class); 16 userController.login(); 17 System.out.println(context.getContext().getObjects()); 18 19 } catch (Exception e) { 20 e.printStackTrace(); 21 } 22 } 23 24 }3.輸出結果
同時輸出了UserController的內容和UserService的內容
?
轉載于:https://www.cnblogs.com/zhuyuejiu/p/7819694.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的一起写框架-Ioc内核容器的实现-对象的调用-属性注入容器的对象(十)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 「mysql优化专题」主从复制面试宝典!
- 下一篇: 连续几天梦到前任出轨