一起写框架-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内核容器的实现-对象的调用-属性注入容器的对象(十)相关推荐
- Spring框架IoC/DI原理及实现
1.概念 IoC:指将对象的创建权,交给到Spring容器: DI :指Spring创建对象的过程中,将对象依赖的属性通过配置的方式自动的设值给当前的对象 . IoC/DI注解详解 完成IoC/DI, ...
- asp.net core自定义依赖注入容器,替换自带容器
依赖注入 在asp.net core程序中,众所周知,依赖注入基本上贯穿了整个项目,以通用的结构来讲解,控制器层(Controller层)依赖业务层(Service层),业务层依赖于仓储层(Repos ...
- 又一个强大的PHP5.3依赖注入容器
简单的服务容器 一个简单的 php 5.3 依赖注入容器. 项目地址:https://github.com/godruoyi/easy-container Why 目前比较流行的 PHP 容器: Pi ...
- Spring5框架-IOC容器
Spring5框架 Spring包下载快照 一.Spring简绍 1什么是Spring 1.Spring是轻量级的开源的JAVAEE框架,可以解决企业应用开发的复杂性 2.Spring有两个核心的部分 ...
- spring根据名称获取bean_带你从零开始手写 spring ioc 框架,深入学习 spring 源码
IoC Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理. 创作目的 使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过 ...
- Spring框架—IoC容器
首先我们需要了解一下是什么是IoC.IoC是Spring的核心技术之一,全称是Inversion of Control(控制反转).最原始的创建对象的方法就是通过new来实现(手动的编写代码实现),而 ...
- 打怪上分! 手写Spring ioc 框架,狠狠的“撸撸”Spring 源码
估计很多朋友使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过. 你是不是有这样的感觉呢? 但是 spring 源码存在一个问题,那就是过于抽象,导致 ...
- Spring框架IOC容器,依赖注入,控制反转
Spring的配制文件中 以上标签的属性id是不是必须的?不是必须的,如果定义id,那么其它的bean就可以通过此name来引用id 创建beans.xml <?xml version=&quo ...
- Spring框架IOC基础及XML的配置 第二章
1 Spring概述 1.1 关于框架 框架的概念 框架:特指软件框架,它是我们在实际开发中解决项目需求的技术集合.运用框架可以大大简化代码的编写,缩短开发周期.同时,对后续负责项目维护的人员降低技术 ...
最新文章
- 在rMBP上利用Python的onetimepass库实现Google Authenticator Application的效果
- B - Linear Algebra Test————只给思路
- 卷积神经网络CNN 手写数字识别
- 用Windows live Writer 2012发布51cto博客
- 蒲公英怎么加入别人的网络_挖蒲公英吃的,抓紧看看吧!
- Business Intelligence——SSIS项目从创建到部署的简单总结(二)
- Python定时任务调度——APScheduler
- 闭包---在函数内部再定义一个函数
- 工作分流是什么意思_【嘉陵特装要闻】重庆嘉陵召开持续推进职工分流安置工作布置会...
- idea中ssm集成freemark_基于SSM框架的迷你天猫商城
- SMTP 发送内嵌图片 邮件
- yii2 获取模块名,控制名,动作方法名
- CMD命令备份驱动和安装驱动
- vue tinymce安装及使用
- ELK企业应用-ekl快速搭建-kibana
- 【服务端知识点】MAC OSX 安装MongoDB
- 排列组合之错排问题总结
- 怎样远程控制别人的电脑
- 提取百度新闻的标题、网址、日期和来源
- oracle 中 in函数
热门文章
- BZOJ 1270: [BeijingWc2008]雷涛的小猫( dp )
- 考研编程练习----排名
- [转载]UEditor报错TypeError: me.body is undefined
- [Everyday Mathematics]20150101
- Oracle 安装 网络配置 警告
- 恐怖之城(深圳)系列1---K113大巴洗劫一空
- c#做端口转发程序支持正向连接和反向链接
- Soot生成控制流图
- 《Nmap渗透测试指南》—第7章7.8节后台打印机服务漏洞
- Javascript构造函数的继承