Java手写IOC

视频教程连接

点击进入
本文实现的注解有

  • @Component
  • @Value
  • @Autowired
  • @Qualifier
    在这里插入图片描述

实现的效果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

实现这些IOC的思路

在这里插入图片描述

1. 获取到我们要管理的Class对象

我们首先要扫描我们要用的包 然后获取到所有有我们定义的@myComponent注解的Class对象 然后把这些Class和他们的名字给封装到一个对象里面在这里插入图片描述
然后我们把获取到的所有对象给放到一个Set集合里面提供给下面步骤的使用

2.实例化要管理的对象 把初始化之后的对象给放到Map容器里面

  • 在第一步的时候我们获取到了所有要管理的MyBeanDefinition
    因为这个对象里面有Class 我们可以直接用反射去用
    clazz.newInstance();调用无参构造方法实例化
  • 然后我们通过反射获取@myValue注解里面的值 然后用反射调用set方法把值给赋进去
    这样我们的对象就能初始化了
  • 我们还需要把这个初始化之后的对象给设置一个名字 根据spring的习惯来说 默认命名都是类 的首字母小写 这一步我们直接把第一步获取到的BeanName处理一下就行了
  • 最后我们把初始化好的 还有他的名字给放到一个Map集合里面 这样一个容器就差不多快做成了

3.依赖注入的实现

  1. 去遍历我们在第一步做好的那个Set 然后找到有@myAutowired这个注解标记的变量
    @myAutowired是根据类型自动注入 或者说就是根据类型的名字去第二部的那个Map容器里面去找名字(key)一样的对象然后赋值 @myQualifier是根据注解里面的value去Map容器里面找对象
  2. 我们获取到有@myAutowired注解的变量的时候还要检查他有没有被 @myQualifier标记
    如果有就根据value找第二步初始化之后的对象 没的话就自动注入就行了

具体实现步骤

注解

这四个注解的使用位置不同 但是我让他们都保存到运行时了
@myAutowired是自动根据类型名注入

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

}

@myComponent标记该类让他被我写的ioc管理

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

@myQualifier是根据value去注入

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

@myValue是根据value的值给实例化对象赋值

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

MyBeanDefinition 存放Class和ClassName

public class MyBeanDefinition {
    private String BeanName;
    private Class beanClass;

    @Override
    public String toString() {
        return "MyBeanDefinition{" +
                "BeanName='" + BeanName + '\'' +
                ", beanClass=" + beanClass +
                '}';
    }

    public String getBeanName() {
        return BeanName;
    }

    public void setBeanName(String beanName) {
        BeanName = beanName;
    }

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class beanClass) {
        this.beanClass = beanClass;
    }

    public MyBeanDefinition(String beanName, Class beanClass) {
        BeanName = beanName;
        this.beanClass = beanClass;
    }
}

MyAnnotationConfigApplicationContext(重点 IOC的核心)

就和上面思路里面说的一样 分三步走就好了

在这里插入图片描述

第一步的实现 获取到我们要管理的Class对象的

我们直接用工具就好了 获取到存放所有class的Set集合 然后通过迭代器遍历
在这里插入图片描述
在这里插入图片描述
不处理的话名字是这样的 如果把这个当成Bean的名字太长了 就截取最后的类名就行
在这里插入图片描述

思路第二步的实现 实例化并且初始化把对象给放到Map容器里面

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

第三步 把我们的存入map的bean给赋值到需要的地方

手动指定bean

在这里插入图片描述

自动注入

在这里插入图片描述

全部代码如下

public class MyAnnotationConfigApplicationContext{

    private Map<String, Object> map = new HashMap();

    public MyAnnotationConfigApplicationContext(String pack) {
        //扫描包下所有的class 吧有mybean注解的都放到set里面
        Set<MyBeanDefinition> beanDefinitions = findBeanDefinitions(pack);
        //根据set里面的beanDefinitions来 创建对象放到map里面
            createObject(beanDefinitions);
        //把map里面的对像给自动装配
            autowireObject(beanDefinitions);

    }
    public Object getBean(String name){
        return map.get(name);
    }

