Java 反射和内省实现spring的IOC和DI
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的更多相关文章
- spring的IOC,DI及案例详解
一:spring的基本特征 Spring是一个非常活跃的开源框架:它是一个基于Core来架构多层JavaEE系统的框架,它的主要目的是简化企业开发.Spring以一种非侵入式的方式来管理你的代码,Sp ...
- 对Spring中IOC和DI的理解
前几篇讲了Spring中IOC和DI的用法,本篇应该放到三篇之前,但一直没有想到好的讲解方式,后参考https://blog.csdn.net/luoyepiaoxue2014/article/det ...
- Spring之IOC,DI,动态代理,反射
Spring框架是J2EE开发中一个使用广泛的框架,它使得dao和service层的维护更加便利.Spring框架有两个重要的特征,一个是IOC,另一个是AOP.我们在这里主要介绍IOC,以及IOC中 ...
- java反射的应用+mybatis+spring动态生成数据库表
最近接触了一个类似于代码生成工具的活.思路是,通过java的反射机制得到类的字段和字段类型, 从而可以创建一个map集合存储表名(由类名决定的特殊结构字符串),表字段(由类变量确定),表字段类型(由变 ...
- 转载百度百科上的强回复,关于spring的IOC和DI
IoC与DI 首先想说说IoC(Inversion of Control,控制倒转).这是spring的核心,贯穿始终.所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命 ...
- 总结一下 Spring的IOC、DI
国庆节刚过,应一些朋友的提问,总结一下Spring中IOC也即DI的通俗理解. 网友wm5920解释: IOC控制反转:说的是创建对象实例的控制权从代码控制剥离到IOC容器控制,实际就是你在xml文件 ...
- spring核心技术IOC,DI
在介绍Spring中IOC之前,先说说Spring的优势有哪些.首先1.方便解耦,简化开发:就是说将对象间的依赖关系交给Spring进行控制,避免了编码造成的过度耦合.2.AOP编程的支持:方便进行切 ...
- Spring的ioc(DI)复习概念和原理简介
IOC的好处 ioc或者说di的概念很显然了,反转控制和依赖注入,那本来直接new就行的东西,为什么要搞这么复杂呢?? 开发维护方便,高层设计不用依赖底层的,不然底层一个类改下构造器,高层就全要改,因 ...
- 关于Spring的IOC和DI
原始调用模型 Spring的演化过程 Spring的调用过程 ======================================= IoC[理解][应用][重点] 1.IoC(Inversi ...
随机推荐
- angular4.0项目main.ts详解
main.ts负责引导整个angular应用的起点 // 导入enableProdMode用来关闭angular开发者模式 import { enableProdMode } from '@angul ...
- Python模块学习------ 多线程threading(1)
# Method 1: 创建一个Thread实例,传给它一个函数:import threading from time import sleep, ctime loops = [4,2] def lo ...
- hexo next主题为博客添加分享功能
title: hexo next主题为博客添加分享功能 date: 2018-01-06 20:20:02 tags: [hexo博客, 博客配置] categories: hexo next主题配置 ...
- windows 异常处理
为了程序的健壮性,windows 中提供了异常处理机制,称为结构化异常,异常一般分为硬件异常和软件异常,硬件异常一般是指在执行机器指令时发生的异常,比如试图向一个拥有只读保护的页面写入内容,或者是硬件 ...
- Jmeter发送JDBC请求
下午花了两个小时研究了一下Jmeter发送JDBC请求,现在把基本操作流程分享一下. 做JDBC请求,首先需要两个jar包:mysql驱动-mysql-connector-java-5.1.13-bi ...
- 《跟我学IDEA》六、插件(编码利器)
idea的另一个可爱之处,就是它的强大的插件,下面我以CodeGlance插件为例,这个可以快速定位代码. 第一节:安装插件 ● All plugins 显示所有插件. ● Enabled 显示当前所 ...
- js和jquery通过this获取html标签中的属性值
<html> <head> <script type="text/javascript" src="jquery-1.10.2.min.js ...
- iptables网络安全服务详细使用
iptables防火墙概念说明 开源的基于数据包过滤的网络安全策略控制工具. centos6.9 --- 默认防火墙工具软件iptables centos7 --- 默认防火墙工具软件fire ...
- 一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](三)
前言 上一篇<一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](二)>我们通过如下操作: 创建实体及工具类 创建Re ...
- BZOJ 3211: 花神游历各国【线段树区间开方问题】
3211: 花神游历各国 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 3514 Solved: 1306[Submit][Status][Discu ...