基于Java反射技术实现简单IOC容器

前言

首先思考一个问题,如果你正在做一个复杂的系统,一个系统模块内有几百个功能业务类,这些类需要使用同一些对象来进行工作。那么,你会怎样去管理这些通用且一样的对象呢?

学习过Spring的朋友会知道,Spring框架为此提供了一种非常先进的思想,即IOC(控制反转)。Spring可以理解为一个工厂,负责对象的创建和对象间关系的维护。IoC即控制反转,简单说就是之前需要使用new的方式创建对象,而Spring框架会从XML文件中根据配置的信息来创建对象,然后放进它自己的容器之中。在程序要使用到该对象的时候,自动注入。

下面就来做一个最简单的IOC容器。

1.创建一个实体类,比如学生类,汽车类

2.创建XML文件配置对象的信息

3.编写一个IOC容器类。这个类工作起来,首先加载XML文件,扫描自己配置的对象信息,之后使用反射技术创建对象,最后将这些

对象放进自己的Map集合中(容器)。外部想要调用这些对象,那么就使用Map的键,来拿到这个集合中对应的值(对象)。

编写一个喜闻乐见的Student学生类。

我做的比较简单,没有使用get() set()方法。

后面使用反射技术可以强制给 private 修饰的属性赋值

package cn.haidnor.bean;

public class Student {

/** 学生姓名 */

private String name;

/** 学生性别 */

private String gender;

/** 学生年龄 */

private int age;

@Override

public String toString() {

return "Student{" +

"name='" + name + '\'' +

", gender='" + gender + '\'' +

", age=" + age +

'}';

}

}

创建XML文件,配置对象信息

  • id 表示在IOC容器(Map)的键
  • class 表示对象类的全类名
  • name 表示对象的各种属性名
  • property下的文本节点表示该属性的值

<?xml version="1.0" encoding="UTF-8"?>

<beans>

<bean id="stu1" class="cn.haidnor.bean.Student">

<property name="name">Lucy</property>

<property name="age">18</property>

<property name="gender">female</property>

</bean>

<bean id="stu2" class="cn.haidnor.bean.Student">

<property name="name">Tom</property>

<property name="age">21</property>

<property name="gender">male</property>

</bean>

<bean id="stu3" class="cn.haidnor.bean.Student">

<property name="name">LiLi</property>

<property name="age">23</property>

<property name="gender">female</property>

</bean>

</beans>

编写IOC容器类

1.首先根据XML中的配置文件,生成学生对象

2.所有的对象都放入到一个Map中

3.提供一个getBean()的方法,传入配置文件中的id,返回对应的对象

package cn.haidnor.core;

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import java.lang.reflect.Field;

import java.util.HashMap;

import java.util.Map;

public class SpringIOC {

/**

* 配置文件地址

*/

private static final String CONFIGURATION_PATH = "resources/applicationContext.xml";

/**

* ioc容器

*/

private static Map<String, Object> ioc = new HashMap<>();

static {

initialization();

}

/**

* 从 ioc 容器中获取指定 bean

*

* @param name 需要获取的 bean 的 id, 对应 XML 配置文件中的 bean id

* @return bean

*/

public static Object getBean(String name) {

return ioc.get(name);

}

/**

* 初始化容器

*/

private static void initialization() {

Document document = null;

try {

DocumentBuilderFactory bdf = DocumentBuilderFactory.newInstance();

DocumentBuilder documentBuilder = bdf.newDocumentBuilder();

document = documentBuilder.parse(CONFIGURATION_PATH);

} catch (Exception e) {

e.printStackTrace();

}

NodeList beanNodes = document.getElementsByTagName("bean");

for (int i = 0; i < beanNodes.getLength(); i++) {

Node node = beanNodes.item(i);

reloadBean(node);

}

}

/**

* 装载 benn

*

* @param beanNode xml 文件 bean 根节点

*/

private static void reloadBean(Node beanNode) {

Element bean = (Element) beanNode;

String id = bean.getAttribute("id"); // IOC 容器中 bean 的名字

String beanClass = bean.getAttribute("class"); // 全类名

// 每个 bean 节点下的全部 property 节点

NodeList childNodes = beanNode.getChildNodes();

Map<String, String> attributeMap = reloadAttribute(childNodes);

// 使用反射构造 bean 对象

Object instance = creatBean(beanClass, attributeMap);

// 将所有的 bean 对象放入容器中

ioc.put(id, instance);

}

/**

* 加载 bean 的属性值

*

* @param attributeNodes 所有的属性 property 节点

* @return Map 属性的名字和值集合

*/

private static Map<String, String> reloadAttribute(NodeList attributeNodes) {

Map<String, String> keyValue = new HashMap<>();

for (int i = 0; i < attributeNodes.getLength(); i++) {

Node filed = attributeNodes.item(i);

if (filed.getNodeType() == Node.ELEMENT_NODE) {

Element element = (Element) filed;

String fileName = element.getAttribute("name");

String value = element.getFirstChild().getNodeValue();

keyValue.put(fileName, value);

}

}

return keyValue;

}

/**

* 构造bean对象

*

* @param className 全类名

* @param attributes 每个对象的属性和

* @return Object 构造完成的 bean 对象

*/

private static Object creatBean(String className, Map<String, String> attributes) {

Object instance = null;

try {

Class<?> clazz = Class.forName(className);

instance = clazz.newInstance();

Field[] fields = clazz.getDeclaredFields();

for (Field field : fields) {

setFiledValue(instance, field, attributes);

}

} catch (Exception e) {

e.printStackTrace();

}

return instance;

}

/**

* 为实例对象的属性赋值

*

* @param instance 实例对象

* @param field 属性字段对象

* @param attributes 属性名与属性值的 Map 集合

*/

private static void setFiledValue(Object instance, Field field, Map<String, String> attributes) {

// 忽略 field 权限检查

field.setAccessible(true);

String type = field.getType().toString();

String name = field.getName();

try {

switch (type) {

case "char":

field.setChar(instance, attributes.get(name).charAt(0));

break;

case "class java.lang.Boolean":

case "boolean":

field.setBoolean(instance, Boolean.parseBoolean(attributes.get(name)));

break;

case "class java.lang.Byte":

case "byte":

field.setByte(instance, Byte.parseByte(attributes.get(name)));

break;

case "class java.lang.Float":

case "float":

field.setFloat(instance, Float.parseFloat(attributes.get(name)));

break;

case "class java.lang.Integer":

case "int":

field.setInt(instance, Integer.parseInt(attributes.get(name)));

break;

case "class java.lang.Long":

case "long":

field.setLong(instance, Long.parseLong(attributes.get(name)));

break;

case "class java.lang.Short":

case "short":

field.setShort(instance, Short.parseShort(attributes.get(name)));

break;

default:

field.set(instance, attributes.get(name));

break;

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

最后编写测试类

  • 不使用new的方式创建学生对象
  • 使用ioc容器getBean()方法获取对象
  • 调用对象的复写的toString()方法

package cn.haidnor.test;

import cn.haidnor.bean.Student;

import cn.haidnor.core.SpringIOC;

public class Test {

public static void main(String[] args) {

// 不使用 new 的方式创建对象, 从容器中获取

Student stu1 = (Student) SpringIOC.getBean("stu3");

// 调用学生类的方法,打印信息

System.out.println(stu1.toString());

}

}

运行结果,控制台打印输出的内容

Student{name='LiLi', gender='female', age=23}

以上是 基于Java反射技术实现简单IOC容器 的全部内容, 来源链接: utcz.com/z/332174.html

回到顶部