SpringIoc以及set注入八种基本类型的简单实现

主要涉及到的技术以及API

反射、xml定义和解析、树模型
反射可以在代码运行状态下动态的创建对象以及调用方法。

API:Dom4j、Class、Field、Method。
请仔细阅读接下来的API详解,为代码的阅读进行铺垫。

Dom4j

org.dom4j.io.SAXreader - Xml读取工具。
                       - Document read(InputStream is) 读取输入流,并返回文档对象。

org.dom4j.Document     - 文档对象
                       - Element getRootElement() 通过文档对象,获取xml文档的根节点。

org.dom4j.Element      - 元素/节点对象,一个Element对象就表示一个xml文档的节点。
                       - String getName() 获取当前节点的名称。
                       - List<Element> elements() 获取当前节点的所有子节点。
                       - String attributeValue("属性名称") 获取当前节点的属性值

Class

java.lang.Class        - 类对象,该类的实例由Java虚拟机和类加载器自动构造。
                       - static Class forName(String className) 根据参数自定的类名创建类对象。
                       - T newInstance() 创建该class对象所表示类型的实例。
                       - Field getDeclaredField(String name) 根据参数指定的name获取类型的字段/成员变量。
                       - Method[] getMethods() 用于获取Class对象所表示类中的所有公共方法。
                        

Field

java.lang.reflect.Field    - 单个 字段/成员变量 对象
                           - void setAccessible(boolean falg)java是门安全的语言,字段默认不可暴力访问,想要通过这种方式访问某个字段,需要打开访问权限。
                           - Type getGenericType() 获取字段类型。

Method

java.lang.reflect.Method    - 用于描述获取到的单个 成员方法 信息。
                            - String getName() 获取当前方法名称 如setName。
                            - Object invoke(Object obj, Object... args) 使用参数对象 obj 去调用该 Method 对象所表示的成员方法,实参传递 args。
                            - 若该 Method 对象表示Person类中setName()方法,则调用该方法就是 obj.setName()。

铺垫完毕 上代码

首先是Person类

展开查看

public class Person {

    private int age;
    private String name;

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Person() {
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
}

第二部分 xml文档

展开查看

第三部分 XmlUtil类

展开查看

public class XmlUtil {
    public static void main(String[] args) throws Exception {
        XmlUtil xmlUtil = new XmlUtil("beans.xml");
        Object bean = xmlUtil.getBean("1002");
        Person p = (Person)bean;
        System.out.println(p);
    }

    Map map = new HashMap();

    /**
     * @param xmlName 想要解析的xml文档
     * @throws Exception
     */
    XmlUtil(String xmlName) throws Exception {
        //加载输入流
        InputStream is = getClass().getClassLoader().getResourceAsStream(xmlName);
        //创建解析器
        SAXReader saxReader = new SAXReader();
        //解析输入流,得到整个文档
        Document document = saxReader.read(is);
        //调用init
        init(document);
    }

    public void  init(Document document) throws Exception {
        //获取文档中的根元素,也就是xml中的beans标签
        Element rootElement = document.getRootElement();
        //通过根元素,获取文档中所有的bean标签
        List beans = rootElement.elements();
        //声明Class类型的引用
        Class cls;
        //声明实列引用,后续执行方法时用到
        Object instance;
        //声明String类型的beanId,充当Map集合中的key
        String beanId;
        //依次取出bean标签
        for (Element bean:beans){
            //获取bean标签的class属性值
            String className = bean.attributeValue("class");
            //获取bean标签的id属性值
            beanId = bean.attributeValue("id");
            //根据获取的class属性值创建Class对象
            cls = Class.forName(className);
            //根据cls记录的类创建实列
            instance = cls.newInstance();
            //获取bean标签下的所有property标签
            List propertys = bean.elements();
            //挨个取出property标签
            for (Element property : propertys){
                //获取property标签的name属性值
                String name = property.attributeValue("name");
                //然后在cls真正指向的类型中获取name中存储的字段
                Field field = cls.getDeclaredField(name);
                //如果字段是private修饰,需要手动打开访问权限
                field.setAccessible(true);
                //获取这个字段的类型,用于后续赋值时的类型判断
                Type type = field.getGenericType();
                //开始拼接set方法,拼接的方式是 "set"+字段 , 用于后续寻找想要使用的set方法
                String methodName = "set" + name;
                //获取cls真正指向类型的所有方法
                Method[] methods = cls.getMethods();
                String value = property.attributeValue("value");
                //遍历所有的方法,并找到吻合的set方法
                for (Method method : methods){
                    //获取方法名,调用String类中的compareToIgnoreCase方法与已经拼接好的 set 方法做比较
                    if (method.getName().compareToIgnoreCase(methodName) == 0) {
                        if (type.equals(value.getClass())) {
                             method.invoke(instance, value);
                        }else if(type == Integer.TYPE){
                            int i = Integer.parseInt(value);
                            method.invoke(instance,i);
                        }
                        /*
                        * 。。。这里可以写需要判断的类型
                        * */

                    }
                }

            }
            //所有流程执行完毕,将准备好的 beanId 以及 填充完毕的实列对象放入map集合中
            map.put(beanId,instance);
        }
    }

    /**
     * @param beanId Map中的key
     * @return 返回参数key所对应的对象/实列
     */
    public Object getBean(String beanId){
        return map.get(beanId);
    }
}

执行结果

泡吧一年多,增加了自己阅读,也学到很多。

第一次写随笔,如有不足请指出。

版权声明:本文为zqgBlog原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/zqgBlog/p/11973306.html