自己模拟实现spring ioc原理

JSON配置文件的数据结构:

package light.zhang.ioc.bean;

import java.io.Serializable;
import java.util.List;

import lombok.Data;
import lombok.ToString;

/**
 * 数据结构
 * @author witts 
 */
@Data
@ToString
public class Beandefinition implements Serializable{ 
    /**
     * 序列ID
     */
    private static final long serialVersionUID = -1723354830429118453L;
    
    /**BeanName参数**/
    private String beanName;
    
    private String className;
    
    private String interfaceName;
    
    private List<ConstructorArg> ConstructorArgs;
    
    private List<PropertyArg> PropertyArgs;
}

参数注入类:

package light.zhang.ioc.bean;

import java.io.Serializable;

import lombok.Data;

@Data
public class ConstructorArg implements Serializable {
 
    private static final long serialVersionUID = -1094744504486782050L;
    
    private String ref;
}
package light.zhang.ioc.bean;

import java.io.Serializable;

public class PropertyArg implements Serializable {
 
    private static final long serialVersionUID = 4398781604716858284L;

}

读取json配置文件:

package light.zhang.ioc.client;

import java.io.InputStream;
import java.util.List;

import com.fasterxml.jackson.core.type.TypeReference;

import light.zhang.ioc.bean.Beandefinition;
import light.zhang.ioc.core.ApplicationContextFactory;
import light.zhang.ioc.utils.JsonUtils; 

/**
 * 通过json格式的方式来存储注册信息,然后让IOC容器管理对象
 * @author witts 
 */
public class JsonApplicationContext extends  ApplicationContextFactory {  
    private String fileName; 
    
    public JsonApplicationContext(String fileName) {
        this.fileName = fileName; 
        initFile();
    }   
    
    private void initFile(){//读取文件,并注册到容器
        InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);//读取配置文件信息
        List<Beandefinition> beanDefinitions = JsonUtils.readValue(is,new TypeReference<List<Beandefinition>>(){});  
        if(beanDefinitions != null && !beanDefinitions.isEmpty()) {
            for (Beandefinition beanDefinition : beanDefinitions) { 
                registerBean(beanDefinition.getBeanName(), beanDefinition);//注册
            }
        }
    } 
}

 通过名称得到bean:

package light.zhang.ioc.core;

import light.zhang.ioc.exception.CreateBeanException;
import light.zhang.ioc.exception.LoadBeanException;

public interface ApplicationContext {
    /**
     * 通过bean获取到注册的实例信息
     * @param name
     * @throws Exception
     * @throws LoadBeanException 
     * @throws CreateBeanException 
     */
    public Object getBean(String name) throws IllegalAccessException; 
    
}

负责bean生命周期管理,加载-实例-注册-销毁等

package light.zhang.ioc.core;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import light.zhang.ioc.bean.Beandefinition;
import light.zhang.ioc.bean.ConstructorArg;
import light.zhang.ioc.exception.CreateBeanException;
import light.zhang.ioc.exception.LoadBeanException;
import light.zhang.ioc.utils.BeanUtils;
import light.zhang.ioc.utils.ClassLoaderUtils;
import light.zhang.ioc.utils.ReflectionUtils;

/**
 * 主要负责对加载到Map里面的对象取舍 beanDefineMap 存储的是对象的名称和对象对应的数据结构的映射。bean 用于保存
 * beanName和实例化之后的对象。 容器初始化的时候,会调用 BeanRegisterFactoryImpl.registerBean 方法。把
 * 对象的 Beandefinition 数据结构,存储起来 当我们调用 getBean() 的方法的时候。会先到 beanMap
 * 里面查找,有没有实例化好的对象。如果没有, 就会去beanDefineMap查找这个对象对应的
 * BeanDefination。再利用DeanDefination去实例化一个对象。 对象实例化成功以后,我们还需要注入相应的参数,调用
 * populatebean()这个方法。在 populateBean 这个方法中, 会扫描对象里面的Field,如果对象中的 Field
 * 是我们IoC容器管理的对象,那就会调用 我们上文实现的 ReflectionUtils.injectField来注入对象。
 * 一切准备妥当之后,我们对象就完成了整个 IoC 流程。最后这个对象放入 beanMap 中,方便下一次使用。 所以我们可以知道 BeanFactory 是管理和生成对象的地方。
 */
