美文网首页
2019-01-29 IOC DI 手动实现原理

2019-01-29 IOC DI 手动实现原理

作者: vpike | 来源:发表于2019-01-29 10:17 被阅读0次

    application.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <beans>
       <bean name="student" class="com.wang.entity.Student" >
           <property name="name" value="123"></property>
       </bean>
       
       <bean name="teacher" class="com.wang.entity.Teacher">
           <property name="student" ref="student"></property>
       </bean>
       <bean name="person" class="com.wang.entity.Person" scope="prototype">
           <property name="teacher" ref="teacher"></property>
           <property name="student" ref="student"></property>
       </bean>
       
    </beans>
    
    

    实体类Student,Teacher,Person:

    package com.wang.entity;
    //Student类
    public class Student {
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    /************************************/
    package com.wang.entity;
    //Teacher类
    public class Teacher {
    
        private Student student;
    
        public Student getStudent() {
            return student;
        }
    
        public void setStudent(Student student) {
            this.student = student;
        }
         
    }
    /************************************/
    package com.wang.entity;
    //Person类
    public class Person {
    
        private Student student;
        private Teacher teacher;
        
        public Student getStudent() {
            return student;
        }
        public void setStudent(Student student) {
            this.student = student;
        }
        public Teacher getTeacher() {
            return teacher;
        }
        public void setTeacher(Teacher teacher) {
            this.teacher = teacher;
        }
    }
    

    用于封装Bean标签信息的Bean类:

    package com.wang.config;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Bean {
    
        
        private String name;
        private String className;
        private String scope="singleton";
        private List<Property> properties=new ArrayList<Property>();
    
        
        public String getScope() {
            return scope;
        }
    
        public void setScope(String scope) {
            this.scope = scope;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getClassName() {
            return className;
        }
    
        public void setClassName(String className) {
            this.className = className;
        }
    
        public List<Property> getProperties() {
            return properties;
        }
    
        public void setProperties(List<Property> properties) {
            this.properties = properties;
        }
    
        
    }
    

    用与封装Bean子标签property内容的Property类:

    package com.wang.config;
    
    public class Property {
    
        private String name;
        private String value;
        private String ref;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getValue() {
            return value;
        }
        public void setValue(String value) {
            this.value = value;
        }
        public String getRef() {
            return ref;
        }
        public void setRef(String ref) {
            this.ref = ref;
        }
    
        
    }
    

    ConfigManager类:

    
    package com.wang.config.parse;
    
    import java.io.InputStream;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    import org.junit.Test;
    
    import com.wang.config.Bean;
    import com.wang.config.Property;
    
    public class ConfigManager {
        
        private static Map<String,Bean> map=new HashMap<String,Bean>(); 
    
        //读取配置文件并返回读取结果
        //返回Map集合便于注入,key是每个Bean的name属性,value是对应的那个Bean对象
        public static Map<String, Bean> getConfig(String path){
            /*dom4j实现
             *  1.创建解析器
             *  2.加载配置文件,得到document对象
             *  3.定义xpath表达式,取出所有Bean元素
             *  4.对Bean元素继续遍历
             *      4.1将Bean元素的name/class属性封装到bean类属性中
             *      4.2获得bean下的所有property子元素
             *      4.3将属性name/value/ref分装到类Property类中
             *  5.将property对象封装到bean对象中
             *  6.将bean对象封装到Map集合中,返回map 
                */
            //1.创建解析器
            SAXReader reader=new SAXReader();
            //2.加载配置文件,得到document对象
            InputStream is = ConfigManager.class.getResourceAsStream(path);
            Document doc =null;
            try {
                 doc = reader.read(is);
            } catch (DocumentException e) {
                e.printStackTrace();
                throw new RuntimeException("请检查您的xml配置是否正确");
            }
            // 3.定义xpath表达式,取出所有Bean元素
            String xpath="//bean";
            
            //4.对Bean元素继续遍历
            List<Element> list = doc.selectNodes(xpath);
            if(list!=null){
                //4.1将Bean元素的name/class属性封装到bean类属性中
            
                 // 4.3将属性name/value/ref分装到类Property类中
                for (Element bean : list) {
                    Bean b=new Bean();
                    String name=bean.attributeValue("name");
                    String clazz=bean.attributeValue("class");
                    String scope=bean.attributeValue("scope");
                    b.setName(name);
                    b.setClassName(clazz);
                    if(scope!=null){
                        b.setScope(scope);
                    }
                     //  4.2获得bean下的所有property子元素
                    List<Element> children = bean.elements("property");
                    
                     // 4.3将属性name/value/ref分装到类Property类中
                    if(children!=null){
                        for (Element child : children) {
                            Property prop=new Property();
                            String pName=child.attributeValue("name"); 
                            String pValue=child.attributeValue("value");
                            String pRef=child.attributeValue("ref");
                            prop.setName(pName);
                            prop.setRef(pRef);
                            prop.setValue(pValue);
                            // 5.将property对象封装到bean对象中
                            b.getProperties().add(prop);
                        }
                    }
                    //6.将bean对象封装到Map集合中,返回map 
                    map.put(name, b);
                }
            }
            
            return map;
        }
    
    }
    

    BeanFactory接口:

    package com.wang.main;
    
    public interface BeanFactory {
        //核心方法getBean
        Object getBean(String name);
    }
    

    ClassPathXmlApplicationContext类:

    
    package com.wang.main;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Map.Entry;
    
    import org.apache.commons.beanutils.BeanUtils;
    import org.junit.Test;
    
    import com.wang.config.Bean;
    import com.wang.config.Property;
    import com.wang.config.parse.ConfigManager;
    import com.wang.entity.Student;
    //import com.wang.utils.BeanUtils;
    import com.wang.utils.BeanUtil;
    
    public class ClassPathXmlApplicationContext implements BeanFactory {
    
        // 获得读取的配置文件中的Map信息
        private Map<String, Bean> map;
        // 作为IOC容器使用,放置sring放置的对象
        private Map<String, Object> context = new HashMap<String, Object>();
    
        public ClassPathXmlApplicationContext(String path) {
            // 1.读取配置文件得到需要初始化的Bean信息
            map = ConfigManager.getConfig(path);
            // 2.遍历配置,初始化Bean
            for (Entry<String, Bean> en : map.entrySet()) {
                String beanName = en.getKey();
                Bean bean = en.getValue();
    
                Object existBean = context.get(beanName);
                // 当容器中为空并且bean的scope属性为singleton时
                if (existBean == null && bean.getScope().equals("singleton")) {
                    // 根据字符串创建Bean对象
                    Object beanObj = createBean(bean);
    
                    // 把创建好的bean对象放置到map中去
                    context.put(beanName, beanObj);
                }
            }
    
        }
    
        // 通过反射创建对象
        private Object createBean(Bean bean) {
            // 创建该类对象
            Class clazz = null;
            try {
                clazz = Class.forName(bean.getClassName());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                throw new RuntimeException("没有找到该类" + bean.getClassName());
            }
            Object beanObj = null;
            try {
                beanObj = clazz.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("没有提供无参构造器");
            }
            // 获得bean的属性,将其注入
            if (bean.getProperties() != null) {
                for (Property prop : bean.getProperties()) {
                    // 注入分两种情况
                    // 获得要注入的属性名称
                    String name = prop.getName();
                    String value = prop.getValue();
                    String ref = prop.getRef();
                    // 使用BeanUtils工具类完成属性注入,可以自动完成类型转换
                    // 如果value不为null,说明有
                    if (value != null) {
                        Map<String, String[]> parmMap = new HashMap<String, String[]>();
                        parmMap.put(name, new String[] { value });
                        try {
                            BeanUtils.populate(beanObj, parmMap);
                        } catch (Exception e) {
                            e.printStackTrace();
                            throw new RuntimeException("请检查你的" + name + "属性");
                        }
                    }
    
                    if (ref != null) {
                        // 根据属性名获得一个注入属性对应的set方法
                        // Method setMethod = BeanUtil.getWriteMethod(beanObj,
                        // name);
    
                        // 看一看当前IOC容器中是否已存在该bean,有的话直接设置没有的话使用递归,创建该bean对象
                        Object existBean = context.get(prop.getRef());
                        if (existBean == null) {
                            // 递归的创建一个bean
                            existBean = createBean(map.get(prop.getRef()));
                            // 放置到context容器中
                            // 只有当scope="singleton"时才往容器中放
                            if (map.get(prop.getRef()).getScope()
                                    .equals("singleton")) {
                                context.put(prop.getRef(), existBean);
                            }
                        }
                        try {
                            // setMethod.invoke(beanObj, existBean);
                  //通过BeanUtils为beanObj设置属性
                            BeanUtils.setProperty(beanObj, name, existBean);
                        } catch (Exception e) {
                            e.printStackTrace();
                            throw new RuntimeException("您的bean的属性" + name
                                    + "没有对应的set方法");
                        }
    
                    }
    
                }
            }
    
            return beanObj;
        }
    
        @Override
        public Object getBean(String name) {
            Object bean = context.get(name);
            // 如果为空说明scope不是singleton,那么容器中是没有的,这里现场创建
            if (bean == null) {
                bean = createBean(map.get(name));
            }
    
            return bean;
        }
    
    }
    

    最后就是一个测试类TestBean:

    
    package com.wang.main;
    
    import org.junit.Test;
    
    import com.wang.entity.Person;
    import com.wang.entity.Student;
    import com.wang.entity.Teacher;
    
    
    public class TestBean {
    
        @Test
        public void func1(){
            
            BeanFactory bf=new ClassPathXmlApplicationContext("/applicationContext.xml");
            Person s=(Person)bf.getBean("person");
            Person s1=(Person)bf.getBean("person");
            System.out.println(s==s1);
            System.out.println(s1);
            Student stu1=(Student) bf.getBean("student");
            Student stu2=(Student) bf.getBean("student");
            String name=stu1.getName();
            System.out.println(name);
            System.out.println(stu1==stu2);
        }
    }
    

    相关文章

      网友评论

          本文标题:2019-01-29 IOC DI 手动实现原理

          本文链接:https://www.haomeiwen.com/subject/hrgtsqtx.html