依赖注入DI --- 二

大概思路:


已经实现了将所有的类初始化的过程, 接下来我们将类里使用了注解需要依赖注入的内容实现.

如Spring框架里, Controller类里面会依赖注入Service类, Service类里会依赖注入Dao类.

public class Controller1 {          // 写一个简易的Controller类, 里面需要注入一个Service类
    
    private static Service1 service1;
    
    public static void hello() {
        service1.sayHello();
    }
}

public class Servcie1Impl implements Service1{    // 这是Service
    @Override
    public void sayHello () {
        System.out.println("hello world");
    }
}

@Target(ElementType.FIELD)                    //    自定义一个注解    
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
    Class<?> value();
}

接下来, 修改controller类里的内容, 为需要注入的service加上注解, 并写一个main主函数, 用来进行测试

public class Controller1 {
    @Inject(value = Servcie1Impl.class)
    private static Service1 service1;
    
    public static void hello() {
        service1.sayHello();
    }
    public static void main(String[] args) {
        hello();
    }
}

我们最终想要得到的结果: 运行主方法, 可以打印出 hello world.

在这里, 我们可以运用上一章所产生的ClassUtil, 将所有的类进行创建, 然后我们把这些类放入模块上下文中

public class ModuleContext {
    private static final Set<Class<?>> BEAN_SET = new HashSet<>();

    public static Set<Class<?>> getBeanSet () {                 // 定义一个getter方法
        return BEAN_SET;
    }

    static {
        String basePackage = "myTest";                          // 包名
        BEAN_SET.addAll(ClassUtil.getClassSet(basePackage));    // ClassUtil: 上一章生成的
    }
}

在主方法中, 调用classutil的loadClass方法, 

ClassUtil.loadClass(ModuleContext.class.getName(), false);

就把模块上下文初始化成功了.

接下来, 进行依赖注入

我们知道, controller里需要依赖注入service, 而service里需要依赖注入controller...., 所有, 需要进行递归操作, 每一次依赖注入的类都需要被依赖注入. 依赖注入是通过反射进行的, 定义一个反射工具类 ReflectUtil

在ReflectUtil里, 定义一个方法, 用来获取 属性Field上含有注解的注解的内容

public static <T>Map<Field, Map<String, T>> getAnnotatedFieldValue(Class<?> cls, Class<? extends Annotation> annotationCls) {
    Map<Field, Map<String, T>> rows = new HashMap<>();
    for(Field field : cls.getDeclaredFields()) {
        if(field.isAnnotationPresent(annotationCls)) {
            Annotation annotation = field.getAnnotation(annotationCls);
            for(Method method : annotation.annotationType().getDeclaredMethods()) {
                if(rows.get(field) == null) {
                    Map<String, T> value = new HashMap<>();
                    try {
                        value.put(method.getName(), (T) method.invoke(annotation));
                        rows.put(field, value);
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }else {
                    try {
                        rows.get(field).put(method.getName(), (T) method.invoke(annotation));
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    return rows;
}
rows里就装入了注解里面的内容

接下来, 定义一个方法用来进行属性的注入

public static void injectField(Object bean, Field target, Object value) {
    try {
        target.setAccessible(true);
        target.set(bean, value);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

这时呢, 需要区分一下注入的是否是一个接口或其他的类型不匹配, 添加一个判断类

private static boolean isImplementOf (Class<?> impl, Class<?> inter) {
    for(Class<?> interfaces : impl.getInterfaces()) {
        if(interfaces == inter) {
            return true;
        }
    }
    return false;
}

修改一下injectField类

public static void injectField(Object bean, Field target, Object value) {
    if(target.getType() == bean.getClass() && isImplementOf(bean.getClass(), target.getType())) {
        throw new RuntimeException("[ERROR] Field Type Do Not Match");
    }
    try {
        target.setAccessible(true);
        target.set(bean, value);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

接下来, 在ModuleContext中定义一个方法, 再定义一个管理bean的类 BeanManager

ModuleContext:

public static <T> T getBean(Class<?> cls){
    Object bean = null;
    if(BEAN_SET.contains(cls)){
        for (Class<?> aClass : BEAN_SET) {
            if (aClass == cls) {
                bean = ReflectUtil.newInstance(aClass);
            }
        }
    }else {
        throw new RuntimeException("[ERROR] CLASS NOT FOUND");
    }
    BeanManager.assemble(bean);
    return (T)bean;
}

将所有的反射活动都抽离到ReflectUtil里去,  

public static Object newInstance(Class<?> cls){
    Object newInstance;
    try {
        newInstance = cls.newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }

    return  newInstance;
}

BeanManager:

public class BeanManager {
    public static void assemble(Object bean) {
        for(Map.Entry<Field, Map<String, Object>> fieldMapEntry : ReflectUtil.getAnnotatedFieldValue(bean.getClass(), Inject.class).entrySet()) {
            injectField(bean, fieldMapEntry);
        }
    }

    private static void injectField (Object bean, Map.Entry<Field, Map<String, Object>> fieldMapEntry) {
        Field target = fieldMapEntry.getKey();                  // 这里递归调用
        ReflectUtil.injectField(bean, target, ModuleContext.getBean((Class<?>) fieldMapEntry.getValue().get("value")));
    }
}

进行递归调用, 就可以避免有些地方未注入

最后, 我们修改一下controller的主方法,进行一下测试

public static void main(String[] args) {
    ClassUtil.loadClass(ModuleContext.class.getName(), false);
    ModuleContext.getBean(Controller1.class);
    hello();
}

最后运行结果:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值