一起写框架-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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/399372.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2064: 分裂 - BZOJ

Description 背景&#xff1a; 和久必分&#xff0c;分久必和。。。 题目描述&#xff1a; 中国历史上上分分和和次数非常多。。通读中国历史的WJMZBMR表示毫无压力。 同时经常搞OI的他把这个变成了一个数学模型。 假设中国的国土总和是不变的。 每个国家都可以用他的国土面积代…

android h5使用缓存_Android SDK 的 H5 打通方案演进 | 数据采集

一、前言近年来&#xff0c;混合开发越来越流行&#xff0c;App 与 H5 的打通需求也越来越迫切。那什么是 App 与 H5 打通呢&#xff1f;所谓 “打通”&#xff0c;是指 H5 集成 JavaScript 数据采集 SDK 后&#xff0c;H5 触发的事件不直接同步给服务端&#xff0c;而是先发给…

简单人物画像_你真的理解用户画像吗?| 船说

“「设计师沙龙」是ARK下半年开始逐渐形成的传统&#xff0c;由ARKers自发组织&#xff0c;分为视觉和交互两类&#xff0c;每月各举办一次。大家围绕一个话题展开&#xff0c;聊聊行业最新案例和工作上的心得&#xff0c;帮助大家共同进步。ARKers表达的观点均为个人见解&…

emoji表情引发的JNI崩溃

今天突然接到客服那边的反馈说&#xff0c;有玩家反馈进游戏后不久就崩溃了&#xff0c;我先是怀疑网络问题&#xff0c;因为一连接聊天成功后就挂了。之后用logcat抓日志&#xff0c;发现挂在jni那里了 JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8…

8cm等于多少像素_「前端剑指offer第5期」物理像素、逻辑像素、CSS像素、PPI、设备像素比是什么...

# 提问物理像素、逻辑像素、CSS像素、PPI、设备像素比是什么&#xff1f;# 回答物理像素代表屏幕上有多少个点&#xff0c;比如1080x2340表示屏幕一排包含1080个物理像素点。逻辑像素表示屏幕展示物体的视觉尺寸是多少。逻辑像素相同表示物体看起来或者打印出来大小一样&#x…

php中获取系统信息的方法

2019独角兽企业重金招聘Python工程师标准>>> $root getenv(DOCUMENT_ROOT); 服务器文档根目录$port getenv(SERVER_PORT); 服务器端口$file getenv(SCRIPT_NAME); 当前执行文件$ua getenv(HTTP_USER_AGENT); 用户UA$method getenv(REQUEST_METHOD); 请求方法$p…

[独家全程图解]ThinkPHP6框架的下载与安装

http://www.php.cn/wenda/159638.html 1. ThinkPHP大事记 2017年4月27日,ThinkPHP5.1-beta.1发布 2017年12月31日, ThinkPHP5.1.0发布,标志着快速进入迭代期 2019年3月3日, ThinkPHP5.1已更新迭代到第35个版本(5.1.35) 2019年3月22日, ThinkPHP5.2的 dev 开发版本也发布了 …

玩转CSS3(一)----CSS3实现页面布局

请珍惜小编劳动成果&#xff0c;该文章为小编原创&#xff0c;转载请注明出处。 摘要&#xff1a; CSS3相对CSS2增加了一些新的布局方式&#xff1a;多栏布局和盒子布局。在这篇文章中&#xff0c;将对CSS2的布局进行简单的回忆&#xff0c;并总结CSS3的布局方式。DIVCSS其实是…

openglshader实现虚拟场景_云桌面,实现办公终端的统一管理与运维

随着无纸化办公和智能化办公的不断推进&#xff0c;在办公过程中传统PC电脑的缺点愈发凸显。传统电脑的性能会随着使用时长增加而降低&#xff0c;系统维护处理时效性较弱&#xff0c;出现问题需要运维人员到现场解决&#xff0c;费时费力。如果出现更换设备的情况&#xff0c;…

前端 == Ajax

