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) 根据参数自定的类名创建类对象,类对象中记录了className指定类名的信息。
                       - T newInstance() 创建该class对象所记录类型的实例。
                       - Field getDeclaredField(String name) 根据参数指定的name获取类型的字段/成员变量。
                       - Method[] getMethods() 用于获取Class对象所表示类中的所有公共方法。

Field

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

Method

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

铺垫完毕 上代码

首先 - 目录结构

pom.xml

第一部分 - 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文档 ![](https://img2020.cnblogs.com/blog/1416345/202007/1416345-20200715173307717-1541196266.png)

注意!!!

第三部分XmlUtil的代码中,由于MarkDown标签冲突原因,集合中的泛型并没有正常显示
如:
    Map<String,Object> map = new HashMap<>();
    List<Element> beans = rootElement.elements();

摘抄代码时,还请手动添加。

第三部分 - XmlUtil类

展开查看

public class XmlUtil {
    //创建Map集合,用于bean对象的存储
    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<Element> 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<Element> 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) {
                    //使用已经获取到的字段类型与标签中读取到的值进行比较
                    //这里进行String类型的比较
                    if (type.equals(value.getClass())) {
                         method.invoke(instance, value);
                    //如果类型不一致,则进入下一个类型判断
                    }else if(type == Integer.TYPE){
                        int i = Integer.parseInt(value);
                        method.invoke(instance,i);
                    }
                    //。。。这里可以继续if else进行类型的判断
                }
            }

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

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

//main方法中进行测试
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);
}

}

###执行结果 ![](https://img2020.cnblogs.com/blog/1416345/202007/1416345-20200715173333896-1820834114.png)


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM