从零开始实现spring(一)最简单的IOC

本文介绍了如何手动实现Spring框架中的IOC容器核心功能,包括通过反射创建对象实例及属性注入过程。作者逐步解析了BeanDefinition、PropertyValue和PropertyValues类的设计原理,并提供了一个简单的Bean工厂实现。

        本文源码可至码云查阅(https://gitee.com/wondersWX/myspring),我也还在一步步构建中,欢迎fork,欢迎star!

        自打开始JavaWeb编程以来,从最初的jsp+servelt,到SSH框架,更行技术框架SSM框架,实现分布式架构,进行前后分离,接触到的框架技术可以说数不胜数,但从没能离开的就是spring,最开始的时候只是将spring用作对象容器,做框架整合,事务管理,然后慢慢从struts过渡到springmvc,使用spring进行view层的控制,再后来,使用spring-boot,有直接打包好的视图层、和jpa、mybatise实体层,到现在使用spring-clouder实现微服务,通过路由加nigix实现前后分离架构。最近在一个微信群中,看到群友分享的一个面试题,如果不能使用spring,你会怎么编程?发现自己看到这个问题着实愣了一下,的确使用spring已成了习惯,没想过缺少了这个框架该怎么办。其实使用了spring这么久,spring两大基础特性ioc(控制反转),aop(面向切面)两大特性可以说是十分熟悉了,自己对该如何实现这两大特性也有一定的思路,那还等什么,自己来尝试实现一下吧!

        那么就从大家最熟悉的开始,对于applicationContext.xml文件中bean的配置可以说用过spring的人没有不熟悉的,那么其本质是什么呢?简单说,就是从xml文件中读取到bean的定义,spring的bean工厂基于此定义进行bean的创建和装配,然后你就能轻松通过getBean()方法获取到实例化的对象,再进一步抽象,就是将一段字符串转化为一个对象实例,熟悉反射的人可能就能想到了,这不挺像类的反射嘛,给出类路径获取Class,再使用newInstance获取对象。没错spring的对象创建就是大量使用了反射的方式。好了说了这么多我们就来尝试自己实现一个最简单的IOC吧!

        spring的BeanFactory在创建对象时并不是直接读取xml文件中的配置,而是对bean的定义进行了封装也就是BeanDefinition

package com.fxx.bean;

public class BeanDefiniton {
    private String beanClassName;
    private Class beanClass;
    //bean的创建与装载应由工厂完成,beanDefinition只维护此属性,不提供创建bean的方法
    private Object bean;
    private PropertyValues pvs;

    public String getBeanClassName() {
        return beanClassName;
    }

    public void setBeanClassName(String beanClassName) {
        this.beanClassName = beanClassName;
        //一般通过class反射创建实例,但ioc目的是通过修改字符串达到调整实例的目标故在设定classname的同时,修改beanClass属性
        try {
            this.beanClass = Class.forName(beanClassName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class beanClass) {
        this.beanClass = beanClass;
    }

    public Object getBean() {
        return bean;
    }

    public void setBean(Object bean) {
        this.bean = bean;
    }

    public PropertyValues getPvs() {
        return pvs;
    }

    public void setPvs(PropertyValues pvs) {
        this.pvs = pvs;
    }
}
    只是通过反射创建对象还不够,我们当然想要给对象进行属性注入,spring对属性配置也进行了封装
package com.fxx.bean;

public class PropertyValue {
    private final String name;
    private final Object value;
    //对象属性属于不可改变的时候,可将其设置为final,在构造器中赋值,并不提供set方法(提供也没用)
    public  PropertyValue(String name,Object value){
        this.name=name;
        this.value=value;
    }

    public String getName() {
        return name;
    }

    public Object getValue() {
        return value;
    }
}
存在多个属性注入,首相想到的是应该是使用list将propertyvalue管理起来,事实上spring也是这么做的,但是为了更灵活的属性注入,提供属性注入前后的操作,那么我们最熟悉的代理设计模式就可以用上了
package com.fxx.bean;

import java.util.ArrayList;
import java.util.List;

/**
 * 用于载入属性前判断
 */
public class PropertyValues {
    private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();

    public void addValue(PropertyValue pv){
        //此处进行注入前操作
        propertyValueList.add(pv);
    }

    public List<PropertyValue> getPropertyValueList() {
        return propertyValueList;
    }
}

好了有了beanDfiniton,现在只要将其注册到工厂中,就可以获取到对象了,我们来创建一个最简单的对象工厂,使用map来管理beanDfiniton,通过对象name获取对象,代码如下
package com.fxx.bean.factory;

import com.fxx.bean.BeanDefiniton;

public interface BeanFactory {

    Object getBean(String name) throws Exception;
    void registBeanDefinition(String name, BeanDefiniton beanDefiniton);
}

package com.fxx.bean.factory;

import com.fxx.bean.BeanDefiniton;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public abstract class AbstractBeanFactory implements BeanFactory{
    private final Map<String,BeanDefiniton> beanDefinitonMap = new ConcurrentHashMap<String, BeanDefiniton>();

    public Object getBean(String name) throws Exception {
        if(!beanDefinitonMap.containsKey(name)||beanDefinitonMap.get(name)==null){
            throw new Exception("对象定义不存在!");
        }
        return beanDefinitonMap.get(name).getBean();
    }

    /**
     * 注册同时创建bean并装载,将bean的创建与装载相分离,创建的方式由子类实现(bean的创建有多种类型的需求)
     * @param name
     * @param beanDefiniton
     */
    public void registBeanDefinition(String name, BeanDefiniton beanDefiniton){
        if(beanDefiniton==null){
            return;
        }
        Object bean = null;
        try {
            bean = creatBean(beanDefiniton);
        } catch (Exception e) {
            e.printStackTrace();
        }
        beanDefiniton.setBean(bean);
        beanDefinitonMap.put(name,beanDefiniton);
    }

    protected abstract Object creatBean(BeanDefiniton beanDefiniton) throws Exception;
}

package com.fxx.bean.factory;

import com.fxx.bean.BeanDefiniton;
import com.fxx.bean.PropertyValue;
import com.fxx.bean.PropertyValues;

import java.lang.reflect.Field;

public class AutoWiredBeanFactory extends AbstractBeanFactory{

    /**
     * 实现实例创建以及属性装载
     * @param beanDefiniton
     * @return
     */
    @Override
    protected Object creatBean(BeanDefiniton beanDefiniton)  throws Exception{
        return doCreatBean(beanDefiniton);
    }

   private Object doCreatBean(BeanDefiniton beanDefiniton) throws Exception{
       Object bean = beanDefiniton.getBeanClass().newInstance();
       setPropertyValues(bean,beanDefiniton.getPvs());
       return bean;
   }

   private void setPropertyValues(Object bean,PropertyValues pvs) throws Exception {
        if(pvs.getPropertyValueList().size()==0){
            return;
        }
        for (PropertyValue pv : pvs.getPropertyValueList()){
            Field declaredField = bean.getClass().getDeclaredField(pv.getName());
            declaredField.setAccessible(true);
            declaredField.set(bean,pv.getValue());
        }
   }
}


        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值