当前位置:网站首页>基于xml实现简单的对象自动创建和依赖注入
基于xml实现简单的对象自动创建和依赖注入
2022-08-08 06:27:00 【写做四月一日的四月一日】
IOC:控制反转,将把对象的创建、复制,管理工作交给业务代码之外的容器来实现。由外部资源来实现对象的创建。
使用ioc技术可以将创建对象的代码和业务代码分开,将资源集中管理,实现资源的可配置和易管理;降低使用资源双方的耦合度。
尝试自己实现一个简单的基于xml的IOC容器。
核心技术:xml解析、反射。
创建dtd约束文件
创建一个syyrjxConstraint.xml对配置文件进行内容约束(文件名任意,xml文件引入时注意文件名相同就行了)
<!ELEMENT beans (bean+) ><!--beans标签下至少要有一个bean标签-->
<!ELEMENT bean (property*)><!--bean标签下可以有任意个property标签-->
<!ELEMENT property (#PCDATA)>
<!ATTLIST bean id ID #REQUIRED><!--bean标签的id属性做为id值不可以重复-->
<!ATTLIST bean className #REQUIRED><!--全限定类名-->
<!ATTLIST property name #REQUIRED><!--属性名-->
<!ATTLIST property value> <!--属性值,基本数据类型-->
<!ATTLIST property reference IDREF> <!--属性值,引用类型-->创建实体类
学生实体类
package xyz.syyrjx.entity;
public class Student {
private int id;
private String name;
private int age;
private ClassRoom classRoom;
public Student() {}
public Student(int id, String name, int age, ClassRoom classRoom) {
this.id = id;
this.name = name;
this.age = age;
this.classRoom = classRoom;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public ClassRoom getClassRoom() {
return classRoom;
}
public void setClassRoom(ClassRoom classRoom) {
this.classRoom = classRoom;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", classRoom=" + classRoom +
'}';
}
}
教室实体类
package xyz.syyrjx.entity;
public class ClassRoom {
private int grade;
private int classNumber;
public ClassRoom() {
}
public ClassRoom(int grade, int classNumber) {
this.grade = grade;
this.classNumber = classNumber;
}
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
public int getClassNumber() {
return classNumber;
}
public void setClassNumber(int classNumber) {
this.classNumber = classNumber;
}
@Override
public String toString() {
return this.grade + "年级" + this.classNumber + "班";
}
}
编写xml文件
xml文件的内容就是我们需要创建的对象的信息,dtd约束文件和xml文件在一个目录下,如果不在一个目录下,需要修改文件路径名称。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans SYSTEM "syyrjxConstraint.dtd">
<beans>
<bean id="student" className="xyz.syyrjx.entity.Student">
<property name="id" value="1" />
<property name="name" value="张三"/>
<property name="age" value="20"/>
<property name="classRoom" reference="classRoom"/>
</bean>
<bean id="classRoom" className="xyz.syyrjx.entity.ClassRoom">
<property name="grade" value="1"/>
<property name="classNumber" value="3"/>
</bean>
</beans>写一个容器类
package xyz.syyrjx.container;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLDecoder;
import java.util.*;
public class BeanFactory {
private static final Map<String,Object> BEAN_MAP = new HashMap<>();
private Map<String,Object> beanMap;
public BeanFactory(){
beanMap = BEAN_MAP;
}
/**
* 类加载时解析xml文件并创建对象到容器种
*/
static {
//等待区,基本数据类型注入完成后再执行引用类型的注入,在基本数据类型注入阶段将需要注入的引用数据类型存入等待区
Map<String,List<Pair<String,String>>> waitArea = new HashMap<>();
//字符集
String charsetName = "utf-8";
//配置文件名
String configurationFileName = null;
try {
configurationFileName = URLDecoder.decode(Objects.requireNonNull(Class.forName("xyz.syyrjx.container.BeanFactory").getClassLoader().getResource("conf/syyrjxBeans.xml")).getPath(),charsetName);
} catch (ClassNotFoundException | UnsupportedEncodingException e) {
e.printStackTrace();
}
File configurationFile = new File(configurationFileName);
//解析xml文件位dom树
Document document = null;
try {
document = Jsoup.parse(configurationFile,charsetName);
} catch (IOException e) {
e.printStackTrace();
}
if (null != document){
//根标签名称
String rootTag = "beans";
//根标签只有一个
Element beans = document.getElementsByTag(rootTag).get(0);
//获取根标签下的子标签(beans下的bean)
Elements beanList = beans.children();
for (Element bean : beanList) {
//bean标签只有id和className属性
String id = bean.attr("id");
String className = bean.attr("className");
//反射生成对象
Class clazz = null;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Object obj = null;
try {
obj = clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
//对象的属性列表
Field[] fields = clazz.getDeclaredFields();
//获取属性标签
Elements properties = bean.children();
for (Element property : properties) {
//获取三个值
String name = property.attr("name");
String value = property.attr("value");
String reference = property.attr("reference");
if ("".equals(value) && "".equals(reference)){
continue;
}
if (!"".equals(reference)){
//加入等待区
if (!waitArea.containsKey(name)){
waitArea.put(id,new ArrayList<>());
}
Pair<String,String> pair = new Pair<>(name,reference);
waitArea.get(id).add(pair);
}else{
//解析,赋值
for (Field field : fields){
field.setAccessible(true);
if (Objects.equals(field.getName(),name)){
String type = field.getType().getSimpleName();
try {
switch (type){
case "int":
case "Integer":
field.set(obj,Integer.parseInt(value));
break;
case "boolean":
case "Boolean":
field.set(obj,Boolean.parseBoolean(value));
break;
case "char":
case "Character":
field.set(obj,value.charAt(0));
break;
case "byte":
case "Byte":
field.set(obj,Byte.parseByte(value));
break;
case "long":
case "Long":
field.set(obj,Long.parseLong(value));
break;
case "double":
case "Double":
field.set(obj,Double.parseDouble(value));
break;
case "float":
case "Float":
field.set(obj,Float.parseFloat(value));
break;
case "short":
case "Short":
field.set(obj,Short.parseShort(value));
break;
default:
field.set(obj,value);
}
}catch (IllegalAccessException e) {
e.printStackTrace();
}
break;
}
}
}
}
//赋值完成加入静态的BEAN_MAP
BEAN_MAP.put(id,obj);
}
//遍历等待区,赋reference值
Set<Map.Entry<String,List<Pair<String,String>>>> entry = waitArea.entrySet();
for (Map.Entry<String, List<Pair<String, String>>> e : entry) {
String id = e.getKey();
List<Pair<String, String>> kAndV = e.getValue();
Object dest = BEAN_MAP.get(id);
Class clazz = dest.getClass();
for (Pair<String,String> pair : kAndV){
String k = pair.getKey();
String v = pair.getVal();
Object src = BEAN_MAP.get(v);
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (Objects.equals(k,field.getName())){
field.setAccessible(true);
try {
field.set(dest,src);
} catch (IllegalAccessException illegalAccessException) {
illegalAccessException.printStackTrace();
}
break;
}
}
}
}
}
}
/**
* 获取容器内的对象
* @param id 对象的id值
* @return 返回对象
*/
public Object get(String id){
return beanMap.get(id);
}
/**
* 容器类的内部类,用来封装引用类型属性到等待区
* @param <K> 键类型
* @param <V> 值类型
*/
private static class Pair<K,V>{
K key;
V val;
public Pair() {}
public Pair(K key, V val) {
this.key = key;
this.val = val;
}
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getVal() {
return val;
}
public void setVal(V val) {
this.val = val;
}
}
}
测试能否获取到这个类

欸嘿,获取到了,在我的业务代码中也没有对student对象的创建(new)。容器创建成功。
补充
使用的xml解析工具为jsoup-1.14.3
边栏推荐
- NVIDIA CUDA 高度并行处理器编程(八):并行模式:直方图计算
- NVIDIA CUDA Highly Parallel Processor Programming (6): Parallel Mode: Convolution
- re模块,初识爬虫,openpyxl模块
- C language judges the problem of big and small endian storage
- Unity object color gradient effect (judgment logic implementation)
- Unity_常用数据分析总结:折线图、条形图(柱状图)、扇形图(饼状图)、雷达图(属性图)
- C# Unicode(万国码)文字转换
- P02 线程的用途
- 排列组合题目小结
- 【图形学】10 UnityShader入门(二)
猜你喜欢
随机推荐
【图形学】09 UnityShader入门(一)
acwing 第63场周赛【2022.08.06】
Unity—ParticleSystem (particle system) and Animator (animation state machine) batch manager
括号问题
如何使用conda,pip安装、更新、查看和卸载重装Pytorch?
Chained queue push and pop related operations
多数之和小结
Nine common interfaces for implementing sequence table in C language
NVIDIA CUDA Highly Parallel Processor Programming (VII): Parallel Mode: Prefix and
《Filter Pruning using Hierarchical Group Sparse》ICPR2020论文详解
P19 美颜相机的实现——基础铺垫1
文件常用操作 IO流原理及分类
状态机控制移位寄存器multisim仿真过程中出现的状态变量和状态转移条件不匹配的问题
【图形学】01 数学部分(一、集合和三角函数)
背包问题小结
Code and ideas for implementing perpetual calendar in C language (detailed tutorial)
Unity3D objects up and down or so rotation (is not affected by axes object itself)
Unity_扇形图(饼状图)+ UI动画
Background Suppression Network for Weakly-supervised Temporal Action Localization
顺序循环队列的创建和基本应用
https://jsoup.org/download








