Spring IOC/DI 源码手写实现

                                          Spring IOC/DI 源码手写实现

                                                                                                          20190814 田超凡

实现步骤,仅供参考,也可使用其他方式,核心原理一句话概括就是代码实现类加载器、加载类和成员、动态加载实例并实现成员属性值的注入

1.创建ClassUtil工具类,根据包名读取包和子包下的所有jar包和class文件,
统一以class文件为封装单位,提供根据文件系统递归读取文件方法、提供根据类加载器加载文件的方法、
2.创建ClassHelper工具类,提供加载所有文件的方法和不同类型文件的方法(Service/Controller/Service && Controller => BeanClassLoader)
3.创建ReflectUtil工具类,提供创建指定类型的实例方法、提供调用指定实例方法执行的方法、提供设置成员变量值得方法
4.创建BeanHelper工具类,定义全局map存储Bean类和对应Bean实例之间的映射,初始化加载所有类并创建实例存入全局映射map,提供根据
反射类型获取对应映射关系的泛型方法,提供获取全局映射map的方法
5.创建IoCHelper实现依赖注入,或获取全局映射map,获取对应Bean类和Bean实例,进而获取Bean实例的所有字段和方法,
对于定义了Inject注解的属性反射获取所在类型的实例,调用反射工具类设置属性的值

package com.tcf.kid.base.util;
/***
 * TODO TCF 属性文件读取工具类
 * @author Hasee
 *
 */

import java.io.IOException;
import java.util.Properties;

public class PropertiesUtil {

    private static Properties properties;
    
    static
    {
        properties=new Properties();
        try 
        {
            properties.load(PropertiesUtil.class.getClassLoader().getResourceAsStream("base.properties"));
        } 
        catch (IOException e) 
        {
            e.printStackTrace();
        }
    }
    
    //TODO TCF 指定属性KEY获取属性VALUE
    public static String getProperties(String key)
    {
        return properties.getProperty(key);
    }
}
 

base_package=com.tcf.kid.base.demo

package com.tcf.kid.base.util;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;

import org.apache.commons.lang3.StringUtils;

/***
 * TODO TCF 类加载器工具类
 * @author Hasee
 *
 */
public class ClassUtil {

    //TODO TCF 获取类加载器
    public static ClassLoader getClassLoader()
    {
        return Thread.currentThread().getContextClassLoader();
    }
    
    //TODO TCF 根据类名加载类
    public static Class<?> loadClass(String className)
    {
        try 
        {
            return Class.forName(className,true,getClassLoader());
        } 
        catch (ClassNotFoundException e) 
        {
            e.printStackTrace();
        }
        
        return null;
    }
    
    //TODO TCF 根据类加载器加载单个文件
    public static void addClass(Set<Class<?>> classSet,String className)
    {
        Class<?> cls=loadClass(className);
        classSet.add(cls);
    }
    
    //TODO TCF 根据包路径、包名递归加载文件
    public static void addClassReceive(Set<Class<?>> classSet,String packagePath,String packageName)
    {
        File dir=new File(packagePath);
        
        //TODO TCF 读取目录下的所有文件
        File[] files=dir.listFiles(new FileFilter() {
            
            public boolean accept(File file) 
            {
                return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
            }
        });
        
        if(files!=null && files.length>0)
        {
            for(File file:files)
            {
                String fileName=file.getName();
                if(file.isFile())
                {
                    //TODO TCF 是文件
                    String className=file.getName().substring(0,file.getName().lastIndexOf("."));
                    if(StringUtils.isNotEmpty(packageName))
                    {
                        className=packageName+"."+className;
                    }
                    
                    addClass(classSet, className);
                }
                else
                {
                    //TODO TCF 是目录,递归读取
                    String subPackagePath=fileName;
                    if(StringUtils.isNotEmpty(subPackagePath))
                    {
                        subPackagePath=packagePath+"/"+subPackagePath;
                    }
                    
                    String subPackageName=fileName;
                    if(StringUtils.isNotEmpty(subPackageName))
                    {
                        subPackageName=packageName+"/"+subPackageName;
                    }
                    
                    addClassReceive(classSet, subPackagePath, subPackageName);
                }
            }
        }
    }
    
