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相关的内容。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