模拟Spring源码思想,读取Spring Config配置文件,创建IOC容器,解析spring.xml,创建对象,放入IOC容器,注入依赖

1、Spring.xml

XML 复制代码
<beans>
    <bean id = "orderController" class="com.atguigu.controller.OrderController">
        <property name = "orderService" ref = "orderService"/>
    </bean>
    <bean id = "orderService" class="com.atguigu.service.impl.OrderServiceImpl">
        <property name="orderDao" ref="orderDao"/>
    </bean>
    <bean id = "orderDao" class="com.atguigu.dao.impl.OrderDaoImpl"></bean>
</beans>

2、ApplicationContext.java

java 复制代码
package com.atguigu.ioc;
import java.util.HashMap;
import java.util.Map;
public interface ApplicationContext {
     Map<String,Object> beanMap = new HashMap<>();

     public void registryBean(String beanName,Object component);

     public Map<String,Object> getIocContainer();

     Object getBean(String beanName);
}

3、ClassPathXmlApplicationContext.java

java 复制代码
package com.atguigu.ioc;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class ClassPathXmlApplicationContext implements ApplicationContext{

    private static final String BEAN_LABEL = "bean";
    private static final String ATTR_ID_LABEL = "id";
    private static final String ATTR_CLAZZ_LABEL = "class";
    private static final String PROPERTY_LABEL = "property";
    private static final String PROPERTY_NAME_LABEL = "name";
    private static final String PROPERTY_REF_LABEL = "ref";
    /**
     *        beans
     *    bean  bean  bean
     */
    public ClassPathXmlApplicationContext(String resolvedFilePath) {
        SAXReader saxReader = new SAXReader();
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(resolvedFilePath);
        try {
            Document document = saxReader.read(new BufferedInputStream(is));
            Element rootElement = document.getRootElement();
            List<Element> beanList = rootElement.elements().stream().filter(element -> element.getName().compareTo(BEAN_LABEL) == 0).collect(Collectors.toList());
            if (beanList == null || beanList.size() == 0){
                return;
            }
            beanList.forEach(beanElement -> {
                Attribute idAttr = beanElement.attribute(ATTR_ID_LABEL);
                Attribute clazzAttr = beanElement.attribute(ATTR_CLAZZ_LABEL);
                String id = idAttr.getData().toString();
                String clazzName = clazzAttr.getData().toString();
                try {
                    Object beanInstance = Class.forName(clazzName).getDeclaredConstructor().newInstance();
                    registryBean(id,beanInstance);
                } catch (InstantiationException e) {
                    throw new RuntimeException(e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException(e);
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e);
                }

            });

           beanList.forEach(beanElement -> {
               String componentClazzName = beanElement.attributeValue(ATTR_CLAZZ_LABEL);
               String componentId = beanElement.attributeValue(ATTR_ID_LABEL);
               try {
                   Class<?> componentClazz = Class.forName(componentClazzName);
                   List<Element> propertyList = beanElement.elements().stream().filter(element -> element.getName().compareTo(PROPERTY_LABEL) == 0).collect(Collectors.toList());
                   propertyList.stream().forEach(property -> {
                       String name = property.attributeValue(PROPERTY_NAME_LABEL);
                       String ref = property.attributeValue(PROPERTY_REF_LABEL);
                       try {
                           Field targetInvokeField = componentClazz.getDeclaredField(name);
                           targetInvokeField.setAccessible(true);
                           targetInvokeField.set(getBean(componentId),getBean(ref));
                       } catch (NoSuchFieldException e) {
                           throw new RuntimeException(e);
                       } catch (IllegalAccessException e) {
                           throw new RuntimeException(e);
                       }


                   });
               } catch (Exception e) {
                   throw new RuntimeException(e);
               }

           });

        } catch (DocumentException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println(beanMap);
    }

    @Override
    public void registryBean(String beanName, Object component) {
         beanMap.put(beanName,component);
    }

    @Override
    public Map<String, Object> getIocContainer() {
        return beanMap;
    }

    @Override
    public Object getBean(String beanName) {
        return beanMap.get(beanName);
    }
}

4、OrderDao.java

java 复制代码
package com.atguigu.dao;

public interface OrderDao {
    void start();
}

4.1、OrderDaoImpl.java

java 复制代码
package com.atguigu.dao.impl;
import com.atguigu.dao.OrderDao;
public class OrderDaoImpl implements OrderDao {
    @Override
    public void start() {
        System.out.println("orderDao start...");
    }
}

5、OrderService.java

java 复制代码
package com.atguigu.service;
public interface OrderService {
    void progress();
}

5.1、OrderServiceImpl.java

java 复制代码
package com.atguigu.service.impl;
import com.atguigu.dao.OrderDao;
import com.atguigu.service.OrderService;
public class OrderServiceImpl implements OrderService {
    private OrderDao orderDao;
    @Override
    public void progress() {
        System.out.println("orderService start...");
        orderDao.start();
    }
}

6、OrderController

java 复制代码
package com.atguigu.controller;
import com.atguigu.service.OrderService;
public class OrderController {
    private OrderService orderService;
    public void save(){
        System.out.println("orderController start...");
        orderService.progress();
    }
}

7、Client

java 复制代码
package com.atguigu.client;
import com.atguigu.controller.OrderController;
import com.atguigu.ioc.ApplicationContext;
import com.atguigu.ioc.ClassPathXmlApplicationContext;
public class Client {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring.xml");
        OrderController orderController = (OrderController) applicationContext.getBean("orderController");
        orderController.save();
    }
}

8、pom.xml

XML 复制代码
    <dependencies>
        <dependency>
            <groupId>org.dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>2.1.4</version>
        </dependency>
    </dependencies>


可以使用以下代码来查看 IOC 容器中有哪些 bean 对象:

java 复制代码
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
String[] beans = context.getBeanDefinitionNames();
for(String bean: beans) {
    System.out.println(bean);
}

其中,getBeanDefinitionNames() 方法返回一个字符串数组,里面存放了所有在 IOC 容器中注册的 bean 对象的名称。遍历输出这个数组就能够查看当前 IOC 容器中有哪些 bean 对象。

相关推荐
考虑考虑4 小时前
JDK25模块导入声明
java·后端·java ee
_小马快跑_6 小时前
Java 的 8 大基本数据类型:为何是不可或缺的设计?
java
Re_zero8 小时前
线上日志被清空?这段仅10行的 IO 代码里竟然藏着3个毒瘤
java·后端
洋洋技术笔记8 小时前
Spring Boot条件注解详解
java·spring boot
程序员清风1 天前
程序员兼职必看:靠谱软件外包平台挑选指南与避坑清单!
java·后端·面试
皮皮林5511 天前
利用闲置 Mac 从零部署 OpenClaw 教程 !
java
NE_STOP1 天前
springMVC-HTTP消息转换器与文件上传、下载、异常处理
spring
华仔啊1 天前
挖到了 1 个 Java 小特性:var,用完就回不去了
java·后端
SimonKing1 天前
SpringBoot整合秘笈:让Mybatis用上Calcite,实现统一SQL查询
java·后端·程序员
日月云棠2 天前
各版本JDK对比:JDK 25 特性详解
java