IOC容器的简单实现(转)

container

package com.easyjf.minicontainer;
import java.util.Collection; import java.util.List;
import java.util.Map;

public interface Container {
    
    void init();
    
    Object getBean(String name);
    
    Object getBean(Class type);
    
    List getBeans(String name);
    
    List getBeans(Class type);
    
    Collection getBeanName();
    
    boolean hasBean(Class clz);
    
    boolean hasBean(String name);
    
    void registBean(Class clz);}


defaultcontainer

 

package com.easyjf.minicontainer.impl; 

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import com.easyjf.minicontainer.Container;
import com.easyjf.minicontainer.annotation.Inject;
public class DefaultContainer implements Container {
    
    private static final Logger logger = Logger.getLogger(DefaultContainer.class);
    
    private final Map objMap = new HashMap();
    public Object getBean(String name) {
        return objMap.get(name);
    }
    public Object getBean(Class type) {
        Iterator it = this.objMap.values().iterator();
        while(it.hasNext()){
            Object obj = it.next();
            if(type.isAssignableFrom(obj.getClass())){
                return obj;
            }
        }
        return null;
    }
    public Collection getBeanName() {
        return null;
    }
    public List getBeans(String name) {
        return null;
    }
    public List getBeans(Class type) {
        return null;
    }
    public boolean hasBean(Class clz) {
        if(this.getBean(clz)!=null){
            return true;
        }
        return false;
    }
    
    public boolean hasBean(String name){
        if(this.getBean(name)!=null){
            return true;
        }
        return false;
    }
    public void init() {
        Config config = new Config();
        config.init(this);
        refresh();
    }
    
    public void registBean(Class clz){
        String name = clz.getCanonicalName();
        try {
            if(!Modifier.isAbstract(clz.getModifiers())&&!Modifier.isInterface(clz.getModifiers())){
                logger.debug("加载了类:"+name);
                Object obj = clz.newInstance();
                objMap.put(name, obj);
            }else{
                Inject inject = (Inject)clz.getAnnotation(Inject.class);
                String taget = inject.target();
                if("".equals(taget)){
                    throw new RuntimeException(
                                            "接口必须指定目标类!");
                }
                Class tagetClz = Class.forName(taget);
                Object tagetObj = tagetClz.newInstance(); 
                logger.debug("加载了类:"+name);
                objMap.put(name, tagetObj);
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    
    public void refresh(){
        Iterator it = this.objMap.values().iterator();
        while(it.hasNext()){
            try {
                Object obj = it.next();
                String name = obj.getClass().getCanonicalName();
                Field[] fields = obj.getClass().getDeclaredFields();
                for(Field field : fields){
                    Annotation inject = field.getAnnotation(Inject.class);
                    if(inject!=null){
                        Object arg = this.getBean(field.getType());
                        if(arg==null){
                            throw new RuntimeException(
                                     "无法加载"+field.getType().getCanonicalName()+"!");
                        }
                        String fieldName = field.getName();
                        String methodName = "set"
                                                    +fieldName.substring(0, 1).toUpperCase()
                                                    +fieldName.substring(1, fieldName.length());
                        Method method;
                        method = obj.getClass()
                                                    .getDeclaredMethod(methodName, arg.getClass());
                        
                        if(method != null){
                            method.invoke(obj, arg);
                        }else{
                            throw new RuntimeException("无法加载"
                                                 +obj.getClass().getCanonicalName()
                                                 +"."+field.getName()
                                                 +",找不到该字段的set方法!");
                        }
                    }
                }
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}

 

 这里主要说说registBean(Class clz)和refresh()这两个方法。registBean(Class clz)是由另外一个类来调用的,这里主要说说这个方法的功能。这个方法接受一个Class类型的参数,然后判断这个Class是不是接口或者抽象类,如果是就根据其@Inject注解中的target值来找到一个类,并初始化这个类。如果不是就直接实例化并且放入容器中。

     refresh()方法则是在加载完需要加载的类之后开始执行注入操作。通过迭代容器中的所有bean,来扫描每一个bean,看看是否有需要注入的字段(即使用了@Inject注解的字段),然后执行这个字段的setter方法,实现注入(未实现构造子注入)。

 

 接下来是Config类,这个类的功能主要是扫面classes目录下的文件,找到所有class文件并尝试交给DefaultContainer来加载。

代码如下:

 

 

package com.easyjf.minicontainer.impl;
import java.io.File;
import java.lang.annotation.Annotation;
import java.util.Map;
import org.apache.log4j.Logger;
import com.easyjf.minicontainer.Container;
import com.easyjf.minicontainer.annotation.Inject;
public class Config {
    
    private static final Logger logger = Logger.getLogger(Config.class);
    
    private String packagePath;
    
    private Container container;
    
    public void init(Container container){
        this.container = container;
        loadClass();
    }
    
    public void loadClass(){
        loadClassFromDir(getPackagePath());
    }
    
    public void loadClassFromFile(String path){
        logger.debug("加载类:"+path);
        logger.debug(path.endsWith(".class"));
        if(path.endsWith(".class")){
            String className = path.replace(packagePath, "");
            className = className.replace("/", ".");
            className = className.substring(1, className.length());
            className = className.substring(0, className.indexOf(".class"));
            logger.debug(className);
            try {
                Class clz = Class.forName(className);
                Annotation inject = clz.getAnnotation(Inject.class);
                if(inject!=null){
                    container.registBean(clz);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
    
    public void loadClassFromDir(String path){
        logger.debug("从文件夹"+path+"加载类");
        File file = new File(path);
        logger.debug("找到目录:"+path);
        if(file.isDirectory()){
            String[] paths = file.list();
            for(String filePath : paths){
                logger.debug("找到子目录:"+filePath);
                loadClassFromDir(path+"/"+filePath);
            }
        }else{
            loadClassFromFile(path);
        }
    }
    
    public String getPackagePath(){
        String appPath = Config.class.getResource("/").getPath();
        appPath = appPath.substring(1, appPath.length()-1);
        logger.debug("包路径:"+appPath);
        if(appPath.contains("%20")){
            appPath = appPath.replaceAll("%20", " ");
        }
        this.packagePath = appPath;
        return appPath;
    }

 


 

这个类有三个重要方法:getPackagePath()、loadClassFromDir(String path)、loadClassFromFile(String path)。

    getPackagePath()功能是获取当前应用的classes目录所处的绝对路径。loadClassFromDir(String path)方法是从一个目录中加载类,这里有一个递归调用,从而遍历所有子目录。loadClassFromFile(String path)的功能就是从一个文件中加载类。

 

 

posted on 2012-07-26 21:05  小山丘  阅读(233)  评论(0编辑  收藏  举报

导航