public class ApplicationContextFactory  implements ApplicationContext {
        
    private static final Logger logger=LoggerFactory.getLogger(ApplicationContextFactory.class);

    private static final ConcurrentHashMap<String, Object> beanMap = new ConcurrentHashMap<String, Object>();

    private static final ConcurrentHashMap<String, Beandefinition> undefineMap = new ConcurrentHashMap<String, Beandefinition>();

    private static final Set<Object> beanNameSet = Collections.synchronizedSet(new HashSet<Object>());// 同步的hash set

    @Override
    public Object getBean(String name) throws IllegalAccessException {
        Object bean = null;
        bean = beanMap.get(name);// 在已经注册过的情况下通过名称获取注册的实例
        if (null != bean) {
            return bean;
        }
        bean = createBean(undefineMap.get(name)); // 如果没有实例化,那就需要调用createBean来创建对象,第一次加载的情况
        if (bean != null) {
            // 对象创建成功以后,注入对象需要的参数 
                populatebean(bean);
                // 再把对象存入Map中方便下次使用。
                beanMap.put(name, bean); 
        }
        // 结束返回
        logger.debug("This "+name+" is managed by ioc!!!");
        return bean;
    }

    /**
     * 注册bean到IOC容器里面
     * 
     * @param name
     * @param bean
     */
    protected void registerBean(String name, Beandefinition bean) {
        undefineMap.put(name, bean);// 先注册
        beanNameSet.add(name);// 添加注册信息
    }

    /**
     * 主要负责对参数的初始化
     * 
     * @param bean
     * @throws IllegalAccessException 
     * @throws Exception
     * @throws LoadBeanException 
     * @throws CreateBeanException  
     */
    private void populatebean(Object bean) throws IllegalAccessException   {
        Field[] fields = bean.getClass().getSuperclass().getDeclaredFields();// 获取的代理对象信息
        if (fields != null && fields.length > 0) {// 存在代理对象
            for (Field field : fields) {
                String beanName = field.getName();
                beanName = StringUtils.uncapitalize(beanName);// beanName字符串的第一个字符,转换为小写
                if (beanNameSet.contains(field.getName())) {// 当包从IOC容器检测到注册信息之后
                    Object fieldBean = getBean(beanName);// 获取实例
                    if (fieldBean != null) {
                        ReflectionUtils.initParamter(field, bean, fieldBean);// 初始化参数信息
                    }
                }
            }
        }
    }

    /**
     * 创建bean实例
     * 
     * @param beanDefinition
     * @return
     * @throws IllegalAccessException 
     * @throws LoadBeanException 
     * @throws Exception
     */
    private Object createBean(Beandefinition beanDefinition) throws IllegalAccessException  {
        if(null == beanDefinition) {
            try {
                throw new CreateBeanException();
            } catch (CreateBeanException e) { 
                e.printStackTrace();
            }
        }
        String beanName = beanDefinition.getClassName();
        Class<?> classInfo = ClassLoaderUtils.loaderClass(beanName);
        if (classInfo == null) {
            try {
                throw new LoadBeanException();
            } catch (LoadBeanException e) { 
                e.printStackTrace();
            }
        }
        List<ConstructorArg> constructorArgs = beanDefinition.getConstructorArgs();// 获取参数列表
        if (constructorArgs != null && !constructorArgs.isEmpty()) {
            List<Object> objects = new ArrayList<Object>();
            for (ConstructorArg constructorArg : constructorArgs) {
                objects.add(getBean(constructorArg.getRef()));// ref引用信息
            }
            try {
                return BeanUtils.instanceCreate(classInfo, classInfo.getConstructor(), objects.toArray());// 有参数的注入
            } catch (NoSuchMethodException e) { 
                e.printStackTrace();
            } catch (SecurityException e) { 
                e.printStackTrace();
            }
        } else {
            return BeanUtils.instanceCreate(classInfo, null, null);// 没有参数
        }
        return null;
    } 

}

