需求:在类的成员属性使用@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的内容