通过反射写出ioc控制反转的bean注入流程和注解解析过程

自定义的四个注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)//内置注解表名用于变量上
@Retention(RetentionPolicy.RUNTIME)//表示在程序运行是也生效
public @interface autowrite {
    String value() default "";//default 设置默认值
}
import java.lang.annotation.*;

@Target({ElementType.METHOD,ElementType.TYPE})//内置注解表名用于方法上
@Retention(RetentionPolicy.RUNTIME) //表示在程序运行是也生效
@Inherited
public  @interface bean {
    String value() default ""; //default 设置默认值
}

还有一个枚举

public enum Resources {
    path(System.getProperty("user.dir") + "\\src\\");


    public String PATH;

    Resources(String PATH) {
        this.PATH = PATH;
    }
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)//
@Retention(RetentionPolicy.RUNTIME) //表示在程序运行是也生效
public @interface component {
    String value() default "";
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)//内置注解表名用于变量上
@Retention(RetentionPolicy.RUNTIME)//表示在程序运行是也生效
public @interface value {
    String value();
}
import com.config.autowrite;
import com.config.bean;
import com.config.component;
import com.config.value;
import com.enu.Resources;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class Deom06 {

    /**
     * 存储我们加载src下全部的java文件的class
     */
    private Set<Class> set = new HashSet<>();
    /**
     * 存储我们的bean对象
     */
    Map<String, Object> map = new ConcurrentHashMap<>();


    public static void main(String[] args) {
        new Deom06().run();
    }

    public void run() {
        final String property = Resources.path.PATH;
        //加载全部的class  并且初始化到我们的set集合中去
        loading(property);
        //System.out.println(set);
        //初始化我们的容器map  并且对 相应的注解进行封装
        initialization();
        System.out.println(Deom03.aa.getName());
    }

    /**
     * 加载src下的java文件
     *
     * @param filePath 路径
     */
    public void loading(String filePath) {
        File file = new File(filePath);
        final File[] files = file.listFiles();
        for (File file1 : files) {
            if (!file1.isFile()) {
                loading(file1.getPath());
            } else {
                if (file1.getPath().contains(".java")) {
                    writerClass(file1);
                }
            }
        }
    }

    /**
     * @param file 把java文件通类加载对象放到我们的set集合里面去
     */
    public void writerClass(File file) {
        String packName = file.getPath().substring(0, file.getPath().indexOf(".java"));
        packName = packName.substring(file.getPath().indexOf("src") + 4);
        packName = packName.replace("\\", ".");
        try {
            final Class aClass = Class.forName(packName);
            set.add(aClass);
        } catch (ClassNotFoundException e) {
            System.out.println(e.getMessage() + "加载异常!!!!!");
        }
    }

    /**
     * 初始化我们的bean 和对我们相应注解需要赋值的对象自动的注入
     */
    public void initialization() {
        for (Class c : set) {
            //component 注解
            writeComponent(c);
            //获取当前calss下的全部方法
            final Method[] methods = c.getDeclaredMethods();
            //遍历方法
            for (Method method : methods) {
                //bean注解
                writerBean(method, c);
            }
        }
        //注解autoWrite的注入
        AnnotationAssignmentAnalysis();
    }

    /**
     * 设置默认值
     *
     * @param c 传入过来的参数
     */
    private Object writeValue(Class c) {
        final Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            final value annotation = field.getAnnotation(value.class);
            if (annotation != null) {
                //当前类下的变量确实有这个注解 我们去给他赋上注解上的默认值
                final String value = annotation.value();
                try {
                    Object o = c.newInstance();
                    field.set(o, value);
                    return o;
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                }
                field.setAccessible(false);
            }
        }
        return c;
    }

    /**
     * 类自动创对象并且加入到bean中去
     *
     * @param c
     */
    private void writeComponent(Class c) {
        final component annotation = (component) c.getAnnotation(component.class);
        if (annotation != null) {
            //证明 我们找到了需要添加到我们bean里面的类
            if (annotation.value().equals("")) {
                //用户没有设置组件名 我们默认就类名小写
                //获取类名
                String simpleName = c.getSimpleName();
                //类名转小写
                simpleName = simpleName.toLowerCase(Locale.ROOT);
                //创建当前类的对象 并且去查询看看有不有value注解的使用
                map.put(simpleName, writeValue(c));
            } else {
                map.put(annotation.value(), writeValue(c));
            }

        }
    }

    /**
     * bean注解的注入实现
     *
     * @param method 方法的class
     */
    public void writerBean(Method method, Class c) {
        //判断方法上面有ben没有
        if (method.getAnnotation(bean.class) != null) {
            final bean annotation = method.getAnnotation(bean.class);
            String name = null;
            //判断写添加bean的名称没有 如果写了就用用户的  如果没有写我们就通过反射获取 方法名添加到我们的map里面去
            if (!annotation.value().equals("")) {
                name = annotation.value();
            } else {
                //有的话我们把返回的对象添加到我们的map里面去
                name = method.getName();
            }
            //把返回值添加到map里面
            try {
                map.put(name, method.invoke(c.newInstance()));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 注释分配分析
     */
    public void AnnotationAssignmentAnalysis() {

        for (Class c : set) {
            //获取全部的变量
            final Field[] fields = c.getDeclaredFields();
            for (Field field : fields) {
                //检查变上有不有我们的注解bean
                final autowrite annotation = field.getAnnotation(autowrite.class);
                if (annotation != null) {
                    //我们先判断是否写bean的名字  如果写了我们直接去map里面去找 如果没有我就循环遍历去找
                    field.setAccessible(true);
                    final String value = field.getAnnotation(autowrite.class).value();
                    if (!field.getAnnotation(autowrite.class).value().equals("")) {
                        if (map.get(value) == null) throw new RuntimeException("检查bean名是否有误!");
                        try {
                            field.set(c.newInstance(), map.get(value));
                        } catch (IllegalAccessException | InstantiationException e) {
                            e.printStackTrace();
                        }
                        field.setAccessible(false);
                    } else {
                        //有的话我们的循环检查看看有不有相应的对象类型如果有我们就赋值上去
                        for (Map.Entry<String, Object> entry : map.entrySet()) {
                            //判断两个对象直接的类型是不是一致的 如果是一致那就证明是需要注入的对象
                            if (entry.getValue().getClass().hashCode() == field.getType().hashCode()) {
                                try {
                                    field.set(c.newInstance(), entry.getValue());
                                } catch (IllegalAccessException | InstantiationException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                    field.setAccessible(false);
                }
            }
        }
    }
}