1.构造两个JavaBean 

  1. package com.spring.model;
  2.  
  3. public class People {
  4.  
  5. private Car car;
  6.  
  7. public Car getCar() {
  8. return car;
  9.  
  10. }
  11.  
  12. public void setCar(Car car) {
  13. this.car = car;
  14. }
  15.  
  16. }
  1. package com.spring.model;
  2.  
  3. public class Car {
  4.  
  5. private String name;
  6.  
  7. public String getName() {
  8. return name;
  9. }
  10.  
  11. public void setName(String name) {
  12. this.name = name;
  13. }
  14.  
  15. public void show() {
  16. System.out.println("我是"+name+"车");
  17. }
  18.  
  19. }

2.构建一个类似于spring配置的xml文件 spring-bean.xml

  按照spring一样的格式配置好节点和属性

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans>
  3. <bean id="car" class="com.spring.model.Car">
  4. </bean>
  5.  
  6. <bean id="people" class="com.spring.model.People">
  7. <property name="car" ref="car"></property>
  8. </bean>
  9. </beans>

3.构建一个类似spring加载配置文件的类 里面运用了反射和内省的机制

  1. package com.spring.core;
  2.  
  3. import java.beans.BeanInfo;
  4. import java.beans.Introspector;
  5. import java.beans.PropertyDescriptor;
  6. import java.util.HashMap;
  7. import java.util.List;
  8. import java.util.Map;
  9.  
  10. import org.dom4j.Document;
  11. import org.dom4j.Element;
  12. import org.dom4j.Node;
  13. import org.dom4j.io.SAXReader;
  14.  
  15. /**
  16. *
  17. * 模仿spring IOC、DI 底层实现
  18. * @author GET_CHEN
  19. *
  20. */
  21. public class ClassPathXmlApplicationContext {
  22. private String configXml;
  23. private Map<String,Object> map = new HashMap<String,Object>();//保存配置文件中的id和class所实例化出来的对象
  24. public ClassPathXmlApplicationContext(String configXml) {
  25. this.configXml = configXml;
  26. this.doImplement();
  27. }
  28.  
  29. /**
  30. * 实现文档的解析
  31. * 通过反射实现IOC
  32. * 通过内省实现DI
  33. */
  34. private void doImplement() {
  35. SAXReader saxReader = new SAXReader();
  36. try {
  37. //通过dom4j解析文档
  38. Document doucment = saxReader.read(this.getClass().getClassLoader().getResourceAsStream(configXml));
  39.  
  40. //获取beans下面的所有bean节点
  41. List<Node> beanNodes = doucment.selectNodes("beans/bean");
  42.  
  43. if(beanNodes == null || beanNodes.size() <= 0) return;
  44. //遍历所有的bean节点,将id和class添加到map中
  45. for (Node bean : beanNodes) {
  46. //将节点转为元素
  47. Element element = (Element)bean;
  48. //获取元素的相关属性内容
  49. String beanId = element.attributeValue("id");
  50. String beanClass = element.attributeValue("class");
  51. //——————————————IOC的实现————————————————
  52. //通过反射将class所对应的对象,实例化出来,保存到map中 --------------> 这一步实现了IOC
  53. map.put(beanId, Class.forName(beanClass).newInstance());
  54. }
  55.  
  56. //——————————————————DI的实现——————————————————
  57. //获取所有的属性标签
  58. List<Node> propertyNodes = doucment.selectNodes("beans/bean/property");
  59.  
  60. if(propertyNodes != null && propertyNodes.size() > 0) {
  61. //遍历获取name属性和ref属性
  62.  
  63. for (Node property : propertyNodes) {
  64. //将节点转为元素
  65. Element element = (Element) property;
  66. //获取name属性和ref属性
  67. String proName = element.attributeValue("name");
  68. String proRef = element.attributeValue("ref");
  69.  
  70. //获取当前元素的直接父元素
  71. Element parent = element.getParent();
  72. //获取父元素所对应的id属性
  73. String parentId = parent.attributeValue("id");
  74.  
  75. //—————————————————— 内省实现依赖注入 ———————————
  76. //获取父元素的字节码对象
  77. Class parentClass = map.get(parentId).getClass();
  78. //通过内省类,获取父元素所指向的类的所有信息(内省对象)
  79. //第二个参数为不需要内省的类,除去Object,为了防止遍历到Object类中的set方法中的参数
  80. BeanInfo beanInfo = Introspector.getBeanInfo(parentClass,Object.class);
  81. //通过内省对象,获取父元素所指向的类的所有属性描述
  82. PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
  83. //遍历属性元素
  84. for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
  85. //获取set方法所对应的属性名
  86. String name = propertyDescriptor.getName();
  87. System.out.println(name+"-------");
  88. //如果 父元素所指向的类中的setter方法的名称 存在 与 配置中其子标签property中name属性相同的值就进行注入
  89. //即:<property name="car"/> 中的 car 与 People类中的 public void setCar;中的car全小写相同时候
  90. if(proName.equals(name)) {
  91. //注入
  92. //将ref对应的对象,注入给父级元素指向对象(内省对象)的set方法参数所对应的对象
  93. //即:完成 new People().setCar(car) 的工作
  94. propertyDescriptor.getWriteMethod().invoke(map.get(parentId), new Object[] {map.get(proRef)});
  95. }
  96. }
  97.  
  98. }
  99.  
  100. }
  101.  
  102. } catch (Exception e) {
  103.  
  104. e.printStackTrace();
  105. }
  106.  
  107. }
  108.  
  109. /**
  110. *
  111. * 获取保存在map中的实例对象,并返回
  112. * @param beanName
  113. * @return
  114. */
  115. public Object getBean(String beanName) {
  116. return map.get(beanName);
  117. }
  118.  
  119. }

