理解IOC --- 一

IOC: 控制反转. 它是怎么实现的呢?

    首先, 要先定义需要控制反转的范围, 也就是确定哪些.class文件需要. 那我们首先找到项目下的所有 .class 文件.

    建立一个普通java工程


在 ClassUtil中定义一个方法来获取当前线程


定义一个方法获取指定包名下的所有类


在getClassSet方法内使用

Enumeration<URL> urls = getClassLoader().getResources(pkgName.replace(".", "/"));

进行枚举.

开始遍历


最后整理一下

public static Set<Class<?>> getClassSet(String pkgName) {
    Set<Class<?>> classSet = new HashSet<>();
    try {
        Enumeration<URL> urls = getClassLoader().getResources(pkgName.replace(".", "/"));
        while(urls.hasMoreElements()) {     // 遍历
            URL url = urls.nextElement();
            if(url != null) {
                String protocol = url.getProtocol();    // 获取协议, 防止可能有压缩包那些
                if("file".equals(protocol)) {           // 类型是文件
                    String pkgPath = url.getPath().replace("%20", " ");// 空格问题
                    addClass(classSet, pkgPath, pkgName);   // 调用addClass方法
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return classSet;
}

在遍历循环内我们调用了 addClass方法, 这个方法用来添加类

private static void addClass (Set<Class<?>> classSet, String pkgPath, String pkgName) {
    // 放入 files 的条件
    File[] files = new File(pkgPath).listFiles(file -> (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory());
    for(File file : files != null ? files : new File[0]) {
        String fileName = file.getName();
        if(file.isFile()) {     // 是文件而不是包, 同时也是递归的出口
            String className = fileName.substring(0, fileName.lastIndexOf("."));    // 字符串截断, 去掉后面的 .class
            if(!pkgName.isEmpty()) {
                className = pkgName + "." + className;
            }
            addClass(classSet, className);
        }else {                 // 不是文件的情况, 需要进入这个目录向下
            String subPath = "/" + fileName;
            if(!pkgPath.isEmpty()) {
                subPath = pkgPath + subPath;
            }
            String subName = "." + fileName;
            if(!pkgPath.isEmpty()) {
                subName = pkgName + subName;
            }
            // 递归调用
            addClass(classSet, subPath, subName);
        }
    }
}
private static void addClass (Set<Class<?>> classSet, String className) {
    System.out.println(className);    // 直接打印看看结果
}

接下来我们写一个测试类

@Test
public void test1() {
    ClassUtil.getClassSet("tech");
}
运行结果:


可以看到我们写的所有.class文件名都被打印了出来.

控制反转是基于java的反射来实现的, 我们将所有的.class类都新建出来, 并放入一个容器中.

修改 addClass方法

private static void addClass (Set<Class<?>> classSet, String className) {
    Class<?> aClass = loadClass(className, false);
    classSet.add(aClass);
}

在addClass方法中调用loadClass, 用来反射生成,并将结果装入classSet.

public static Class<?> loadClass(String className, boolean isInitialized){
    Class<?> cls;
    try {
        cls = Class.forName(className,isInitialized,getClassLoader());
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
    return cls;
}

我们测试一下.

@Test
public void test1() {
    for(Class<?> aClass : ClassUtil.getClassSet("tech")) {
        System.out.println(aClass);
    }
}

结果


我们知道, Spring是通过注解来进行识别的, 通过注解进行自动装配, 自动生成, 并且解决类的内部域, 方便开发, 接下来我们使用自定义注解实现基本的功能

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值