一塊兒寫框架-Ioc內核容器的實現-對象的調用-屬性注入容器的對象(十)

實現功能

 

需求:在類的成員屬性使用@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的內容

相關文章
相關標籤/搜索