模拟spring中的IOC容器

来源:互联网 发布:微软程序员年薪 编辑:程序博客网 时间:2024/06/03 22:07
package cn.itcastheima.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BeanConfig {
    //主键id是要创建的对象简称
 private String id;
    //判断是否是单例
 private String scope = "singleton";
    //它保存类的完整路径用于反射生成对象
 private String className;
    //它保存普通属性,key是属性变量名value是其值
 private Map<String,String> map = new HashMap<String,String>();
    //它是保存引用属性变量名
 private List<String> ref = new ArrayList<String>();
 
public String getScope() {
    return scope;
}
public void setScope(String scope) {
    this.scope = scope;
}
public String getClassName() {
    return className;
}
public void setClassName(String className) {
    this.className = className;
}
public String getId() {
    return id;
}
public void setId(String id) {
    this.id = id;
}
public Map<String, String> getMap() {
    return map;
}
public void setMap(Map<String, String> map) {
    this.map = map;
}
public List<String> getRef() {
    return ref;
}
public void setRef(List<String> ref) {
    this.ref = ref;
}
}


package cn.itcastheima.util;

import java.util.List;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class BeanFacotryUtils {
    private BeanFacotryUtils(){
    }
    
    /**
     * 读出配置文件中的属性生成BeanConfing对象
     * 并把其加入到factory中map集合中去
     * @param factory
     * @param filename
     */
    public static void load(BeanFactory factory,String filename){
        SAXReader sax = new SAXReader();
        try{
        Document document= sax.read(BeanFacotryUtils.class.getResourceAsStream("/"+filename));
        
        //获取根节点
        Element root = document.getRootElement();
        //获取根节点下所有标签名为bean的元素
        List<Element> list = root.elements("bean");
        //循环操作bean单个元素
        for(Element e:list){
            //创建BeanConfig对象
            BeanConfig config = new BeanConfig();
            //获取bean标签下属性名为id的值并保存入beanConfig对象中
            String text1 = e.attributeValue("id");
            config.setId(text1);
            
            //获取bean标签下属性名为className的值并保存入beanConfig对象中
            String text2 = e.attributeValue("className");
            config.setClassName(text2);
            //获取bean标签下的Scope属性值并保存入beanConfig对象中
            String scope = e.attributeValue("scope");
            if(scope!=null)
                config.setScope(scope);
            //获取bean标签下所有property标签
            List<Element> ls = e.elements("property");
            //循环操作每个property标签
            for(Element node:ls){
                //获取property标签中属性为name的值,属性名为value的值并放入beanConfig的map中
                String nn = node.attributeValue("name");
                String nv = node.attributeValue("value");
                config.getMap().put(nn, nv);
            }
            
            //获取bean标签下的ref标签
            List<Element> refs = e.elements("ref");
            //如果存在
            if(refs!=null){
                //获取其value属性值并保存入beanConfig对象中
                for(Element ref:refs){
            String rv = ref.attributeValue("value");
            config.getRef().add(rv);
                }
            }
            
            //把beanConfig对象加入到factory中
            factory.addBeanConfig(config);
        }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}


package cn.itcastheima.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.management.RuntimeErrorException;

import cn.itcast.dao.Classes;

public class BeanFactory {
    // 配置文件对应体
    private Map<String, BeanConfig> configs = new HashMap<String, BeanConfig>();
    // Bean的缓存id是键,Bean是值
    private Map<String, Object> beanCache = new HashMap<String, Object>();
    
    private boolean singleton = true;

    public BeanFactory(String path) {
        BeanFacotryUtils.load(this, path);
    }

    /**
     * 如果缓存中有返回 没有先创建在返回
     *
     * @param id
     * @return
     */
    public Object getBean(String id) {
        BeanConfig config = configs.get(id);
        if (config == null)
            throw new RuntimeException("没找到主键id");
        String scope = config.getScope();
        if(scope!=null){
        if(scope.equals("singleton"))
            singleton=true;
        else if(scope.equals("prototype"))
            singleton = false;
        else
            throw new RuntimeException("你输入的scope有误");
        }
           
            if (singleton&&beanCache.containsKey(id))
                return beanCache.get(id);
            try {
                Class clazz = Class.forName(config.getClassName());
                Object t = clazz.newInstance();
                string2Bean(clazz, t, config);
                if(singleton)
                beanCache.put(id, t);
                return t;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
    }

    public void string2Bean(Class clazz, Object t, BeanConfig config)
            throws Exception {
        Map<String, String> map2 = config.getMap();
        Set<String> set = map2.keySet();
        for (String s : set) {
            String objs = map2.get(s);
            Method[] methonds = clazz.getMethods();
            
            value2Settter(t, s, objs, methonds);
        }
        // 判断并获取引用对象
        List<String> cids = config.getRef();
        if (cids.size()>0) {
            
            
            for (String cid : cids) {
                // 获取引用对象的beanConfig
                BeanConfig config2 = configs.get(cid);
                // 先初始化引用对象为空
                Object t2 = null;
                // 获取引用对象的Class对象
                Class clazz2 = Class.forName(config2.getClassName());
                // 如果缓存中有引用对象则直接取出没有就先创建放入缓存中再赋值给t
                if (singleton&&beanCache.containsKey(cid))
                    t2 = beanCache.get(cid);
                else {
                    t2 = clazz2.newInstance();
                    string2Bean(clazz2, t2, config2);
                    if(singleton)
                    beanCache.put(cid, t2);
                }
            
            // 方法一通过字段反射获取
            /*
             * String sn = clazz2.getSimpleName(); Field[] fs =
             * clazz.getDeclaredFields(); for(int j=0;j<fs.length;j++){
             * fs[j].setAccessible(true);
             * if(!fs[j].getType().getSimpleName().equals(sn)) continue;
             * fs[j].set(t, t2); }
             */

            // 方法二是通过公共方法反射把引用对象设置到t中
            /**
             * 注意set方法后的字符串变小写要和其属性值相同 还有设置的参数也要和属性值相同不然无法设置上去
             */
            String cclass = clazz2.getSimpleName();
            Method[] ms = clazz.getMethods();
            for (int i = 0; i < ms.length; i++) {
                String msn = ms[i].getName();
                if (!msn.contains("set") || !msn.contains(cclass))
                    continue;
                ms[i].invoke(t, t2);
            }
            }
        }
    }

    /**
     * 把class类中的普通属性反射到setter方法上
     */
    public void value2Settter(Object t, String s, String objs, Method[] methonds)
            throws IllegalAccessException, InvocationTargetException {
        // 遍历所有的方法
        for (int i = 0; i < methonds.length; i++) {
            // 获取方法的名称
            String men = methonds[i].getName();
            // 查找set在方法名出现的位置
            int index = men.indexOf("set");
            // 如果小于等于-1表示没有直接跳过
            if (index <= -1)
                continue;

            if (!men.toLowerCase().contains(s))
                continue;

            // 获取方法上的参数类型它是个数组
            Class[] type1 = methonds[i].getParameterTypes();
            // 获取第一个参数类型
            Class type = (Class) type1[0];

            // 判断参数是哪些类型并赋值给它
            if (type.getSimpleName().equals("int")
                    || type.getSimpleName().equals("Integer")) {
                Integer obj = Integer.parseInt(objs);
                methonds[i].invoke(t, obj);
            } else if (type.getSimpleName().equals("char")
                    || type.getSimpleName().equals("Character")) {
                Character obj = objs.charAt(0);
                methonds[i].invoke(t, obj);
            } else if (type.getSimpleName().equals("String")) {
                methonds[i].invoke(t, objs);
            } else if (type.getSimpleName().equals("Boolean")||type.getSimpleName().equals("boolean")) {
                Boolean obj =new Boolean(objs);
                methonds[i].invoke(t, obj);
            } else if (type.getSimpleName().equals("float")
                    || type.getSimpleName().equals("Float")) {
                Float obj = Float.parseFloat(objs);
                methonds[i].invoke(t, obj);
            } else if (type.getSimpleName().equals("double")
                    || type.getSimpleName().equals("Double")) {
                Double obj = Double.parseDouble(objs);
                methonds[i].invoke(t, obj);
            }
        }
    }

    /**
     * 把beanConfig添加到配置map中
     *
     * @param beanConfig
     */
    public void addBeanConfig(BeanConfig beanConfig) {
        configs.put(beanConfig.getId(), beanConfig);
    }
}


0 0
原创粉丝点击