4.测试代码

  1. package com.spring.test;
  2.  
  3. import org.junit.Test;
  4.  
  5. import com.spring.core.ClassPathXmlApplicationContext;
  6. import com.spring.model.Car;
  7. import com.spring.model.People;
  8.  
  9. public class TestDemo {
  10.  
  11. @Test
  12. public void h() {
  13. ClassPathXmlApplicationContext bean = new ClassPathXmlApplicationContext("com/spring/config/spring-bean.xml");
  14.  
  15. People people = (People) bean.getBean("people");
  16.  
  17. Car car = people.getCar();
  18. car.setName("奔驰");
  19. car.show();
  20. }
  21.  
  22. }

5.运行结果

  1. car-------
  2. 我是奔驰车

总结:高大上的spring就是利用反射和内省的机制完成对于一个类的管理,和相关类的注入的。控制反转主要使用的是反射机制,通过Class.fromName,获取类的字节码对象并实例化。依赖注入就是通过内省获取一个类并类中的set方法所set的一个对象,通过这个对象所对应的名称,获取在map中与之对应的实例化对象之后。通过内省的对象调用 真实的set方法,将已实例好的对象赋值给内省对象中所对应的成员变量

Java 反射和内省实现spring的IOC和DI的更多相关文章

  1. spring的IOC,DI及案例详解

    一:spring的基本特征 Spring是一个非常活跃的开源框架:它是一个基于Core来架构多层JavaEE系统的框架,它的主要目的是简化企业开发.Spring以一种非侵入式的方式来管理你的代码,Sp ...

  2. 对Spring中IOC和DI的理解

    前几篇讲了Spring中IOC和DI的用法,本篇应该放到三篇之前,但一直没有想到好的讲解方式,后参考https://blog.csdn.net/luoyepiaoxue2014/article/det ...

  3. Spring之IOC,DI,动态代理,反射

    Spring框架是J2EE开发中一个使用广泛的框架,它使得dao和service层的维护更加便利.Spring框架有两个重要的特征,一个是IOC,另一个是AOP.我们在这里主要介绍IOC,以及IOC中 ...

  4. java反射的应用+mybatis+spring动态生成数据库表

    最近接触了一个类似于代码生成工具的活.思路是,通过java的反射机制得到类的字段和字段类型, 从而可以创建一个map集合存储表名(由类名决定的特殊结构字符串),表字段(由类变量确定),表字段类型(由变 ...

  5. 转载百度百科上的强回复,关于spring的IOC和DI

    IoC与DI   首先想说说IoC(Inversion of Control,控制倒转).这是spring的核心,贯穿始终.所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命 ...

  6. 总结一下 Spring的IOC、DI

    国庆节刚过,应一些朋友的提问,总结一下Spring中IOC也即DI的通俗理解. 网友wm5920解释: IOC控制反转:说的是创建对象实例的控制权从代码控制剥离到IOC容器控制,实际就是你在xml文件 ...

  7. spring核心技术IOC,DI

    在介绍Spring中IOC之前,先说说Spring的优势有哪些.首先1.方便解耦,简化开发:就是说将对象间的依赖关系交给Spring进行控制,避免了编码造成的过度耦合.2.AOP编程的支持:方便进行切 ...

  8. Spring的ioc(DI)复习概念和原理简介

    IOC的好处 ioc或者说di的概念很显然了,反转控制和依赖注入,那本来直接new就行的东西,为什么要搞这么复杂呢?? 开发维护方便,高层设计不用依赖底层的,不然底层一个类改下构造器,高层就全要改,因 ...

  9. 关于Spring的IOC和DI

    原始调用模型 Spring的演化过程 Spring的调用过程 ======================================= IoC[理解][应用][重点] 1.IoC(Inversi ...

随机推荐

  1. angular4.0项目main.ts详解

    main.ts负责引导整个angular应用的起点 // 导入enableProdMode用来关闭angular开发者模式 import { enableProdMode } from '@angul ...

  2. Python模块学习------ 多线程threading(1)

    # Method 1: 创建一个Thread实例,传给它一个函数:import threading from time import sleep, ctime loops = [4,2] def lo ...

  3. hexo next主题为博客添加分享功能

    title: hexo next主题为博客添加分享功能 date: 2018-01-06 20:20:02 tags: [hexo博客, 博客配置] categories: hexo next主题配置 ...

  4. windows 异常处理

    为了程序的健壮性,windows 中提供了异常处理机制,称为结构化异常,异常一般分为硬件异常和软件异常,硬件异常一般是指在执行机器指令时发生的异常,比如试图向一个拥有只读保护的页面写入内容,或者是硬件 ...

  5. Jmeter发送JDBC请求

    下午花了两个小时研究了一下Jmeter发送JDBC请求,现在把基本操作流程分享一下. 做JDBC请求,首先需要两个jar包:mysql驱动-mysql-connector-java-5.1.13-bi ...

  6. 《跟我学IDEA》六、插件(编码利器)

    idea的另一个可爱之处,就是它的强大的插件,下面我以CodeGlance插件为例,这个可以快速定位代码. 第一节:安装插件 ● All plugins 显示所有插件. ● Enabled 显示当前所 ...

  7. js和jquery通过this获取html标签中的属性值

    <html> <head> <script type="text/javascript" src="jquery-1.10.2.min.js ...

  8. iptables网络安全服务详细使用

    iptables防火墙概念说明 开源的基于数据包过滤的网络安全策略控制工具. centos6.9  --- 默认防火墙工具软件iptables centos7    --- 默认防火墙工具软件fire ...

  9. 一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](三)

    前言 上一篇<一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](二)>我们通过如下操作: 创建实体及工具类 创建Re ...

  10. BZOJ 3211: 花神游历各国【线段树区间开方问题】

    3211: 花神游历各国 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 3514  Solved: 1306[Submit][Status][Discu ...