手撸spring-ioc,两种方法实现DI
具备以下知识,看起来可能会更舒服:
- dom4j解析xml文件
- java反射机制
项目目录结构
pom.xml
<dependencies>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
</dependencies>
DiyClassPathXmlApplicationContext
package ioc;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class DiyClassPathXmlApplicationContext {
//配置文件基路径
private static final String BASE_PATH = "D:\\java从头到脚\\springStudy\\diySpringIoc\\src\\main\\resources\\";
//配置xml文件路径
private String xmlPath;
//定义此map用于存放bean对象,key为id,值为类对象
private Map<String,Object> map = new HashMap<>();
//构造此对象时传入xml文件配置路径
public DiyClassPathXmlApplicationContext(String xmlPath) {
this.xmlPath = xmlPath;
try {
creatBean();
} catch (Exception e) {
e.printStackTrace();
}
}
//通过反射创建bean实例并且存入map集合中
private void creatBean() throws FileNotFoundException, DocumentException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//1. 获取文件的输入流
FileInputStream fis = new FileInputStream(BASE_PATH+xmlPath);
//2.创建xml读取工具对象
SAXReader sr = new SAXReader();
//3.通过读取工具, 读取XML文档的输入流 , 并得到文档对象
Document doc = sr.read(fis);
//4. 通过文档对象 , 获取文档的根节点对象<beans>
Element root = doc.getRootElement();
//5. 通过根节点, 获取所有子节点<bean>
List<Element> es = root.elements();
if (!es.isEmpty()){
for (Element e : es) {
//获得bean的id
String id = e.attributeValue("id");
//获得bean的class类路径
String classPath = e.attributeValue("class");
//获取bean的子节点
List<Element> elements = e.elements();
//得到对应的class对象
Class<?> clz = Class.forName(classPath);
Object o = null;
if (elements.isEmpty()){//如果bean没有property子节点则直接调用无参构造方法
//无参构造创建对应类的对象
o = clz.getConstructor().newInstance();
}else {
o = clz.getConstructor().newInstance();
//得到此类的获取所有属性,方法一,属性赋值
Field[] fields = clz.getDeclaredFields();
for (int i = 0; i < elements.size(); i++) {
//获得节点对应的value值
String value = elements.get(i).attributeValue("value");
//开放访问权限
fields[i].setAccessible(true);
// Class<?> type = fields[i].getType();
// System.out.println(type);
fields[i].set(o,value);
}
//得到此类的所有方法,方法二,方法赋值
/* Method[] methods = clz.getMethods();
int j = 0;//慢指针,作为bean子节点的下标
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().startsWith("set")){//如果此方法是以set打头
//String pName = methods[i].getName().substring(3).toLowerCase(Locale.ROOT);
//System.out.println(pName);
if (j<elements.size()) {
Object value = elements.get(j).attributeValue("value");
System.out.println(value);
//调用set方法设置对象的属性值
methods[i].invoke(o, value);
//指针后移
j++;
}
}
}*/
}
map.put(id,o);
}
}
}
public Object getBean(String id){
return map.get(id);
}
}
application.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="student" class="pojo.Student">
<property name = "idNum" value="1001"/>
<property name = "name" value="Zy" />
<property name = "school" value="湖理"/>
</bean>
</beans>
student
package pojo;
public class Student {
private String idNum;
private String name;
private String school;
public Student() {
}
public String getIdNum() {
return idNum;
}
public void setIdNum(String idNum) {
this.idNum = idNum;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
@Override
public String toString() {
return "Student{" +
"idNum='" + idNum + '\'' +
", name='" + name + '\'' +
", school='" + school + '\'' +
'}';
}
}
测试类
@Test
public void test2(){
DiyClassPathXmlApplicationContext dca = new DiyClassPathXmlApplicationContext("application.xml");
Student student = (Student) dca.getBean("student");
System.out.println(student);
}
运行截图