Spring IoC底层实现
⭐核心技术点:XML解析+反射
具体思路:
- 根据需求编写XML文件,配置需要创建的bean。
- 编写程序读取XML文件,获取bean相关信息,类、属性、id。
- 根据第2步获取到的信息,结合反射机制动态创建对象,同时完成属性的赋值。
- 将创建好的bean存入Map集合,设置key-value映射,key就是bean中的id值,value就是bean对象。
- 提供方法从Map通过id获取到对应的value。
⭐实现代码如下:
spring_ioc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
xmlns:p="http://www.springframework.org/schema/p">
<bean id="car" class="com.oyrf.entity.Car">
<property name="num" value="1"></property>
<property name="brand" value="宝马"></property>
<property name="price" value="22.8"></property>
</bean>
</beans>
△关键:自定义的ClassPathXmlApplicationContext
MyClassPathXmlApplicationContext.java(当中省略了抽象方法)
public class MyClassPathXmlApplicationContext implements ApplicationContext {
private Map<String,Object> iocMap;
public MyClassPathXmlApplicationContext(String path) {
iocMap = new HashMap<>();
//解析XML
parseXML(path);
}
public void parseXML(String path){
SAXReader saxReader = new SAXReader();
try {
Document document = saxReader.read("src/main/resources/"+path);
Element root = document.getRootElement();
Iterator<Element> rootIter = root.elementIterator();
while (rootIter.hasNext()){
Element bean = rootIter.next();
String idStr = bean.attributeValue("id");
String classStr = bean.attributeValue("class");
//反射动态创建对象
Class clazz = Class.forName(classStr);
Constructor constructor = clazz.getConstructor();
Object object = constructor.newInstance();
//给属性赋值
Iterator<Element> beanIter = bean.elementIterator();
while (beanIter.hasNext()){
Element property = beanIter.next();
String propertyName = property.attributeValue("name");
String propertyValue = property.attributeValue("value");
//获取setter方法
//num对应setNum,brand对应setBrand
String methodName = "set"+propertyName.substring(0,1).toUpperCase() + propertyName.substring(1);
//获取属性类型
Field field = clazz.getDeclaredField(propertyName);
Method method = clazz.getMethod(methodName,field.getType());
Object value = propertyValue;
//类型转换
switch(field.getType().getName()){
case "java.lang.Integer":
value = Integer.parseInt(propertyValue);
break;
case "java.lang.Double":
value = Double.parseDouble(propertyValue);
}
//调用方法
method.invoke(object,value);
}
//存入Map
iocMap.put(idStr,object);
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (ClassNotFoundException e){
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
注意:要对其中一个抽象方法getbean()进行修改:
@Override
public Object getBean(String s) throws BeansException {
return iocMap.get(s);
}
测试类
Test.java
package com.oyrf.ioc;
import com.oyrf.entity.Car;
import org.springframework.context.ApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new MyClassPathXmlApplicationContext("spring_ioc.xml");
Car car=(Car) applicationContext.getBean("car");
System.out.println(car);
}
}