从零写一个具有IOC-AOP-MVC功能的框架—学习笔记—05. 实现容器的依赖注入

1. 实现思路及需要完成的内容

实现思路

  1. 定义相关的注解标签
  2. 实现创建被注解标记的成员变量实例,并将其注入到被@Autowired标记的成员变量中

需要完成的内容

  1. 编写ClassUtil#setField方法为对应的实例设置属性值
  2. 编写@Autowired注解
  3. 编写DependencyInjector实现属性的依赖注入

2. 第一部分: 编写@Autowired注解和ClassUtil#setField方法

2.1 本部分需要完成的代码如下:

package org.myframework.injection.annotation;

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

/**
 * @author wuyiccc
 * @date 2020/6/13 23:20
 * 岂曰无衣,与子同袍~
 */

/**
 * Autowired目前只支持成员变量级别的注入
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
    String value() default "";
}
/**
     * 设置类的属性值
     * @param field 成员变量
     * @param target 类实例
     * @param value 成员变量的值
     * @param accessible 是否允许设置私有属性
     */
    public static void setField(Field field, Object target, Object value, boolean accessible) {

        field.setAccessible(accessible);
        try {
            field.set(target, value);
        } catch (IllegalAccessException e) {
            log.error("setField error", e);
            throw new RuntimeException(e);
        }
    }

2.2 相关代码解读

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---05. 实现容器的依赖注入

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---05. 实现容器的依赖注入

3. 第二部分:完成DependencyInjector

3.1 需要完成的代码如下:

package com.wuyiccc.helloframework.injection;

import com.wuyiccc.helloframework.core.BeanContainer;
import com.wuyiccc.helloframework.injection.annotation.Autowired;
import com.wuyiccc.helloframework.util.ClassUtil;
import com.wuyiccc.helloframework.util.ValidationUtil;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.Set;

/**
 * @author wuyiccc
 * @date 2020/7/13 14:57
 * 岂曰无衣,与子同袍~
 */
@Slf4j
public class DependencyInjector {

    /**
     * Bean容器
     */
    private BeanContainer beanContainer;


    public DependencyInjector() {
        beanContainer = BeanContainer.getInstance();
    }

    /**
     * 执行IOC
     */
    public void doIoc() {

        if (ValidationUtil.isEmpty(beanContainer.getClasses())) {
            log.warn("empty classes in BeanContainer");
            return;
        }

        // 遍历容器中的所有class的对象
        for (Class<?> clazz : beanContainer.getClasses()) {

            Field[] fields = clazz.getDeclaredFields();

            if (ValidationUtil.isEmpty(fields)) {
                continue;
            }

            for (Field field : fields) {
                // 找出被Autowired标记的成员变量
                if (field.isAnnotationPresent(Autowired.class)) {
                    Autowired autowired = field.getAnnotation(Autowired.class);
                    String autowiredValue = autowired.value(); // value值
                    // 获取该field的类型
                    Class<?> fieldClass = field.getType();
                    // 获取该类型在容器中对应的实例
                    Object fieldValue = getFieldInstance(fieldClass, autowiredValue);
                    if (fieldValue == null) {
                        throw new RuntimeException("unable to inject relevant type, target fieldClass is:" + fieldClass.getName() + " autowiredValue is : " + autowiredValue);
                    } else {
                        // 通过反射将对应的成员变量实例注入到成员变量所在类的实例里
                        Object targetBean = beanContainer.getBean(clazz);
                        ClassUtil.setField(field, targetBean, fieldValue, true);
                    }
                }

            }

        }


    }

    /**
     * 根据Class在beanContainer里获取实例或者实现类
     *
     * @param fieldClass     实例中属性的类型
     * @param autowiredValue 要注入的值的名称
     * @return
     */
    private Object getFieldInstance(Class<?> fieldClass, String autowiredValue) {
        // 看能否获取同等级的实例
        Object fieldValue = beanContainer.getBean(fieldClass);
        if (fieldValue != null) {
            return fieldValue;
        } else {
            Class<?> implementedClass = geImplementedClass(fieldClass, autowiredValue);
            if (implementedClass != null) {
                return beanContainer.getBean(implementedClass);
            } else {
                return null;
            }
        }
    }

    /**
     * 获取接口i的实现类
     *
     * @param fieldClass 实例中要注入的属性的类型
     * @return
     */
    private Class<?> geImplementedClass(Class<?> fieldClass, String autowiredValue) {

        Set<Class<?>> classSet = beanContainer.getClassesBySuper(fieldClass);
        if (!ValidationUtil.isEmpty(classSet)) {
            if (ValidationUtil.isEmpty(autowiredValue)) {

                if (classSet.size() == 1) {
                    return classSet.iterator().next();
                } else {
                    throw new RuntimeException("multiple implemented classes for " + fieldClass.getName() + "please set @Autowired's value to pick one");
                }
            } else {

                for (Class<?> clazz : classSet) {
                    if (autowiredValue.equals(clazz.getSimpleName())) {
                        return clazz;
                    }
                }
            }
        }

        return null;
    }
}

3.2 相关代码讲解如下:

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---05. 实现容器的依赖注入

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---05. 实现容器的依赖注入

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---05. 实现容器的依赖注入

从零写一个具有IOC-AOP-MVC功能的框架---学习笔记---05. 实现容器的依赖注入

GitHub地址: https://github.com/wuyiccc/he…

原文 

https://segmentfault.com/a/1190000023206860

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » 从零写一个具有IOC-AOP-MVC功能的框架—学习笔记—05. 实现容器的依赖注入

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址