创建对象时异常

package light.zhang.ioc.exception;
 
/**
 * 创建时异常
 * @author witts
 *
 */
public class CreateBeanException extends Throwable { 
    
    private static final long serialVersionUID = 1L;
    
    public CreateBeanException() { 
        super("create bean fail,bean name is not found!!!");
    }
     /**
      * 创建bean异常
      * @param exc
      */
    public CreateBeanException(String exc) { 
        super(exc);
    }
}

加载bean异常

package light.zhang.ioc.exception;

/**
 * 加载时异常
 * @author witts 
 */
public class LoadBeanException extends Throwable{ 
    
    private static final long serialVersionUID = 8520827571307312752L;
    
    @Override
    public synchronized Throwable fillInStackTrace() { 
        return super.fillInStackTrace();
    }
    
    public LoadBeanException() {
        super("load bean exception,bean not found!!!");
    }
    
    public LoadBeanException(String message) {
        super(message);
    }
}

bean工具类:

package light.zhang.ioc.utils;

import java.lang.reflect.Constructor;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;

/**
 * 主要负责处理对BEAN的管理,BEAN的初创建,始化,状态管理
 * @author witts 
 */
public class BeanUtils {
    /**
     * 动态代理,并创建类
     * @param clas
     * @param constructor
     * @param args
     * @return
     */
    public static Object instanceCreate(Class<?> clas,Constructor<?> constructor,Object[] args) {
        /**
         * Enhancer允许为非接口类型创建一个Java代理。Enhancer动态创建了给定类型的子类但是拦截了所有的方法。和Proxy不一样的是,不管是接口还是类他都能正常工作
         */
        Enhancer enhancer=new Enhancer(); 
        enhancer.setSuperclass(clas);//代理类
        enhancer.setCallback(NoOp.INSTANCE);//代理类型>初始化实例
        if(null == constructor) {
            return enhancer.create();//默认创建无参数实例
        }else {
            return enhancer.create(constructor.getParameterTypes(),args);//带参数的初始化
        } 
    }
}

类装载工具类:

package light.zhang.ioc.utils;

 /**
  * 主要负责读取配置文件,装载类信息
  * @author witts
  *
  */
public class ClassLoaderUtils {
    /**创建读取配置信息的对象**/
    public static ClassLoader install() {
        return Thread.currentThread().getContextClassLoader();
    }
    /**装载class**/
    public static Class<?> loaderClass(String className) {
        try {
            return install().loadClass(className);//通过配置文件装载类信息
        }catch (ClassNotFoundException e) { 
            e.printStackTrace();
        }
        return null;
    } 
}

json工具类:

package light.zhang.ioc.utils;
 

import java.io.InputStream;
import java.text.SimpleDateFormat;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

public class JsonUtils {

    private static final ObjectMapper mapper = new ObjectMapper();

    private JsonUtils() {
    }

    public static ObjectMapper getObjectMapper() {
        return mapper;
    }

    public static <T> T readValue(String json, Class<T> cls) {
        try {
            return mapper.readValue(json, cls);
        } catch (Exception var3) {
            return null;
        }
    }

    public static <T> T readValue(InputStream is,Class<T> cls){
        try{
            return mapper.readValue(is,cls);
        }catch (Exception e){
            return null;
        }
    }

    public static <T> T readValue(byte[] bytes, Class<T> cls) {
        try {
            return mapper.readValue(bytes, cls);
        } catch (Exception var3) {
            return null;
        }
    }

