手写实现spring ioc自动注入、包扫描、单例多例模式(@Component @Autowired @Scope)

源码地址:https://gitee.com/HumorChen/spring_ioc_impl.git
见测试类
主要结构:
在这里插入图片描述
在这里插入图片描述

  • 实体类
package com.humorchen.spring_ioc_impl.bean;

import com.humorchen.spring_ioc_impl.annotation.MyAutowired;
import com.humorchen.spring_ioc_impl.annotation.MyComponent;
import com.humorchen.spring_ioc_impl.annotation.MyScope;
import com.humorchen.spring_ioc_impl.constant.ScopeType;

/**
 * 用户实体类
 */
//@MyScope(ScopeType.PROTOTYPE)
@MyComponent(scope = ScopeType.PROTOTYPE)
public class User {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

  • 上下文接口

提供了两种手动获取bean的方法 Object getBean(String name); Object getBean(Class cls);
自动注入由@MyAutowired实现(仅支持被ioc容器管理的对象(@Component))

package com.humorchen.spring_ioc_impl.interfaces;

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

/**
 * spring 上下文接口
 */
public interface MySpringContext {
     //IOC容器
     Map<String, Object> IOC=new HashMap<String, Object>();
     //存储上下文的属性
     Map<Object,Object> ATTRS=new HashMap<Object, Object>();

     /**
      * 根据名称获取 bean 实例
      * @param name bean实例的名称
      * @return Object bean实例
      */
     Object getBean(String name);

     /**
      * 获取 bean
      * @param cls bean的类型
      * @return Object bean实例
      */
     Object getBean(Class cls);

     /**
      * 获取上下文的属性
      * @param object 键
      * @return Object 值
      */
     Object getAttr(Object object);

     /**
      * 设置上下文属性
      * @param key 键
      * @param value 值
      */
     void setAttrs(Object key,Object value);

     /**
      * 销毁所有实例
      */
     void dispose();

     /**
      * 设置 bean
      * @param name 名称
      * @param object bean实例
      */
     void setBean(String name,Object object);

     /**
      * 打印下ioc容器概览
      */
     void overview();
}

  • 定义了三个注解

@MyAutowired 对应Spring里的@Autowired
@MyComponent 对应Spring里的@Component
@MyScope 对应Spring里的@Scope

package com.humorchen.spring_ioc_impl.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自动填充注解
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAutowired {
    public String value() default "";
}

package com.humorchen.spring_ioc_impl.annotation;

import com.humorchen.spring_ioc_impl.constant.ScopeType;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 组件注解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {
    //component name
    public String name() default "";
    public String scope() default ScopeType.SINGLETON;
}

package com.humorchen.spring_ioc_impl.annotation;

import com.humorchen.spring_ioc_impl.constant.ScopeType;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * scope注解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyScope {
    public String value() default ScopeType.SINGLETON;
}

  • 一个常量类用来存scope
package com.humorchen.spring_ioc_impl.constant;

/**
 * Scope 单例/多例
 */
public interface   ScopeType {
    //单例模式
    String SINGLETON ="singleton";
    //多例模式
    String PROTOTYPE ="prototype";
}

  • 一个自定义的类加载器
package com.humorchen.spring_ioc_impl.classloader;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;

/**
 * 自定义类加载器
 */
public class MyClassLoader extends ClassLoader {
    private static String MINE=MyClassLoader.class.getName();
    /**
     * 传入绝对路径则  loadClass("F:\\project\\spring_ioc_impl\\target\\classes\\com\\humorchen\\spring_ioc_impl\\annotation\\MyAutowired.class",false)
     * @param absolutePath 绝对路径
     * @return
     */
    public Class loadClass(String absolutePath,String name){
        //如果已经加载了直接返回
        try {
            Class cls=MyClassLoader.class.getClassLoader().loadClass(name);
            if(cls!=null){
                return cls;
            }
        }catch (Exception e){}
        //没有加载的继续加载
        byte[] data=loadData(absolutePath);
        return this.defineClass(name,data,0,data.length);
    }

