自定义简易SpringIOC-XML注入

lautakyan007 阅读:58 2022-07-29 11:53:00 评论:0

Spring的各个模块构建的核心模块之上,Bean包装的是Object对象,Object里面一定是存在数据的,Context给数据提供一个生存空间的,Context就是发现和维护Bean之间的关系的,这个复杂的Bean的关系集合可以说是SpringIOC容器.)

步骤

手写简易版的SpringIOC步骤如下,本次实现过程基于如下的步骤的.

  1. 编写要解析的配置文件

  2. Xml解析获取Bean节点

  3. 通过反射获取对象并设置对象属性值

  4. 获取容器Bean对象

环境

环境搭建:IDEA,Java8,搭建Maven工程。

代码实现

POM文件

        <dependency> 
            <groupId>dom4j</groupId> 
            <artifactId>dom4j</artifactId> 
            <version>1.6.1</version> 
        </dependency>

Bean对象

public class Person { 
    private String name; 
    private String age; 
    private Book book; 
 
    // 省略 get/set/ toString 
}
public class Book { 
    private String name; 
    private String place; 
    private String price; 
 
    // 省略 get/set/ toString 
}

Person.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.xsd"> 
    <!-- bean的配置文件 --> 
    <bean id="book" class="bean.Book"> 
        <property name="name" value="think in java"></property> 
        <property name="place" value="China"></property> 
        <property name="price" value="79"></property> 
    </bean> 
    <bean id="person" class="bean.Person"> 
        <property name="name" value="grl"></property> 
        <property name="age" value="11"></property> 
        <property name="book" ref="book"></property> 
    </bean> 
</beans>

IOC

ApplicationContext 接口

public interface ApplicationContext { 
    Object getBean(String name); 
}

ClassPathXmlApplicationContext 实现

import ioc.factory.ApplicationContext; 
import org.dom4j.Document; 
import org.dom4j.DocumentException; 
import org.dom4j.Element; 
import org.dom4j.io.SAXReader; 
 
import java.io.File; 
import java.lang.reflect.Field; 
import java.lang.reflect.Method; 
import java.net.URISyntaxException; 
import java.net.URL; 
import java.util.*; 
 
/** 
 * @Desc: TODO 基于类路径加载配置文件 
 */ 
public class ClassPathXmlApplicationContext implements ApplicationContext { 
 
    /** 
     * 要解析的配置文件 
     */ 
    private File file; 
    /** 
     * 存放Bean对象的实例 
     */ 
    private Map map = Collections.synchronizedMap(new HashMap()); 
 
    /** 
     * 解析配置文件,实例化容器,将对象存放入容器当中 
     */ 
    public ClassPathXmlApplicationContext(String configFile) throws Exception { 
        URL url = this.getClass().getClassLoader().getResource(configFile); 
        try { 
            file = new File(url.toURI()); 
            xmlParse(file); 
        } catch (URISyntaxException e) { 
            e.printStackTrace(); 
        } 
    } 
 
    /** 
     * 解析xml文件 
     * 
     * @param file 
     */ 
    private void xmlParse(File file) throws DocumentException, 
                                            ClassNotFoundException, 
                                            IllegalAccessException, 
                                            InstantiationException, 
                                            NoSuchFieldException { 
        // 创建saxReader对象 
        SAXReader reader = new SAXReader(); 
        // 通过read方法读取一个文件 转换成Document对象 
        Document document = reader.read(file); 
        // 获取根节点【beans】 
        Element rootElement = document.getRootElement(); 
        // 获得根节点下的所有子节点【bean】 
        List<Element> elements = rootElement.elements(); 
 
        Iterator iterator = elements.iterator(); 
        while (iterator.hasNext()) { 
            Element element = (Element) iterator.next(); 
 
            String id = element.attributeValue("id"); 
            String classPath = element.attributeValue("class"); 
 
            // 使用java的反射机制初始化类 
            Class<?> clazz = Class.forName(classPath); 
            // 反射调用有参函数 
            Object newInstance = clazz.newInstance(); 
            // 获取类的所有方法,然后通过set方法给这个对象设置属性值 
            Method[] methods = clazz.getDeclaredMethods(); 
            // 获取属性【properties】 
            List<Element> sonEle = element.elements(); 
            // 遍历属性下的name,value 
            for (Element el : sonEle) { 
                // 获取配置文件属性名称 
                String attField = el.attributeValue("name"); 
                Object value = el.attributeValue("value"); 
                if (value == null) { 
                    // 属性为引用对象的属性 
                    String ref = el.attributeValue("ref"); 
                    value = map.get(ref); 
                } 
 
                // 获得私有属性 
                Field declaredField = clazz.getDeclaredField(attField); 
                // 暴力反射获取私有属性 
                declaredField.setAccessible(true); 
                // 给有参构造函数赋值【value】 
                declaredField.set(newInstance, value); 
            } 
 
            // 将对象添加到容器里面 
            map.put(id, newInstance); 
        } 
    } 
 
    /** 
     * 获取Bean对象 
     */ 
    public Object getBean(String name) { 
        return map.get(name); 
    } 
}

测试

public class Test { 
    public static void main(String[] args) throws Exception { 
        ApplicationContext context = new ClassPathXmlApplicationContext("Person.xml"); 
        Person person = (Person) context.getBean("person"); 
        System.out.println(person); 
    } 
}

控制台输出:Person{name='grl', age='11', book=Book{name='think in java', place='China', price='79'}}

总结一句话:Java通过配置文件的解读,反射拿到类实例,获取该类的所有Set方法,过滤取出和Xml中配置的属性值,然后反射动态给该属性设置(Xml中配置的值),这样调用相应属性的get方法就可以获取到相应的值啦.

 


本文参考链接:https://www.cnblogs.com/mmdz/p/15449180.html
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

搜索
排行榜
关注我们

一个IT知识分享的公众号