实现一个简单的IoC容器
Spring的两大核心,一个是AOP(面向切面编程),另一个是IoC(控制反转)。Spring可以为企业级开发提供各个层面的解决方案。
其中IoC容器就是和DI(依赖注入)一起使用的。
所属模式:
IoC:工厂模式
AOP:代理模式
在Java企业级开发中,Spring框架的IoC(控制反转)容器是最核心的概念之一。本文将带你从零开始实现一个简易的IoC容器,理解Spring IoC容器的底层原理。
一、IoC容器概述
IoC(Inversion of Control)控制反转是Spring框架的核心思想之一,它将对象的创建、依赖注入等控制权从应用程序代码中反转给容器管理。我们实现的简易IoC容器主要包含以下功能:
读取XML配置文件
解析bean定义
实例化bean对象
处理属性注入
提供bean获取接口
IoC的工作原理?
我们在编写Java代码的时候,通常是通过new来创建一个新对象,如下图中。

但是如果在企业级的开发中,数据对象通常是几十成百上万的,此时通过new来实现对象创建似乎很困难,而IoC可以很好的解决这个问题。
控制反转:
在IoC的思想里,创建对象不再由调用者创建,而是交给IoC容器来创建,再推给调用者。

类似于动态代理。
假设实例要操作的文件(XML)如下:
<beans>
<bean id="userService" class="com.example.UserService">
<property name="name" value="张三"/>
<property name="age" value="25"/>
</bean>
</beans>
实现IoC的逻辑:
1.实现了 App licationContext 接口
2.使用 Map<Str ing, Object> 作为Bean容器
3.核心方法:
构造函数:初始化容器并解析XML配置(parseXML)
parseXML():XML解析和Bean初始化的核心方法
getBean():从容器中获取Bean实例
4.XML解析流程:
使用SAXReader读取XML文件
遍历所有 <bean> 元素
通过反射创建Bean实例
处理每个Bean的属性配置
调用setter方法注入属性值
将初始化完成的Bean存入容器
代码如下:
public class MyClassPathXmlApplicationContext implements ApplicationContext {
private Map<String,Object> iocMap;//作为bean容器
public MyClassPathXmlApplicationContext(String path) {
iocMap = new HashMap<>();
//解析 XML
parseXML(path);
}
/**
* 解析XML配置文件并初始化Bean
* @param path XML配置文件路径
*/
public void parseXML(String path) {
SAXReader saxReader = new SAXReader();//SAXReader是 dom4j 库中的一个类,用于解析 XML 文档并构建 DOM树。它
//提供了一种简单的方式来读取XML文件并将其转换为Java对象,以便进行进一步的处理。
try {
// 1. 读取XML文件
Document document = saxReader.read("src/main/resources/" + path);//Document它提供了访问和操作XML文
//档的方法,是解析和生成 XML 的关键类。
Element root = document.getRootElement();
//代表XML文档中的一个元素(标签),用于表示XML中的各个节点。
// 2. 遍历所有bean元素
Iterator<Element> rootIter = root.elementIterator();
while (rootIter.hasNext()) {
Element bean = rootIter.next();
// 3. 获取bean的id和class属性
String idStr = bean.attributeValue("id");
String className = bean.attributeValue("class");
// 4. 使用反射创建Bean实例
Class clazz = Class.forName(className);
Constructor constructor = clazz.getConstructor();
Object object = constructor.newInstance();
// 5. 处理bean的属性配置
Iterator<Element> beanIter = bean.elementIterator();
while (beanIter.hasNext()) {
Element property = beanIter.next();
String propertyName = property.attributeValue("name");
String propertyValue = property.attributeValue("value");
// 6. 构造setter方法名(如:setName)
String methodName = "set" +
propertyName.substring(0, 1).toUpperCase() +
propertyName.substring(1);
// 7. 获取属性类型信息
Field field = clazz.getDeclaredField(propertyName);
Method method = clazz.getMethod(methodName, field.getType());
// 8. 类型转换(处理基本数据类型)
Object value = propertyValue;
switch (field.getType().getName()) {
case "java.lang.Integer":
value = Integer.parseInt(propertyValue);
break;
case "java.lang.Double":
value = Double.parseDouble(propertyValue);
break;
}
// 9. 调用setter方法设置属性值
method.invoke(object, value);
}
// 10. 将初始化完成的Bean存入容器
iocMap.put(idStr, object);
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
/**
* 从容器中获取Bean实例
* @param s Bean的id
* @return Bean实例
* @throws BeansException 如果Bean不存在
*/
@Override
public Object getBean(String s) throws BeansException {
return iocMap.get(s);
}
}
通过这段代码,我们更加清晰的理解我们使用Spring的ApplicationContext解析并读取到bean的过程,有助于我们深入学习IoC相关的内容。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)