实现功能

需求:在类的成员属性使用@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内核容器的实现-对象的调用-属性注入容器的对象(十)相关推荐

  1. Spring框架IoC/DI原理及实现

    1.概念 IoC:指将对象的创建权,交给到Spring容器: DI :指Spring创建对象的过程中,将对象依赖的属性通过配置的方式自动的设值给当前的对象 . IoC/DI注解详解 完成IoC/DI, ...

  2. asp.net core自定义依赖注入容器,替换自带容器

    依赖注入 在asp.net core程序中,众所周知,依赖注入基本上贯穿了整个项目,以通用的结构来讲解,控制器层(Controller层)依赖业务层(Service层),业务层依赖于仓储层(Repos ...

  3. 又一个强大的PHP5.3依赖注入容器

    简单的服务容器 一个简单的 php 5.3 依赖注入容器. 项目地址:https://github.com/godruoyi/easy-container Why 目前比较流行的 PHP 容器: Pi ...

  4. Spring5框架-IOC容器

    Spring5框架 Spring包下载快照 一.Spring简绍 1什么是Spring 1.Spring是轻量级的开源的JAVAEE框架,可以解决企业应用开发的复杂性 2.Spring有两个核心的部分 ...

  5. spring根据名称获取bean_带你从零开始手写 spring ioc 框架,深入学习 spring 源码

    IoC Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理. 创作目的 使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过 ...

  6. Spring框架—IoC容器

    首先我们需要了解一下是什么是IoC.IoC是Spring的核心技术之一,全称是Inversion of Control(控制反转).最原始的创建对象的方法就是通过new来实现(手动的编写代码实现),而 ...

  7. 打怪上分! 手写Spring ioc 框架,狠狠的“撸撸”Spring 源码

    估计很多朋友使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过. 你是不是有这样的感觉呢? 但是 spring 源码存在一个问题,那就是过于抽象,导致 ...

  8. Spring框架IOC容器,依赖注入,控制反转

    Spring的配制文件中 以上标签的属性id是不是必须的?不是必须的,如果定义id,那么其它的bean就可以通过此name来引用id 创建beans.xml <?xml version=&quo ...

  9. Spring框架IOC基础及XML的配置 第二章

    1 Spring概述 1.1 关于框架 框架的概念 框架:特指软件框架,它是我们在实际开发中解决项目需求的技术集合.运用框架可以大大简化代码的编写,缩短开发周期.同时,对后续负责项目维护的人员降低技术 ...

最新文章

  1. 在rMBP上利用Python的onetimepass库实现Google Authenticator Application的效果
  2. B - Linear Algebra Test————只给思路
  3. 卷积神经网络CNN 手写数字识别
  4. 用Windows live Writer 2012发布51cto博客
  5. 蒲公英怎么加入别人的网络_挖蒲公英吃的,抓紧看看吧!
  6. Business Intelligence——SSIS项目从创建到部署的简单总结(二)
  7. Python定时任务调度——APScheduler
  8. 闭包---在函数内部再定义一个函数
  9. 工作分流是什么意思_【嘉陵特装要闻】重庆嘉陵召开持续推进职工分流安置工作布置会...
  10. idea中ssm集成freemark_基于SSM框架的迷你天猫商城
  11. SMTP 发送内嵌图片 邮件
  12. yii2 获取模块名,控制名,动作方法名
  13. CMD命令备份驱动和安装驱动
  14. vue tinymce安装及使用
  15. ELK企业应用-ekl快速搭建-kibana
  16. 【服务端知识点】MAC OSX 安装MongoDB
  17. 排列组合之错排问题总结
  18. 怎样远程控制别人的电脑
  19. 提取百度新闻的标题、网址、日期和来源
  20. oracle 中 in函数

热门文章

  1. BZOJ 1270: [BeijingWc2008]雷涛的小猫( dp )
  2. 考研编程练习----排名
  3. [转载]UEditor报错TypeError: me.body is undefined
  4. [Everyday Mathematics]20150101
  5. Oracle 安装 网络配置 警告
  6. 恐怖之城(深圳)系列1---K113大巴洗劫一空
  7. c#做端口转发程序支持正向连接和反向链接
  8. Soot生成控制流图
  9. 《Nmap渗透测试指南》—第7章7.8节后台打印机服务漏洞
  10. Javascript构造函数的继承