Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 298|回复: 0

[Java框架学习]IOC容器简单实现

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-5 00:00:53 | 显示全部楼层 |阅读模式
    这是个很简单的IOC容器,基本功能有:自动加载所有使用了@Inject注解的类,然后注入每个类里边使用了@Inject注解的字段。
                                                                                        
            原理很简单,就是扫描classes目录下的所有文件和子目录文件,如果是.class文件就检查是否有@Inject这个注解,有就加载,然后在分析这个类,看字段有没有使用了@Inject这个注解的,有就尝试注入(注入是在所有类加载完之后进行的)。 首先,是一个接口:Container.java,定义了容器的一些方法。 代码如下:
    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);
    }[/code] 这里定义的是容器的通用方法,比如从容器获取一个bean,向容器中注册一个bean等。 接下来是容器类的实现,这个容器很简单,代码集中在初始化过程,初始化的时候会加载类,并注入某些字段。 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();
                            }
                    }
            }
    }[/code]     这里主要说说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;
            }
    }[/code] 这个类有三个重要方法:getPackagePath()、loadClassFromDir(String path)、loadClassFromFile(String path)。     getPackagePath()功能是获取当前应用的classes目录所处的绝对路径。loadClassFromDir(String path)方法是从一个目录中加载类,这里有一个递归调用,从而遍历所有子目录。loadClassFromFile(String path)的功能就是从一个文件中加载类。 三个类,实现一个简单的IOC,相信大家都能看懂,其实IOC也就那么回事,我们都能写,哈哈! 代码很少,也写得比较粗糙,问题也很多,见笑了! 完整代码请下载,里边还包含了一个测试实例。

       
         
         
          
          

            
          

            
          
         
       

      


    源码下载:http://file.javaxxz.com/2014/11/5/000052890.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 13:35 , Processed in 0.416370 second(s), 46 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表