1.构造两个JavaBean 

package com.spring.model;

public class People {

    private Car car;

    public Car getCar() {
return car; } public void setCar(Car car) {
this.car = car;
} }
package com.spring.model;

public class Car {

    private String name;

    public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public void show() {
System.out.println("我是"+name+"车");
} }

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

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

<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="car" class="com.spring.model.Car">
</bean> <bean id="people" class="com.spring.model.People">
<property name="car" ref="car"></property>
</bean>
</beans>

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

package com.spring.core;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader; /**
*
* 模仿spring IOC、DI 底层实现
* @author GET_CHEN
*
*/
public class ClassPathXmlApplicationContext {
private String configXml;
private Map<String,Object> map = new HashMap<String,Object>();//保存配置文件中的id和class所实例化出来的对象
public ClassPathXmlApplicationContext(String configXml) {
this.configXml = configXml;
this.doImplement();
} /**
* 实现文档的解析
* 通过反射实现IOC
* 通过内省实现DI
*/
private void doImplement() {
SAXReader saxReader = new SAXReader();
try {
//通过dom4j解析文档
Document doucment = saxReader.read(this.getClass().getClassLoader().getResourceAsStream(configXml)); //获取beans下面的所有bean节点
List<Node> beanNodes = doucment.selectNodes("beans/bean"); if(beanNodes == null || beanNodes.size() <= 0) return;
//遍历所有的bean节点,将id和class添加到map中
for (Node bean : beanNodes) {
//将节点转为元素
Element element = (Element)bean;
//获取元素的相关属性内容
String beanId = element.attributeValue("id");
String beanClass = element.attributeValue("class");
//——————————————IOC的实现————————————————
//通过反射将class所对应的对象,实例化出来,保存到map中 --------------> 这一步实现了IOC
map.put(beanId, Class.forName(beanClass).newInstance());
} //——————————————————DI的实现——————————————————
//获取所有的属性标签
List<Node> propertyNodes = doucment.selectNodes("beans/bean/property"); if(propertyNodes != null && propertyNodes.size() > 0) {
//遍历获取name属性和ref属性 for (Node property : propertyNodes) {
//将节点转为元素
Element element = (Element) property;
//获取name属性和ref属性
String proName = element.attributeValue("name");
String proRef = element.attributeValue("ref"); //获取当前元素的直接父元素
Element parent = element.getParent();
//获取父元素所对应的id属性
String parentId = parent.attributeValue("id"); //—————————————————— 内省实现依赖注入 ———————————
//获取父元素的字节码对象
Class parentClass = map.get(parentId).getClass();
//通过内省类,获取父元素所指向的类的所有信息(内省对象)
//第二个参数为不需要内省的类,除去Object,为了防止遍历到Object类中的set方法中的参数
BeanInfo beanInfo = Introspector.getBeanInfo(parentClass,Object.class);
//通过内省对象,获取父元素所指向的类的所有属性描述
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
//遍历属性元素
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
//获取set方法所对应的属性名
String name = propertyDescriptor.getName();
System.out.println(name+"-------");
//如果 父元素所指向的类中的setter方法的名称 存在 与 配置中其子标签property中name属性相同的值就进行注入
//即:<property name="car"/> 中的 car 与 People类中的 public void setCar;中的car全小写相同时候
if(proName.equals(name)) {
//注入
//将ref对应的对象,注入给父级元素指向对象(内省对象)的set方法参数所对应的对象
//即:完成 new People().setCar(car) 的工作
propertyDescriptor.getWriteMethod().invoke(map.get(parentId), new Object[] {map.get(proRef)});
}
} } } } catch (Exception e) { e.printStackTrace();
} } /**
*
* 获取保存在map中的实例对象,并返回
* @param beanName
* @return
*/
public Object getBean(String beanName) {
return map.get(beanName);
} }

4.测试代码

package com.spring.test;

import org.junit.Test;

import com.spring.core.ClassPathXmlApplicationContext;
import com.spring.model.Car;
import com.spring.model.People; public class TestDemo { @Test
public void h() {
ClassPathXmlApplicationContext bean = new ClassPathXmlApplicationContext("com/spring/config/spring-bean.xml"); People people = (People) bean.getBean("people"); Car car = people.getCar();
car.setName("奔驰");
car.show();
} }

5.运行结果

car-------
我是奔驰车

总结:高大上的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. JSP EL隐含对象

    JSP 内置对象 JSP EL隐含对象 描述 page pageScope page 作用域 request requestScope request 作用域 session sessionScope ...

  2. Java内存分配以及GC

    转自http://www.cnblogs.com/hnrainll/archive/2013/11/06/3410042.html  写的太棒了,简单易懂 Java垃圾回收概况 Java GC(Gar ...

  3. 前端开发chrome console的使用 :评估表达式 – Break易站

    本文内容来自:chrome console的使用 :评估表达式 – Break易站 从 DevTools 控制台使用它的某个评估功能查看页面上任意项目的状态. DevTools 控制台让您可通过特定方 ...

  4. Wechat 微信端正确播放audio、video的姿势

    在开发微信项目时,有在项目中播放音频(audio)和视频(video)的需求: 在开发中,我们会遇到的问题 audio.video在Android和IOS系统上的兼容性: video播放完成后,跳出浏 ...

  5. 【转】彻底理解js中this的指向,不必硬背。

    首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然 ...

  6. Pandas系列之入门篇

    Pandas系列之入门篇 简介 pandas 是 python用来数据清洗.分析的包,可以使用类sql的语法方便的进行数据关联.查询,属于内存计算范畴, 效率远远高于硬盘计算的数据库存储.另外pand ...

  7. windows 连接Linux

    服务器:阿里云 ecs 从 Windows 环境远程登录 Linux 实例 远程登录软件的用法大同小异.本文档以 Putty 为例,介绍如何远程登录实例.Putty 操作简单.免费.免安装, 下载地址 ...

  8. Elastic-Job-一个分布式调度解决方案

    注:Elastic-Job是一个分布式调度解决方案,由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成.Elastic-Job-Lite定位为轻量级无中心化 ...

  9. 【括号问题】$("li:lt(" + (idx + 1) + ")") 手风琴效果注意事项

    $("li:lt(" + (idx + 1) + ")").each(function(i){ 注意,这里必须要加括号,是因为如果不加,idx与前面  &quo ...

  10. 关于FPGA的一些你必须知道的概念

    前仿真也称为功能仿真,主旨在于验证电路的功能是否符合设计要求,其特点是不考虑电路门延迟与线延迟,主要是验证电路与理想情况是否一致.可综合FPGA代码是用RTL级代码语言描述的,其输入为RTL级代码与T ...