一起写框架-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;而是先发给…

渐渐褪色的彩虹 好像一个梦

渐渐褪色的彩虹 好像一个梦 ——初梦 好像从来没写过游记呢...就权当记流水账随便写一些吧 11.10 Day 0 期待又紧张&#xff0c; 像以前一样坐高铁&#xff0c; 车上打了打几个板子&#xff0c;抵达广州&#xff0c; 时间过的真快啊... 到达酒店&#xff0c; 这也许又(?)是我…

php 开发框架 (资料收集)

PHP最流行的框架是Laravel, Symfony, CodeIgniter, Yii 1 and 2&#xff0c;Phalcon 和其他一些&#xff0c;这些工具能帮你创建功能强大而整洁的应用程序 Laravel与thinkPHP的异同点 主要区别:(thinkPHP更适合国人的编码习惯) TP5更简单实用&#xff0c;文档丰富&#xff0c;…

Android的Button按钮,ACTION_UP事件不触发解决方案

在android 编程时&#xff0c;有时候要实现当Button一直按下的时候&#xff0c;执行一些逻辑代码&#xff0c;当按钮弹起的时候&#xff0c;终止这些逻辑代码的执行。 比如在 设置页面的滑动开关时&#xff0c;如果不监听ACTION_CANCEL&#xff0c;在滑动到中间时&#xff0c;如…

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

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

try catch线程问题???

try。。。catch 在遇见异常是会开启一个新的线程&#xff0c;用来处理异常&#xff0c;转载于:https://www.cnblogs.com/Flyrun/p/7828788.html

thinkphp 3 升到 thinkphp 5 或更高 ( 资料收集)

https://www.cnblogs.com/shy-/p/10447827.html thinkphp3.2升级至thinkphp5.0.24 view文件# 修改文件名# 把tp3.2.3\app\module\view文件夹下所有文件夹拷贝至tp5\app\module\view打开cmd命令窗口&#xff0c;cd至view文件夹下&#xff0c;执行dir /b 1.bat使用notepad打开…

emoji表情引发的JNI崩溃

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

[Java]向上/下转型Casting

一、向上转型。 通俗地讲即是将子类对象转为父类对象。此处父类对象可以是接口。 1&#xff0c;向上转型中的方法调用。 看下面代码&#xff1a; 注意这里的向上转型&#xff1a;Animal bnew Bird(); //向上转型b.eat(); 此处将调用子类的eat()方法。原因&#xff1a;b实际指向…

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

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

Python学习之路:函数介绍

编程&#xff1a;面向对象&#xff1a;华山派----->类---->class 面向过程&#xff1a;少林派----->过程--->def 一段段的函数和功能包含在过程中 函数式编程&#xff1a;逍遥派--->函数---->def 过程就是没有return返回值的函数 函数的定义&#xff1a;数学…

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;通过序列化和反序…

Objective-c 程序结构

类是Objective-c的核心&#xff0c;Objective-c程序都是围绕类进行的。Objective-c程序至少包含以下三个部分&#xff1a; 1、类接口&#xff1a;定义了类的数据和方法&#xff0c;但是不包括方法的实现代码。 2、类实现&#xff1a;仓储 了实现类方法的代码。 3、应用程序&…

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

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