    public static <T> T readValue(String json, TypeReference<?> valueTypeRef) {
        try {
            return mapper.readValue(json, valueTypeRef);
        } catch (Exception var3) {
            return null;
        }
    }

    public static <T> T readValue(byte[] bytes, TypeReference<?> valueTypeRef) {
        try {
            return mapper.readValue(bytes, valueTypeRef);
        } catch (Exception var3) {
            return null;
        }
    }

    public static <T> T readValue(InputStream is,TypeReference<?> valueTypeRef){
        try{
            return mapper.readValue(is,valueTypeRef);
        }catch (Exception e){
            return null;
        }
    }
    public static String writeValue(Object entity) {
        try {
            return mapper.writeValueAsString(entity);
        } catch (Exception var2) {
            return null;
        }
    }

    public static byte[] writeByteValue(Object entity) {
        try {
            return mapper.writeValueAsBytes(entity);
        } catch (Exception var2) {
            return null;
        }
    }

    static {
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        mapper.setSerializationInclusion(JsonInclude.Include.USE_DEFAULTS);
        mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
        mapper.getDeserializationConfig().withoutFeatures(new DeserializationFeature[]{DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES});
        mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, true);
        mapper.configure(MapperFeature.ALLOW_EXPLICIT_PROPERTY_RENAMING,true);
        mapper.configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, true); 
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

}

反射类:

package light.zhang.ioc.utils;

import java.lang.reflect.Field;

/**
 * 主要通过 Java 的反射原理来完成对象的信息注入
 * @author witts
 */
public class ReflectionUtils {
        /**
         * 初始化参数信息
         * @param field
         * @param key
         * @param val
         * @throws IllegalAccessException
         */
        public static void initParamter(Field field,Object key,Object val) throws IllegalAccessException {
            if(null !=field) {
                field.setAccessible(Boolean.TRUE);
                field.set(key, val);//注入参数信息
            }
        }
}

客户端调用

package light.zhang.ioc.test;

import junit.framework.TestCase;
import light.zhang.ioc.client.JsonApplicationContext;
import light.zhang.ioc.core.ApplicationContext;
 
/**
 * 模拟spring ioc对象创建管理销毁
 * @author witts
 *
 */
public class AppTest extends TestCase {
    
     private static final ApplicationContext applicationContext=new JsonApplicationContext("application.json"); //读取配置文件
     
     public static void main(String[] args)   { 
        try { 
            Robot aiRobot; aiRobot =  (Robot) applicationContext.getBean("robot");//获取对象
            aiRobot.show();//调用对象功能
        } catch (Exception e) { 
            e.printStackTrace();
        }  
    }
}

需要被管理的对象

package light.zhang.ioc.test;

public class Hand {
    public void waveHand(){
        System.out.println("hand out message");
    }
}
package light.zhang.ioc.test;

public class Mouth {
    public void speak(){
        System.out.println("Mouth out message");
    }
}
package light.zhang.ioc.test;
 
public class Robot {
     //需要注入 hand 和 mouth,容器自动注入对象并实例化
    private Hand hand;
    private Mouth mouth;
    
    public void show(){
        hand.waveHand();
        mouth.speak();
    }
}

主要是理解spring ioc的加载-实例-注册-销毁等一系列的对象生命周期管理,我这里只是模仿一下spring对对象的加载,创建,注册 对象销毁是个复杂的过程,并不是那么容器就模拟出来的,

spring管理的对象方式有很多种,

本来是由应用程序管理的对象之间的依赖关系,现在交给容器管理,这就是控制反转,及交给Ioc容器。Spring的IoC主要使用DI方式实现,

不需要主动查找,对象的查找、定位和创建全部由容器管理。spring中有三种注入方式,一种是set注入,一种是接口注入,另一种是构造方法注入

 

posted @ 2018-01-31 10:19  light-zhang  阅读(2011)  评论(1编辑  收藏  举报