手写 spring IOC控制反转

博客介绍控制反转思想,其目的是降低程序耦合度、提高扩展力。反转的是对象创建权和关系维护权,交给第三方容器。还讲述了自己实现的ApplicationContext,通过getBean方法,利用File类和反射思想,用map存储对象,类似spring的IOC。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 控制反转是一种思想。

  • 控制反转是为了降低程序耦合度,提高程序扩展力。

  • 控制反转,反转的是什么?

    • 将对象的创建权利交出去,交给第三方容器负责。
    • 将对象和对象之间关系的维护权交出去,交给第三方容器负责。

自己写的 ApplicationContext 主要提供getBean方法

public interface ApplicationContext {

    Object getBean(Class clazz);
}

然后创建实现类,原spring中的IOC就是用MAP来存储对象并且返回的,则我们也创建map来存储对象,主要就是应用FIle类和反射的思想,从类的字节码一步一步把对象构建出来

public class AnnotationApplicationContext implements ApplicationContext{

    //创建map集合,放bean对象   模拟IOC对象的存储方式
    private Map<Class,Object> beanFactory = new HashMap<>();

    private static String rootPath;

    //返回对象
    @Override
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }

    //设置包扫描规则
    //当前包及其子包,那个类有@Bean注解,把这个类通过反射实例化
    public AnnotationApplicationContext(String basePackage){

        //basePackage = com.atguigu 我们需要把·换位斜杠,这样才符合路径规则
        try {
            String packagePath = basePackage.replaceAll("\\.","\\\\");

            //通过该路径获得相应的绝对路径
            Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packagePath);
            while(urls.hasMoreElements()){
                URL url = urls.nextElement();
                String filePath = URLDecoder.decode(url.getFile(), "utf-8");

                //获取绝对路径后,由于出了包可能会不同,但包前面的绝对路径都是相同的,则可以截取出来反复使用
                rootPath = filePath.substring(0, filePath.length() - packagePath.length());

                //包扫描
                loadBean(new File(filePath));

            }

        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

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

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

            //4 如果文件里面不为空,遍历文件夹所有内容
            for(File child : childrenFiles){
                //4.1 遍历得到每个File对象,继续判断,如果还是文件夹,递归
                if(child.isDirectory()){
                    loadBean(child);
                }else{
                    //4.2 遍历得到的File对象不是文件夹,是文件,
                    //4.3 得到包路径+类名称部分 (字符串截取)
                    String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
                    //4.4 判断当前文件类型是否.class
                    if(pathWithClass.contains(".class")){
                        //4.5 如果是.class类型,把路径\替换成. 把.class去掉
                        String allName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
                        //com.atguigu.service.UserServiceImpl
                        //4.6 判断类型上面是否有注解 @Bean, 如果有实例化过程
                        //4.6.1 获取类的Class对象
                        Class<?> clazz = Class.forName(allName);

                        //4.6.2 判断不是接口
                        if(!clazz.isInterface()){
                            //4.6.3 判断上面是否有@Bean
                            Bean annotation = clazz.getAnnotation(Bean.class);
                            if(annotation != null){
                                //4.6.4 实例化
                                Object instance = clazz.getConstructor().newInstance();
                                //4.7 把对象实例化之后,放到map集合beanFactory
                                //4.7.1 当前类如果实现类接口,让接口class作为map的key
                                if(clazz.getInterfaces().length>0){
                                    beanFactory.put(clazz.getInterfaces()[0],instance);
                                }else{
                                    beanFactory.put(clazz,instance);
                                }

                            }
                        }


                    }


                }


            }


        }




    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值