需求:在類的成員屬性使用@Autowirde註解注入容器中的對象。ide
要實現這個功能。咱們首先要思考一個問題:類與類的關係是在調用的創建的,仍是說在建立對象的時候就就將創建了?測試
---我實現的方案是,在在程序啓動後,全部對象建立後直接就將對象的屬性和屬性之間的關係建立了。接下來我就用這個思路來實現,將根據@Autowirde創建對象與對象之間的關係。this
爲何必定要對象所有建立後再實現對象與對象直接的關係呢?spa
這個是邏輯問題,若是對象沒有建立完就創建對象與對象之間的關係,人家都尚未建立,你怎麼引用呢?對吧。全部必定在全部對象建立完後創建對象與對象的關係。3d
1.Context接口增長一個方法。用於經過Map的和屬性名對象或者對象的類型與屬性的類型對象,給屬性匹配對象。定義如代碼的說明code
1 /** 2 * 根據類的類型以及設置的對象名返回容器對象 3 * 若是傳入的類型容器中有對應key的對象,並且返回類型是兼容的,直接返回對應的對象。 4 * 若是傳入的類型容器中有沒有對應key的對象,那麼判斷傳入的類型是否和容器的對象的找到惟一配置的。 5 * 若是傳入類型惟一匹配,返回對象。若是沒有或者配配多個對象,都報一個RuntimeException異常 6 * @param classType 7 * @return 8 */ 9 Object getObject(Class<?> classType,String key);
2.在ContextImpl容器實現類實現這個方法component
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,注意標紅處blog
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的內容