spring-ioc的极简实现

spring-ioc的极简实现

简介

spring ioc的极简实现,可以完成自动属性注入,使用二级缓存解决循环依赖(就是把半成品对象放个map里先保存着),基于注解,可以指定配置文件,总计不到100行代码,可以简单对spring依赖注入有个大致的了解,项目下载链接在文末

大概步骤

最基本的注解

Autowired注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}

Component注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
}

ComponentScan注解(这个注解其实也可以不要,比如默认就扫描main方法目录)

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
    String value();
}

Application类

用来解析配置文件,创建bean

public class Application {
    Map<Class<?>,Object> singletonInstance =new HashMap<>();
    Map<Class<?>,Object> earlySingletonInstance=new HashMap<>();
    Set<Class<?>> classSet=new HashSet<>();
    public Application(Class<?> configClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        //获得扫描路径
        String path = configClass.getDeclaredAnnotation(ComponentScan.class).value();
        ClassLoader classLoader = Application.class.getClassLoader();
        //获得扫描路径下所有文件
        for (File file : new File(classLoader.getResource(path.replace(".","/")).getFile()).listFiles()) {
            //这里没有递归处理,只扫描第一层的class文件
            if(!file.getName().endsWith(".class"))continue;
            String fullName=(path+"."+file.getName()).replace(".class","");
            Class<?> aClass = classLoader.loadClass(fullName);
            //保存所有被Component注解的类
            if(aClass.isAnnotationPresent(Component.class))classSet.add(aClass);
        }
        //生成半成品对象放到二级缓存
        for (Class<?> aClass : classSet) earlySingletonInstance.put(aClass,aClass.newInstance());
        //Autowired属性注入
        for (Class<?> aClass : classSet){
            Object instance = earlySingletonInstance.get(aClass);
            for (Field field : aClass.getDeclaredFields()) {
                if(field.isAnnotationPresent(Autowired.class)){
                    field.setAccessible(true);
                    field.set(instance,earlySingletonInstance.get(field.getType()));
                }
            }
            //放到单例池
            singletonInstance.put(aClass, instance);
        }
    }
    //按类型获取,生成的都是单例bean
    public <T> T getBean(Class<T> clazz){
        return clazz.cast(singletonInstance.get(clazz));
    }
}

测试

Calculate.java,Service.java这两个文件位于io.spring.test目录下

@Component
public class Calculate {
    @Autowired
    private Service service;

    public int add(int x,int y){
        return service.add(x, y);
    }
}
@Component
public class  Service {
    @Autowired
    Calculate calculate;//测试循环依赖
    public int add(int x, int y) {
        return x+y;
    }
}
@ComponentScan("io.spring.test")//扫描路径
public class App {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        Application appContext = new Application(App.class);//初始化
        Calculate cal = appContext.getBean(Calculate.class);//获得bean对象
        System.out.println(cal.add(3,5));
    }
}

测试程序输出8,说明依赖注入的目的达到了

项目下载

https://github.com/fuchengshun/simple-spring-ioc

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » spring-ioc的极简实现