Django-Ajax 1.目录 ajax 准备知识&#xff1a;json ajax 简介 jquery 实现的ajax js 实现的ajax jquery.serialize() 上传文件 同源策略与jsonp 2.准备知识&#xff1a;json 1.什么是 json ? 个人回答&#xff1a; json 的作用是 数据交换格式。&#xff08;通过序列化和反序…

WordPress 5.0 换回老版”Classic Editor”经典编辑器教程

WordPress 5.0 正式采用了全新的“Block Editor”编辑器&#xff0c;从而替换了原有“Classic Editor”编辑器&#xff0c;相信有很多人和子凡一样会不习惯或者不喜欢新编辑器&#xff0c;那么新版 WordPress 该如何换回原来的 WordPress 编辑器呢&#xff1f; 不可否认 WordPr…

html5视频播放

<video width"320" height"240" controls"controls"> <source src"test.mp4" type"video/mp4"> Your browser does not support the video tag. </video> IE9对于video标签确实是不支持的&…

判断是否存在此对象_JVM的垃圾回收机制,判断对象是否死亡

这节我们主要讲垃圾收集的一些基本概念&#xff0c;先了解垃圾收集是什么、然后触发条件是什么、最后虚拟机如何判断对象是否死亡。一、前言我们都知道Java和C有一个非常大的区别就是Java有自动的垃圾回收机制&#xff0c;经过半个多世纪的发展&#xff0c;Java已经进入了“自动…

Software--Developer Tools_

Log4net 日志框架 由 Java log4j 移植到 .Net 平台的开源日志框架。 http://logging.apache.org/log4net/index.html 转载于:https://www.cnblogs.com/masterSoul/p/7832317.html

万兆网卡实际吞吐量_AKITIO 10G/NBASE-T PCIe 网卡开箱拆解评测

前言今天来到koolshare评测室的是AKITIO的10G/NBASE-T PCIe扩展网卡(官网链接)&#xff0c;采用PCIe2.0 x4接口&#xff0c;支持10G/5G/2.5G/1G/100Mbps&#xff0c;可以在100m的CAT-6A线缆上达到最高10Gbps的链接速率&#xff0c;或者在100m的CAT-5e线缆上达到最高5Gbps的链接…

【RabbitMQ】8、RabbitMQ之mandatory和immediate

1. 概述 mandatory和immediate是AMQP协议中basic.publish方法中的两个标识位&#xff0c;它们都有当消息传递过程中不可达目的地时将消息返回给生产者的功能。对于刚开始接触RabbitMQ的朋友特别容易被这两个参数搞混&#xff0c;这里博主整理了写资料&#xff0c;简单讲解下这两…

获取异常信息_如何在 ASP.NET Core 中实现全局异常拦截

异常是一种运行时错误&#xff0c;当异常没有得到适当的处理&#xff0c;很可能会导致你的程序意外终止&#xff0c;这篇就来讨论一下如何在 ASP.Net Core MVC 中实现全局异常处理&#xff0c;我会用一些 样例代码 和 截图 来说明这些概念。全局异常处理其实在 ASP.Net Core MV…

Hadoop学习笔记—15.HBase框架学习(基础知识篇)

Hadoop学习笔记—15.HBase框架学习&#xff08;基础知识篇&#xff09; HBase是Apache Hadoop的数据库&#xff0c;能够对大型数据提供随机、实时的读写访问。HBase的目标是存储并处理大型的数据。HBase是一个开源的&#xff0c;分布式的&#xff0c;多版本的&#xff0c;面向列…

二维数组删除_「leetcode」数组:总结篇!(一文搞懂数组题目)

数组理论基础数组是非常基础的数据结构&#xff0c;在面试中&#xff0c;考察数组的题目一般在思维上都不难&#xff0c;主要是考察对代码的掌控能力也就是说&#xff0c;想法很简单&#xff0c;但实现起来 可能就不是那么回事了。首先要知道数组在内存中的存储方式&#xff0c…