从零开始写javaweb框架笔记15-搭建轻量级JAVAWEB框架-实现依赖注入功能

本文介绍如何使用@Inject注解实现IoC容器,通过反射机制自动装配Service成员变量,并提供相关工具类代码。

        我们在Controller中定义了Service成员变量,然后在Controller的Action方法中调用Service成员变量的方法,那么如果实现Service的成员变量?

      之前定义了@Inject注解,就用它来实现Service是例话,那么谁来实例化呢。

      不是开发者通过new的方式来实例化,而是通过框架自身来实例化,像这类实例化过程称为IOC(控制反转),控制不是由开发者来决定,而是反转给框架了。一般也将控制反转称为DI(依赖注入),可以理解为将某个类需要依赖的成员注入到这个类中,那么我们该如何实现了?

      最简单的方式是,先通过BeanHelper获取所有的BeanMap(是一个Map<Class<?>,Object>结构,记录了类与对象的映射关系),然后遍历这个映射关系,分别取出Bean类与Bean实例,进而通过反射获取类中所有成员变量。继续遍历这些成员变量,在循环中判断这些成员变量是否带有Inject注解,若带有该注解,则从BeanMap根据Bean类取出Bean实例。最后通过ReflectionUtil的setField的方法来修改当前成员变量的值。

     把上面的逻辑写成一个IocHelper的类,让它来完成这件事,代码如下:

    

package org.smart4j.framework.helper;


import org.smart4j.framework.annotation.Inject;
import org.smart4j.framework.org.smart4j.framework.util.ArrayUtil;
import org.smart4j.framework.org.smart4j.framework.util.CollectionUtil;
import org.smart4j.framework.org.smart4j.framework.util.ReflectionUtil;

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

/**
 * Created by jack on 2017/5/23.
 * 依赖注入助手类
 */
public class IocHelper {
    static {
        //获取所有的Bean类与Bean实例之间的关系(简称Bean Map)
        Map<Class<?>, Object> beanMap = BeanHelper.getBeanMap();
        if (CollectionUtil.isNotEmpty(beanMap)) {
            //遍历beanMap
            for (Map.Entry<Class<?>, Object> beanEntry : beanMap.entrySet()) {
                //从beanMap中获取bean类与bean实例
                Class<?> beanClass = beanEntry.getKey();
                Object beanInstance = beanEntry.getValue();
                //获取Bean类定义的所有成员变量(简称Bean Field)
                Field [] beanFields = beanClass.getDeclaredFields();
                if (ArrayUtil.isNotEmpty(beanFields)){
                    //遍历beanField
                    for (Field beanField : beanFields) {
                        //判断当前的Bean Field是否带有Inject注解
                        if (beanField.isAnnotationPresent(Inject.class)){
                            //在Bean Map中获取Bean Field对应的实例
                            Class<?> beanFieldClass = beanField.getType();
                            Object beanFieldInstance = beanMap.get(beanFieldClass);
                            if (beanFieldInstance != null){
                                //通过放射初始化beanField值
                                ReflectionUtil.setField(beanInstance,beanField,beanFieldInstance);
                            }
                        }
                    }
                }


            }
        }
    }
}


     只需在IocHelper的静态代码库中实现相关逻辑,就能完成IOC容器的初始化工作。这么这个代码块在上面时候进行加载了?

    其实IocHelper类加载的时候就会加载这个代码块,后面需要找一个统一的地方来加载IocHelper。

   上面的代码涉及了CollectionUtil(对集合的封装工具类),ArrayUtil(对数组的封装工具类)工具类

 

   CollecionUtil的代码如下:

package org.smart4j.framework.org.smart4j.framework.util;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;

import java.util.Collection;
import java.util.Map;

/**
 * Created by jack on 2017/5/23.
 * 集合工具类
 */
public class CollectionUtil {
    /**
     * 判断Collection是否为空
     */
    public static boolean isEmpty(Collection<?> collection){
        return CollectionUtils.isEmpty(collection);
    }
    /**
     *判断Collection是否非空
     */
    public static boolean isNotEmpty(Collection<?> collection){
        return !isEmpty(collection);
    }
    /**
     * 判断Map是否为空
     */
    public static boolean isEmpty(Map<?,?> map){
        return MapUtils.isEmpty(map);
    }
    /**
     * 判断Map是否非空
     */
    public static boolean isNotEmpty(Map<?,?> map){
        return !isEmpty(map);
    }
}


ArrayUtil的代码如下:

     

package org.smart4j.framework.org.smart4j.framework.util;

import org.apache.commons.lang3.ArrayUtils;

/**
 * Created by jack on 2017/5/23.
 * 数组工具类
 */
public class ArrayUtil {
    /**
     * 判断数组是否非空
     */
    public static boolean isNotEmpty(Object[] array) {
        return !ArrayUtils.isEmpty(array);
    }

    /**
     * 判断数组是否为空
     */
    public static boolean isEmpty(Object[] array) {
        return ArrayUtils.isEmpty(array);
    }
}

     可见一个简单的IOC框架十几行代码就搞定了,似乎比想象的简单。需要注意的是,此时在Ioc框架中管理的Bean都是单例的,由于Ioc框架底层还是从BeanHelper获取Bean Map的,而Bean Map中的对象都是事先创建好并放入这个bean容器的,所有的对象都是单例的。

    下面在给出一个StringUtil,字符串集合工具类的代码:

   

package org.smart4j.framework.org.smart4j.framework.util;

import org.apache.commons.lang3.StringUtils;

/**
 * Created by jack on 2017/5/23.
 * 字符串工具类
 */
public class StringUtil {
    /*
    * 判断字符串是否为空
    * */
    public static boolean isEmpty(String str){
        if(str != null){
            str=str.trim();
        }
        return StringUtils.isEmpty(str);
    }
    /*
    * 判断字符串是否非空
    * */
    public static boolean isNotEmpty(String str){
        return !isEmpty(str);
    }
}

     此时框架代码地址:框架代码地址



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值