    //TODO TCF 根据基准包名读取包名下的所有文件
    @SuppressWarnings("static-access")
    public static Set<Class<?>> loadClassPackage(String packageName)
    {
        Set<Class<?>> classList=new HashSet<Class<?>>();
        
        if(StringUtils.isNotEmpty(packageName))
        {
            try 
            {
                Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".","/"));
                
                if(urls!=null)
                {
                    while(urls.hasMoreElements())
                    {
                        URL url=urls.nextElement();
                        
                        if(url!=null)
                        {
                            String protoType=url.getProtocol();
                            if(StringUtils.isNotEmpty(protoType))
                            {
                                if(protoType.equals("file"))
                                {
                                    String packagePath=url.getPath().replaceAll("%20"," ");
                                    addClassReceive(classList, packagePath, packageName);
                                }
                                else if(protoType.equals("jar"))
                                {
                                    JarURLConnection jarURLConnection=(JarURLConnection)url.openConnection();
                                    if(jarURLConnection!=null)
                                    {
                                        Enumeration<JarEntry> jarEntries=jarURLConnection.getJarFile().entries();
                                        if(jarEntries!=null)
                                        {
                                            while(jarEntries.hasMoreElements())
                                            {
                                                JarEntry jarEntry=jarEntries.nextElement();
                                                String jarEntryName=jarEntry.getName();
                                                
                                                if(StringUtils.isNotEmpty(jarEntryName) && jarEntryName.endsWith(".class"))
                                                {
                                                    String className=jarEntryName.substring(0,jarEntryName.lastIndexOf(".")).replaceAll("/",".");
                                                    addClass(classList, className);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            } 
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
        return classList;
    }
}
 

package com.tcf.kid.base.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/***
 * TODO TCF 反射工具类
 * @author Hasee
 *
 */
public class ReflectUtil {

    //TODO TCF 创建指定类型实例
    public static Object newInstance(Class<?> cls)
    {
        Object obj=new Object();
        try 
        {
            obj = cls.newInstance();
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
        }
        
        return obj;
    }
    
    //TODO TCF 调用实例方法
    public static void invokeMethod(Object obj,Method method,Object...args)
    {
        try
        {
            method.invoke(obj,args);
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }
    
    //TODO TCF 给属性赋值
    public static void setField(Object obj,Field field,Object fieldValue)
    {
        try 
        {
            if(field!=null)
            {
                field.setAccessible(true);
                field.set(obj,fieldValue);
            }
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }
}
 

package com.tcf.kid.base.helper;

import java.util.HashSet;
import java.util.Set;

import com.tcf.kid.base.annotation.Controller;
import com.tcf.kid.base.annotation.Service;
import com.tcf.kid.base.util.ClassUtil;
import com.tcf.kid.base.util.PropertiesUtil;

/***
 * TODO TCF 类加载器助手类
 * @author Hasee
 *
 */
public class ClassHelper {

    public static String packageName=PropertiesUtil.getProperties("base_package");
    
    //TODO TCF 加载的所有文件
    public static Set<Class<?>> CLASSLIST=new HashSet<Class<?>>();
    
    //TODO TCF 加载所有文件的方法
    static
    {
        CLASSLIST=ClassUtil.loadClassPackage(packageName);
    }
    
    //TODO TCF 加载Service注解类
    public static Set<Class<?>> loadServiceClasses()
    {
        Set<Class<?>> classes=new HashSet<Class<?>>();
        if(CLASSLIST!=null && CLASSLIST.size()>0)
        {
            for(Class<?> cls:CLASSLIST)
            {
                if(cls.isAnnotationPresent(Service.class))
                {
                    classes.add(cls);
                }
            }
        }
        
        return classes;
    }
    
    //TODO TCF 加载Controller注解类
    public static Set<Class<?>> loadControllerClasses()
    {
        Set<Class<?>> classes=new HashSet<Class<?>>();
        
        if(CLASSLIST!=null && CLASSLIST.size()>0)
        {
            for(Class<?> cls:CLASSLIST)
            {
                if(cls.isAnnotationPresent(Controller.class))
                {
                    classes.add(cls);
                }
            }
        }
        
        return classes;
    }
    
    //TODO TCF 加载所有Inject注解类
    public static Set<Class<?>> loadBeanClasses()
    {
        Set<Class<?>> classes=new HashSet<Class<?>>();
        classes.addAll(loadServiceClasses());
        classes.addAll(loadControllerClasses());
        return classes;
    }
}
 

package com.tcf.kid.base.helper;
/***
 * TODO TCF Bean类型和Bean实例映射关系助手类
 * @author Hasee
 *
 */

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.tcf.kid.base.util.ReflectUtil;

public class BeanHelper {

    //TODO TCF Bean反射类型和Bean实例之间的映射关系
    private static Map<Class<?>,Object> beanMap=new HashMap<Class<?>,Object>();
    
    static
    {
        Set<Class<?>> classList=ClassHelper.CLASSLIST;
        if(classList!=null)
        {
            for(Class<?> cls:classList)
            {
                //TODO TCF 创建每个类型的实例,存入类型-实例映射Map
                Object instance=ReflectUtil.newInstance(cls);
                beanMap.put(cls,instance);
            }
        }
    }
    
    //TODO TCF 获取映射Map
    public static Map<Class<?>,Object> getBeanMap()
    {
        return beanMap;
    }
    
    //TODO TCF 根据类型获取值(Bean实例)
    public static Object getInstance(Class<?> cls)
    {
        return beanMap.get(cls);
    }
}
 

package com.tcf.kid.base.helper;

import java.lang.reflect.Field;
import java.util.Map;

import com.tcf.kid.base.annotation.Inject;
import com.tcf.kid.base.util.ReflectUtil;

/***
 * TODO TCF IoC助手类,加载类和实例实现依赖注入
 * @author Hasee
 *
 */
public class IoCHelper {

    static
    {
        Map<Class<?>,Object> map=BeanHelper.getBeanMap();
        if(map!=null)
        {
            for(Map.Entry<Class<?>,Object> entry:map.entrySet())
            {
                //TODO TCF 反射类型
                Class<?> cls=entry.getKey();
                
                //TODO TCF 反射类型对应的Bean实例
                Object instance=entry.getValue();
                
                if(instance!=null)
                {
                    Field[] fields=cls.getDeclaredFields();
                    if(fields!=null && fields.length>0)
                    {
                        for(Field field:fields)
                        {
                            if(cls.isAnnotationPresent(Inject.class))
                            {
                                //TODO TCF DEMO 属性名和属性值 实际对应手写SpringMVC后控制层请求参数和值,实现属性注入
                                String fieldName=field.getName();
                                
                                Object fieldValue=null;
                                if(fieldName.equals("name"))
                                {
                                    fieldValue="张三";
                                }
                                
                                if (fieldName.equals("sex")) 
                                {
                                    fieldValue="男";
                                }
                                
                                if (fieldName.equals("age")) 
                                {
                                    fieldValue=20;
                                }
                                
                                //TODO TCF 目标实例,属性,属性值
                                ReflectUtil.setField(instance,field,fieldValue);
                            }
                        }
                        
                        //TODO TCF 属性赋值后执行方法
                        ReflectUtil.invokeMethod(instance, instance.getClass().getDeclaredMethods()[0]);
                    }
                }
            }
        }
    }
}
 

package com.tcf.kid.test;

import java.util.HashSet;
import java.util.Set;

import com.tcf.kid.base.helper.BeanHelper;
import com.tcf.kid.base.helper.ClassHelper;
import com.tcf.kid.base.helper.IoCHelper;
import com.tcf.kid.base.util.ClassUtil;

public class Test {

    public static void main(String[] args) 
    {
        Set<Class<?>> classes=new HashSet<Class<?>>();
        classes.add(ClassHelper.class);
        classes.add(BeanHelper.class);
        classes.add(IoCHelper.class);
        
        //TODO TCF ...
        
        for(Class<?> cls:classes)
        {
            ClassUtil.loadClass(cls.getName());
        }
    }
}
 

发布了100 篇原创文章 · 获赞 10 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_30056341/article/details/99552597