模拟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 对象。

相关推荐
浅陌sss1 小时前
C#中实现XML解析器
xml·c#
此木|西贝2 小时前
【设计模式】享元模式
java·设计模式·享元模式
李少兄3 小时前
解决Spring Boot多模块自动配置失效问题
java·spring boot·后端
bxlj_jcj3 小时前
JVM性能优化之年轻代参数设置
java·性能优化
八股文领域大手子3 小时前
深入理解缓存淘汰策略:LRU 与 LFU 算法详解及 Java 实现
java·数据库·算法·缓存·mybatis·哈希算法
不当菜虚困4 小时前
JAVA设计模式——(八)单例模式
java·单例模式·设计模式
m0_740154674 小时前
Maven概述
java·maven
吗喽对你问好4 小时前
Java位运算符大全
java·开发语言·位运算
Java致死4 小时前
工厂设计模式
java·设计模式·简单工厂模式·工厂方法模式·抽象工厂模式