    public void autowireObject(Set<MyBeanDefinition> beanDefinitions)  {
        Iterator<MyBeanDefinition> iterator = beanDefinitions.iterator();
        while(iterator.hasNext()){
            MyBeanDefinition next = iterator.next();
            Class beanClass = next.getBeanClass();
            for (Field declaredField : beanClass.getDeclaredFields()) {
                myAutowired annotation = declaredField.getAnnotation(myAutowired.class);
                if (annotation!=null){
                    //根据bean的name获取bean
                    myQualifier declaredannotation = declaredField.getAnnotation(myQualifier.class);
                    if (declaredannotation!=null){
                        try {
                        String beanName = declaredannotation.value();
                        Object bean = getBean(beanName);
                        String fieldName = declaredField.getName();
                        String methodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
                        Method method = null;
                        method = beanClass.getMethod(methodName, declaredField.getType());
                        Object object = getBean(next.getBeanName());
                        method.invoke(object, bean);
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        }
                    }else{
                        //自动装配  获取到
                        try {
                            String name = declaredField.getType().getName();
                            String className =   name.replaceAll( beanClass.getPackage().getName() + ".", "");
                            String  beanName = className.substring(0, 1).toLowerCase()+className.substring(1);
                            Object bean = getBean(beanName);
                            String fieldName = declaredField.getName();
                            String methodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
                            Method method = null;
                            method = beanClass.getMethod(methodName, declaredField.getType());
                            Object object = getBean(next.getBeanName());
                            method.invoke(object, bean);
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        }
                    }
                }

            }

        }
    }

    public void createObject( Set<MyBeanDefinition> set){
        Iterator<MyBeanDefinition> iterator = set.iterator();
        while(iterator.hasNext()){
            MyBeanDefinition next = iterator.next();
            Class beanClass = next.getBeanClass();
            String beanName = next.getBeanName();

            try {
                //根据findBeanDefinitions里面存入的 class对象来新建一个对象
                Object o = beanClass.newInstance();
                Field[] declaredFields = beanClass.getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    myValue myValueAnnotation = declaredField.getAnnotation(myValue.class);
                    if (myValueAnnotation!=null){
                        String value = myValueAnnotation.value();//获取value上面的值
                        String name = declaredField.getName();//获取方法名字
                        String methodName = "set"+name.substring(0, 1).toUpperCase()+name.substring(1);

                        try {
                            //获取get方法
                            System.out.println(methodName);
                            Method method = beanClass.getMethod(methodName,declaredField.getType());
                            try {

                                //完成数据类型转换
                                Object val = null;
                                switch (declaredField.getType().getName()){
                                    case "java.lang.Integer":
                                        val = Integer.parseInt(value);
                                        break;
                                    case "java.lang.String":
                                        val = value;
                                        break;
                                    case "java.lang.Float":
                                        val = Float.parseFloat(value);
                                        break;
                                }                               //使用 set方法
                                method.invoke(o,val);
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }

                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        }

                    }

                    System.out.println(declaredField);
                }
                map.put(beanName,o);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        }

    }

    public Set<MyBeanDefinition> findBeanDefinitions(String pack){
        Set<MyBeanDefinition> myset=new HashSet<>();

        //获取到包下所有的类
        Set<Class<?>> classes = MyTools.getClasses(pack);
        Iterator<Class<?>> iterator = classes.iterator();
        while(iterator.hasNext()){
            Class<?> next = iterator.next();
            myComponent annotation = next.getAnnotation( myComponent.class);
            if(annotation != null){
                String packname = next.getPackage().getName();
                String name = next.getName();
                String beanName  = annotation.value();
                if("".equals(beanName)){
                    String classname = name.replace(packname + ".", "");
                    String s = classname.substring(0, 1).toLowerCase();
                    beanName=s+classname.substring(1);
                }
                myset.add(new MyBeanDefinition(beanName,next));


            }
        }
        return myset;
    }

}

MyTools工具类