    private byte[] loadData(String path){
        try {
            FileInputStream inputStream=new FileInputStream(path);
            ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
            int b;
            while ((b=inputStream.read())!=-1){
                byteArrayOutputStream.write(b);
            }
            inputStream.close();
            return byteArrayOutputStream.toByteArray();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

  • 上下文Context的两种实现
  • MySpringDefaultContext
package com.humorchen.spring_ioc_impl.context;

import com.humorchen.spring_ioc_impl.annotation.MyAutowired;
import com.humorchen.spring_ioc_impl.annotation.MyComponent;
import com.humorchen.spring_ioc_impl.annotation.MyScope;
import com.humorchen.spring_ioc_impl.constant.ScopeType;
import com.humorchen.spring_ioc_impl.exception.MyAutowiredException;
import com.humorchen.spring_ioc_impl.exception.MyBeanNotFoundException;
import com.humorchen.spring_ioc_impl.exception.NotSupportException;
import com.humorchen.spring_ioc_impl.interfaces.MySpringContext;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 默认上下文
 */
public class MySpringDefaultContext implements MySpringContext {
    public Object getBean(String name) {
        Object bean=IOC.get(name);
        if(bean!=null){
            return bean;
        }
        return null;
    }

    /**
     * 概览
     */
    public void overview(){
        System.out.println("\n\n");
        System.out.println("-----------------IOC容器概览---------------------");
        System.out.println("IOC容器中共有"+IOC.size()+"个bean");
        for(String name:IOC.keySet()){
            System.out.println(name);
        }
        System.out.println("-------------------------------------------------");
        System.out.println("\n\n");
    }

    /**
     * 获取bean
     * @param cls bean的类型
     * @return
     */
    public Object getBean(Class cls) {
        MyComponent myComponent=(MyComponent)cls.getAnnotation(MyComponent.class);
        MyScope myScope=(MyScope) cls.getAnnotation(MyScope.class);
        String type=ScopeType.SINGLETON;
        if((myComponent!=null&&myComponent.scope().equals(ScopeType.PROTOTYPE))||(myScope!=null&&myScope.value().equals(ScopeType.PROTOTYPE)))
        {
            type=ScopeType.PROTOTYPE;
        }
        if(type.equals(ScopeType.SINGLETON)){
            //单例模式
            String name=genName(cls);
            Object object=getBean(name);
            //直接找这个类的实例
            if(object!=null){
                return object;
            }
            if(cls.isAnnotation()){
                throw new NotSupportException("类型:注解"+cls.getName());
            }
            //找同类型的且优先同类型
            List<Object> instances=new ArrayList<Object>();
            for(Map.Entry<String,Object> entry:IOC.entrySet()){
                if(cls.isInstance(entry.getValue())){
                    instances.add(entry.getValue());
                }
            }
            //找不到这个类的实例如果是个接口就找这个类实现类的实例
            if(cls.isInterface()){
                //找实现类的实例
                for (Object o:instances){
                    if(cls.isInstance(o)){
                        return o;
                    }
                }
                //找不到实现类的实例对象
                throw  new MyBeanNotFoundException("找不到"+cls.getName()+"的任何实现类bean");
            }

            //先找同类型
            for (Object o:instances){
                if (cls.equals(o.getClass())){
                    return o;
                }
            }
            //后找子类
            for (Object o:instances){
                if (cls.isInstance(o)){
                    return o;
                }
            }
            //子类的实例也找不到就去创建一个
            return genObjectByClass(cls);
        }else{
            //多例模式

            //找同类型的且优先同类型
            List<Object> instances=new ArrayList<Object>();
            for(Map.Entry<String,Object> entry:IOC.entrySet()){
                if(cls.isInstance(entry.getValue())){
                    instances.add(entry.getValue());
                }
            }
            //找不到这个类的实例如果是个接口就找这个类实现类的实例
            if(cls.isInterface()){
                //找实现类的实例
                for (Object o:instances){
                    if(cls.isInstance(o)){
                        return genObjectByClass(o.getClass());
                    }
                }
                //找不到实现类的实例对象
                throw  new MyBeanNotFoundException("找不到"+cls.getName()+"的任何实现类bean");
            }
            //先找同类型
            for (Object o:instances){
                if (cls.equals(o.getClass())){
                    return genObjectByClass(o.getClass());
                }
            }
            //后找子类
            for (Object o:instances){
                if (cls.isInstance(o)){
                    return genObjectByClass(o.getClass());
                }
            }
            return genObjectByClass(cls);
        }
    }

    /**
     * 根据类生成对象实例
     * @param cls
     * @return
     */
    protected Object genObjectByClass(Class cls){
        try {
            Object object=cls.newInstance();
            for(Field field:cls.getDeclaredFields()){
                MyAutowired annotation=field.getAnnotation(MyAutowired.class);
                //是否存在需要注入的方法
                if(annotation!=null){
                    field.setAccessible(true);
                    //如果注入的时候传入了bean的名字
                    String name=annotation.value();
                    Object fieldObj;
                    if(name.equals("")){
                        fieldObj=getBean(field.getType());
                    }else{
                        fieldObj=getBean(name);
                    }
                    if(fieldObj!=null){
                        field.set(object,fieldObj);
                    }else{
                        throw new MyAutowiredException("创建对象时自动注入异常"+cls.getName()+":"+field.getName());
                    }
                }
            }
            String name=genName(cls);
            IOC.put(name,object);
            return object;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 销毁
     */
    public void dispose() {
        IOC.clear();
        ATTRS.clear();
    }

    public void setBean(String name, Object object) {
        IOC.put(name,object);
        Class cls=object.getClass();
    }
    public void setBean(Class cls, Object object) {
        String name=genName(cls);
        IOC.put(name,object);
    }
    private String genName(Class cls){
        return cls.getName();
    }

    public Object getAttr(Object object) {
        return ATTRS.get(object);
    }

    public void setAttrs(Object key, Object value) {
        ATTRS.put(key,value);
    }
}

  • MySpringPackageContext包扫描的上下文
package com.humorchen.spring_ioc_impl.context;

import com.humorchen.spring_ioc_impl.annotation.MyComponent;
import com.humorchen.spring_ioc_impl.bean.User;
import com.humorchen.spring_ioc_impl.util.ClassFileScanUtil;

import java.util.List;

/**
 * 带包扫描的上下文
 */
public class MySpringPackageContext extends MySpringDefaultContext {
    public MySpringPackageContext(String packageName){
        //扫描出这个包下面的所有类
        List<Class> classes= ClassFileScanUtil.scanPackageRetClass(packageName);
        for (Class cls:classes){
            //对需要IOC管理的进行解析初始化容器
            MyComponent myComponent=(MyComponent) cls.getAnnotation(MyComponent.class);
            if (myComponent!=null){
                super.genObjectByClass(cls);
            }
        }
    }


}

  • 类加载的时候扫描用到的工具类
package com.humorchen.spring_ioc_impl.util;

import com.humorchen.spring_ioc_impl.bean.User;
import com.humorchen.spring_ioc_impl.classloader.MyClassLoader;

import java.io.File;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;

/**
 * 扫描某个目录下的所有class文件工具
 */
public class ClassFileScanUtil {
    /**
     * 扫描出一个目录下所有的class文件
     * @param directory
     * @return
     */
    public static List<String> scanRetFilePath(String directory){
        List<String> classes=new ArrayList<String>();
        File root=new File(directory);
        if(root.isDirectory()){
            File[] files=root.listFiles();
            for(File file:files){
                if(file.isDirectory()){
                    //如果是目录则递归
                    classes.addAll(scanRetFilePath(file.getAbsolutePath()));
                }else if(file.isFile()&&file.getName().endsWith(".class")){
                    //符合则加入
                    classes.add(file.getAbsolutePath());
                }
            }
        }
        return classes;
    }
    public static List<Class> scanPackageRetClass(String packageName){
        String rootDir=getClassRootDirPath();
        MyClassLoader classLoader=new MyClassLoader();
        List<String> classes=scanRetFilePath(rootDir);
        List<Class> ret=new ArrayList<Class>();
        for(String cls:classes){
            String name=getClassNameByAbsolutePath(cls,rootDir);
            if(name.startsWith(packageName)){
                Class loadedClass=classLoader.loadClass(cls,name);
                ret.add(loadedClass);
            }
        }
        return ret;
    }
    /**
     * 对某个目录下的所有类扫描出来并返回
     * @param directory
     * @return
     */
    public static List<Class> scanRetClass(String directory){
        File root=new File(directory);
        String prefix=root.getAbsolutePath();
        List<String> filesPath=scanRetFilePath(directory);
        List<Class> ret=new ArrayList<Class>();
        MyClassLoader classLoader=new MyClassLoader();
        for(String path:filesPath){
            if(path.startsWith(prefix)){
                System.out.println(path);
                String name=getClassNameByAbsolutePath(path,prefix);
                System.out.println(name);
                Class cls=classLoader.loadClass(path,name);
                if(cls!=null){
                    ret.add(cls);
                }
            }
        }
        return ret;
    }

    /**
     * 获得class存放的目录的绝对路径
     * @return
     */
    public static String getClassRootDirPath(){
        return new File(URLDecoder.decode(ClassFileScanUtil.class.getClassLoader().getResource("").getPath())).getAbsolutePath();
    }

    /**
     * 给定一个类的完整路径和项目源码根路径,生成类名
     * @param absolutePath
     * @param srcDirPath
     * @return
     */
    public static String getClassNameByAbsolutePath(String absolutePath,String srcDirPath){
        String name=absolutePath.replace(srcDirPath+File.separator,"").replace(File.separator,".");
        name=name.substring(0,name.length()-6);
        return name;
    }

}

  • 三个异常类

MyAutowiredException
MyBeanNotFoundException
NotSupportException
在这里插入图片描述

posted @ 2020-12-15 18:41  HumorChen99  阅读(1)  评论(0编辑  收藏  举报  来源