基于反射与DOM4J实现简易Spring IOC容器
本文通过结合Java反射机制与DOM4J库,模拟实现Spring框架中的控制反转(IOC)核心功能。该方案能够读取XML配置文件,动态实例化对象,并根据配置自动注入属性值。
1. 配置文件:applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="userOne" class="com.example.entity.UserProfile">
<property name="id" value="U001"/>
<property name="name" value="李四"/>
</bean>
<bean id="userTwo" class="com.example.entity.UserProfile">
<property name="id" value="U002"/>
<property name="name" value="王五"/>
</bean>
</beans>
2. 核心实现类:XmlApplicationContext
使用DOM4J解析XML,结合反射创建对象并注入属性。
package com.example.container;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class XmlApplicationContext {
private static final String BEAN_ID = "id";
private static final String BEAN_CLASS = "class";
private static final String PROPERTY_NAME = "name";
private static final String PROPERTY_VALUE = "value";
private final String configPath;
public XmlApplicationContext(String configPath) {
this.configPath = configPath;
}
public Object getBean(String beanName) throws Exception {
if (StringUtils.isBlank(beanName)) return null;
SAXReader reader = new SAXReader();
Document document = reader.read(getClass().getClassLoader().getResourceAsStream(configPath));
Element root = document.getRootElement();
for (Element bean : root.elements("bean")) {
String id = bean.attributeValue(BEAN_ID);
if (!beanName.equals(id)) continue;
String className = bean.attributeValue(BEAN_CLASS);
Class> clazz = Class.forName(className);
Object instance = clazz.getDeclaredConstructor().newInstance();
// 注入属性
for (Element prop : bean.elements("property")) {
String fieldName = prop.attributeValue(PROPERTY_NAME);
String fieldValue = prop.attributeValue(PROPERTY_VALUE);
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(instance, fieldValue);
}
return instance;
}
throw new IllegalArgumentException("No bean found with id: " + beanName);
}
}
3. 测试实体类:UserProfile
package com.example.entity;
public class UserProfile {
private String id;
private String name;
public UserProfile() {
System.out.println("UserProfile 构造函数被调用");
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "UserProfile{id='" + id + "', name='" + name + "'}";
}
}
4. 使用示例
public class TestMain {
public static void main(String[] args) throws Exception {
XmlApplicationContext context = new XmlApplicationContext("applicationContext.xml");
UserProfile user = (UserProfile) context.getBean("userOne");
System.out.println(user);
}
}