这个工具类做的主要是遍历指定的包 然后获取包里面的class
我的建议是 CV

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class MyTools {

    public static Set<Class<?>> getClasses(String pack) {

        // 第一个class类的集合
        Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
        // 是否循环迭代
        boolean recursive = true;
        // 获取包的名字 并进行替换
        String packageName = pack;
        String packageDirName = packageName.replace('.', '/');
        // 定义一个枚举的集合 并进行循环来处理这个目录下的things
        Enumeration<URL> dirs;
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            // 循环迭代下去
            while (dirs.hasMoreElements()) {
                // 获取下一个元素
                URL url = dirs.nextElement();
                // 得到协议的名称
                String protocol = url.getProtocol();
                // 如果是以文件的形式保存在服务器上
                if ("file".equals(protocol)) {
                    // 获取包的物理路径
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    // 以文件的方式扫描整个包下的文件 并添加到集合中
                    findClassesInPackageByFile(packageName, filePath, recursive, classes);
                } else if ("jar".equals(protocol)) {
                    // 如果是jar包文件
                    // 定义一个JarFile
                    System.out.println("jar类型的扫描");
                    JarFile jar;
                    try {
                        // 获取jar
                        jar = ((JarURLConnection) url.openConnection()).getJarFile();
                        // 从此jar包 得到一个枚举类
                        Enumeration<JarEntry> entries = jar.entries();
                        findClassesInPackageByJar(packageName, entries, packageDirName, recursive, classes);
                    } catch (IOException e) {
                        // log.error("在扫描用户定义视图时从jar包获取文件出错");
                        e.printStackTrace();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return classes;
    }

    private static void findClassesInPackageByJar(String packageName, Enumeration<JarEntry> entries, String packageDirName, final boolean recursive, Set<Class<?>> classes) {
        // 同样的进行循环迭代
        while (entries.hasMoreElements()) {
            // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
            JarEntry entry = entries.nextElement();
            String name = entry.getName();
            // 如果是以/开头的
            if (name.charAt(0) == '/') {
                // 获取后面的字符串
                name = name.substring(1);
            }
            // 如果前半部分和定义的包名相同
            if (name.startsWith(packageDirName)) {
                int idx = name.lastIndexOf('/');
                // 如果以"/"结尾 是一个包
                if (idx != -1) {
                    // 获取包名 把"/"替换成"."
                    packageName = name.substring(0, idx).replace('/', '.');
                }
                // 如果可以迭代下去 并且是一个包
                if ((idx != -1) || recursive) {
                    // 如果是一个.class文件 而且不是目录
                    if (name.endsWith(".class") && !entry.isDirectory()) {
                        // 去掉后面的".class" 获取真正的类名
                        String className = name.substring(packageName.length() + 1, name.length() - 6);
                        try {
                            // 添加到classes
                            classes.add(Class.forName(packageName + '.' + className));
                        } catch (ClassNotFoundException e) {
                            // .error("添加用户自定义视图类错误 找不到此类的.class文件");
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    private static void findClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, Set<Class<?>> classes) {
        // 获取此包的目录 建立一个File
        File dir = new File(packagePath);
        // 如果不存在或者 也不是目录就直接返回
        if (!dir.exists() || !dir.isDirectory()) {
            // log.warn("用户定义包名 " + packageName + " 下没有任何文件");
            return;
        }
        // 如果存在 就获取包下的所有文件 包括目录
        File[] dirfiles = dir.listFiles(new FileFilter() {
            // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
            @Override
            public boolean accept(File file) {
                return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
            }
        });
        // 循环所有文件
        for (File file : dirfiles) {
            // 如果是目录 则继续扫描
            if (file.isDirectory()) {
                findClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
            } else {
                // 如果是java类文件 去掉后面的.class 只留下类名
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    // 添加到集合中去
                    // classes.add(Class.forName(packageName + '.' +
                    // className));
                    // 经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
                    classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
                } catch (ClassNotFoundException e) {
                    // log.error("添加用户自定义视图类错误 找不到此类的.class文件");
                    e.printStackTrace();
                }
            }
        }
    }

}

测试方法

public class run {
    public static void main(String[] args) {
        MyAnnotationConfigApplicationContext myAnnotationConfigApplicationContext = new MyAnnotationConfigApplicationContext("myioc.test");
        Object student = myAnnotationConfigApplicationContext.getBean("student");
        System.out.println(student.toString());
        Object at = myAnnotationConfigApplicationContext.getBean("at");
        At a=(At)at;
        System.out.println("================");
        System.out.println(a.student.toString());
    }
}

@myComponent()
public class At {
  @myAutowired
  @myQualifier("student")
  public Student student;

  @Override
  public String toString() {
      return "At{" +
              "student=" + student +
              '}';
  }

  public Student getStudent() {
      return student;
  }

  public void setStudent(Student student) {
      this.student = student;
  }

  public At() {
  }

  public At(Student student) {
      this.student = student;
  }
}

package myioc.test;

import myioc.myAnnotation. myComponent;
import myioc.myAnnotation.myValue;
@myComponent()
public class Student {
    @myValue("张三")
    String name;
    @myValue("25")
    Integer age;

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值