• 自定义简易SpringIOC-XML注入


    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方法就可以获取到相应的值啦.

     

  • 相关阅读:
    SQL2014还原到2008
    SQL SERVER2014 安装 Error code 0x858C001B.
    c++builder XE7 C++11 C++0x 新语法
    c++Builder XE6 MD5 加密算法 BASE64 URL 编码
    手机新功能
    xe fmx 怎么改变button颜色
    XE6 任务栏 控件
    js里面return 和 return false的区别
    web.xml的contextConfigLocation作用及自动加载applicationContext.xml
    mybatis-config.xml配置
  • 原文地址:https://www.cnblogs.com/mmdz/p/15449180.html
Copyright © 2020-2023  润新知