手写IOC容器,如何设置包扫描规则以及将有注解的类实例化和对象注入

首先创建两个注解一个创建对象,一个完成属性注入,然后创建bean容器接口(这里名字记为Application)定义一个方法返回对象,最后实现bean容器接口完成两个方法(1.返回对象 2.根据包规则加载bean)

(两个注解就不展示了)

//首先在实现Application的类中创建map集合来装bean对象,再实现接口方法
    private Map<Class,Object> beanFactory = new HashMap<>();

    @Override
    public Object getBean(Class c1){
        return beanFactory.get(c1)
    }

然后创建有参构造,传递包路径,设置包扫描规则
根据递归判断当前包及其子包中哪个类有注解,把这个类通过反射实例化

public AnnotationApplicationContext(String beanPackage){
    try{
        //1.把.替换成\
        Sting packagePath  = basePackage.replaceAll("\\.", "\\\\");
    
        //2.获取包的绝对路径,会返回一个枚举类
        Eumeration<URL> urls = Thread.currentTread().getContextClassLoader(packagePath);
        While(urls.hasMoreElements()) {
            URL url = urls.nextElement();
            String filePath = URLDecoder.decode(url,].getfile(),"utf-8");
            //进行包扫描
            LoadBean(new File(filePath));
        }
    }catch(Exception e){
        throw new RuntimeException(e);
    }
    //属性注入(这里将@Di为注入注解)
    loadDi();
}

这里为了后续获得包的名称方便,对包进行截取

private rootPath;

//在包扫描上面加上
rootPath = filePath.substring(0,filePath.length() - packagePath.length());

包扫描过程,实例化

过程:

        1 判断当前是否是文件夹

        2 获取文件夹里面所有内容

        3 判断文件夹里面为空,直接返回

        4 如果文件夹里面不为空,遍历文件夹所有内容

        4.1 遍历得到每个File对象,继续判断,如果还是文件,递归

        4.2 遍历得到File对象不是文件夹,那就是文件

        4.3 得到包路径+类名称部分

        4.4 判断当前文件类型是否.class

        4.5 如果是.class类型,把路径\替换成.   把.class去掉

        4.6 判断类上面是否有注解 ,如果有实例化过程

        4.7 把对象实例化之后,放到map集合beanFactory

private void loadBean(File file) throws Exception{
    //1 判断当前是否是文件夹
    if(file.isDirectory()){
        //2 获取文件夹里面所有内容
        File[] childrenFiles = file.listFiles();

        
        //3 判断文件夹里面为空,直接返回
        if(childrenFiles == null || childrenFiles.length == 0){
            retrun;
        }

        //4 如果文件夹里面不为空,遍历文件夹所有内容
        //4.1 遍历得到每个File对象,继续判断,如果还是文件,递归
        if(child.isDirectory()){
            loadBean(child);
        }else{
            //4.2 遍历得到File对象不是文件夹,那就是文件
            //4.3 得到包路径+类名称部分
            String pathWithClass = child.getAbsolutePath().substring(rootPath

            //4.4 判断当前文件类型是否.class
            if(pathWithClass.contains(".class")){
                //4.5 如果是.class类型,把路径\替换成.   把.class去掉
                String allName = pathWithClass.replaceAll("\\\\",".")
                                 .replace(".class","");
                //4.6 判断类上面是否有注解 ,如果有实例化过程
                //4.6.1 获取类的class
                Class<?> c1 = Class.forName(allName);
                //4.6.2 判断不是接口
                if(!c1.isInterface()){
                    //4.6.3 判断类上面是否有注解 (假如是@Bean)
                    Bean annotation=c1.getAnnotation(Bean.class);
                    if(annotation != null){
                        //4.6.4 实例化
                        Object instance = c1.getConstructor().newInstance();
                        //4.7 把对象实例化之后,放到map集台beanFactory
                        //4.7.1 判断当前类如果有接口,让接口class作为map的key
                        if(c1.getInterfaces().length>0){
                            beanFactory.put(c1.getInterfaces()[0],instance);
                        }else{
                            beanFactory.put(c1,instance);
                        }
                    }
                }
            }
        }
    }
}

                



        

属性注入

实例化对象在beanFactory的map集合里面

1 遍历beanFactory的map集合

2 获取map集合每个对象(value),获取到每个对象属性

3 遍历得到每个对象属性数组,得到每个属性

4 判断属性上面是有@Di注解

        如果私有属性,设置可以设置值

5 如果有@Di注解,把对象进行注入

private void loadDi(){
    //实例化对象在beanFactory的map集合里面
    //1 遍历beanFactory的map集台
    Set<Map.Entry<Class, Object>> entries = beanFactory.entrySet();
    for(Map.Entry<class,object>entry:entries){
        //2 获取map集合每个对象(value),每个对象属性获取到
        Object obj = entry.getvalue();
        //获取对象Class
        Class<?>c1 = obj.getclass();
        //获取每个对象属性
        Field[] declaredFields = c1.getDeclaredFields();
        //3 遍历得到每个对象属性数组,得到每个属性
        for(Field field:declaredFields){
            //4 判断属性上面是否有@Di注解
            Di annotation = field.getAnnotation(Di.class);
            if(annotation != null){
                //如果私有属性,设置可以设置值
                field.setAccessible(true);
                //5 如果有@Di注解,把对象进行设置(注入)
                try{
                    field.set(obj,beanFactory.get(field.getType()));
                }catch(IllegalAccessException e){
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值