• Java 反射和内省实现spring的IOC和DI


    1.构造两个JavaBean 

    package com.spring.model;
    
    
    public class People {
        
        private Car car;
    
        public Car getCar() {
            return car;
            
        }
    
        public void setCar(Car car) {
            this.car = car;
        }
    
    }
    package com.spring.model;
    
    public class Car {
        
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        
        public void show() {
            System.out.println("我是"+name+"");
        }
    
    }

    2.构建一个类似于spring配置的xml文件 spring-bean.xml

      按照spring一样的格式配置好节点和属性

    <?xml version="1.0" encoding="UTF-8"?>
    <beans>
        <bean id="car" class="com.spring.model.Car">
        </bean>
    
        <bean id="people" class="com.spring.model.People">
            <property name="car" ref="car"></property>
        </bean>
    </beans>

    3.构建一个类似spring加载配置文件的类 里面运用了反射和内省的机制

    package com.spring.core;
    
    import java.beans.BeanInfo;
    import java.beans.Introspector;
    import java.beans.PropertyDescriptor;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.dom4j.Document;
    import org.dom4j.Element;
    import org.dom4j.Node;
    import org.dom4j.io.SAXReader;
    
    /**
     * 
     * 模仿spring IOC、DI 底层实现
     * @author GET_CHEN
     *
     */
    public class ClassPathXmlApplicationContext {
        private String configXml;
        private Map<String,Object> map = new HashMap<String,Object>();//保存配置文件中的id和class所实例化出来的对象
        public ClassPathXmlApplicationContext(String configXml) {
            this.configXml = configXml;
            this.doImplement();
        }
        
        
    
        /**
         * 实现文档的解析
         * 通过反射实现IOC
         * 通过内省实现DI
         */
        private void doImplement() {
            SAXReader saxReader = new SAXReader();
            try {
                //通过dom4j解析文档
                Document doucment = saxReader.read(this.getClass().getClassLoader().getResourceAsStream(configXml));
                
                //获取beans下面的所有bean节点
                List<Node> beanNodes = doucment.selectNodes("beans/bean");
                
                if(beanNodes == null || beanNodes.size() <= 0) return;
                //遍历所有的bean节点,将id和class添加到map中
                for (Node bean : beanNodes) {
                    //将节点转为元素
                    Element element = (Element)bean;
                    //获取元素的相关属性内容
                    String beanId = element.attributeValue("id");
                    String beanClass = element.attributeValue("class");
                    //——————————————IOC的实现————————————————
                    //通过反射将class所对应的对象,实例化出来,保存到map中  --------------> 这一步实现了IOC
                    map.put(beanId, Class.forName(beanClass).newInstance());
                }
                
                
                //——————————————————DI的实现——————————————————
                //获取所有的属性标签
                List<Node> propertyNodes = doucment.selectNodes("beans/bean/property");
                
                if(propertyNodes != null && propertyNodes.size() > 0) {
                    //遍历获取name属性和ref属性
                    
                    for (Node property : propertyNodes) {
                        //将节点转为元素
                        Element element = (Element) property;
                        //获取name属性和ref属性
                        String proName = element.attributeValue("name");
                        String proRef = element.attributeValue("ref");
                        
                        //获取当前元素的直接父元素
                        Element parent = element.getParent();
                        //获取父元素所对应的id属性
                        String parentId = parent.attributeValue("id");
                        
                        //—————————————————— 内省实现依赖注入 ———————————
                        //获取父元素的字节码对象
                        Class parentClass = map.get(parentId).getClass();
                        //通过内省类,获取父元素所指向的类的所有信息(内省对象)
                        //第二个参数为不需要内省的类,除去Object,为了防止遍历到Object类中的set方法中的参数
                        BeanInfo beanInfo = Introspector.getBeanInfo(parentClass,Object.class);
                        //通过内省对象,获取父元素所指向的类的所有属性描述
                        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
                        //遍历属性元素
                        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                            //获取set方法所对应的属性名
                            String name = propertyDescriptor.getName();
                            System.out.println(name+"-------");
                            //如果 父元素所指向的类中的setter方法的名称 存在 与 配置中其子标签property中name属性相同的值就进行注入
                            //即:<property name="car"/> 中的 car 与 People类中的 public void setCar;中的car全小写相同时候
                            if(proName.equals(name)) {
                                //注入
                                //将ref对应的对象,注入给父级元素指向对象(内省对象)的set方法参数所对应的对象
                                //即:完成 new People().setCar(car) 的工作
                                propertyDescriptor.getWriteMethod().invoke(map.get(parentId), new Object[] {map.get(proRef)});
                            }
                        }
                        
                    }
                    
                }
                
                
                
            } catch (Exception e) {
                
                e.printStackTrace();
            }
            
        }
    
        /**
         * 
         * 获取保存在map中的实例对象,并返回
         * @param beanName
         * @return
         */
        public  Object getBean(String beanName) {
            return map.get(beanName);
        }
    
    }

    4.测试代码

    package com.spring.test;
    
    import org.junit.Test;
    
    import com.spring.core.ClassPathXmlApplicationContext;
    import com.spring.model.Car;
    import com.spring.model.People;
    
    public class TestDemo {
        
        @Test
        public void h() {
            ClassPathXmlApplicationContext bean = new ClassPathXmlApplicationContext("com/spring/config/spring-bean.xml");
            
            People people = (People) bean.getBean("people");
            
            Car car = people.getCar();
            car.setName("奔驰");
            car.show();
        }
    
    }

    5.运行结果

    car-------
    我是奔驰车

    总结:高大上的spring就是利用反射和内省的机制完成对于一个类的管理,和相关类的注入的。控制反转主要使用的是反射机制,通过Class.fromName,获取类的字节码对象并实例化。依赖注入就是通过内省获取一个类并类中的set方法所set的一个对象,通过这个对象所对应的名称,获取在map中与之对应的实例化对象之后。通过内省的对象调用 真实的set方法,将已实例好的对象赋值给内省对象中所对应的成员变量

  • 相关阅读:
    日报10.29
    日报10.28
    日报10.27
    周进度总结-6
    日报10.25
    日报10.23
    日报10.22
    日报10.21
    日报10.18
    STL bitset
  • 原文地址:https://www.cnblogs.com/getchen/p/7886139.html
Copyright © 2020-2023  润新知