简单模拟SpringIOC工作机制流程开发

  紧接上一篇文章《轻松了解Spring中的控制反转和依赖注入》讲解了SpringIOC和DI的基本概念,这篇文章我们模拟一下SpringIOC的工作机制,使我们更加深刻的理解其中的工作。再上代码之前我们先来看看几个类的设计目的。 

  BeanFactor接口:在Spring源码中的定义是:持有对一定数量的Bean的定义,同时每个Bean都被唯一标识的对象(类),需要实现这个接口。根据对Bean的定义,该工厂将会返回一个包含Bean定义的对象的独立实例(原型设计模式),或者单例共享(一个不错的单例设计模式,)范围是整个工厂的范围(也可以理解成是整个容器下),返回哪种类型的实例依赖于Bean工厂的配置:API是相同的。因为Spring2.0中扩大了依赖范围,可以根据具体应用上下问(如在Web环境中的请求和会话),BeanFactory是应用程序组件的中央注册中心和集中配置。简单的来说该接口定义了获取Bean的方法,由子类去实现。

  BeanFactory接口:是实现BeanFactory接口的抽象基类。实现获取Bean定义的方法。

  XmlContext类:继承了AbstractBeanFactory抽象类,进行Bean的注册和注册XML的读取器。

  BeanInfo类:进行存储Bean的信息。

  接下来上代码,需要注释的地方我都添加上去了,类的目录如下。

    

  类之间的结构图如下

  以下是代码

  

package ioc.factory;

/**
 * Created by zzf on 2016/10/26.
 */
public interface BeanFactory {
    /**
     * 根据对象的ID标识获取对象实例
     * @param name
     * @return
     */
    Object getBean(String name);
}
package ioc.factory;

import ioc.info.BeanInfo;
import ioc.reader.SourceReader;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * Created by zzf on 2016/10/26.
 *
 * 最顶层的IOC实现
 * 该类负责从注册器中取出注册对象
 * 实现从对象描述信息转换为对象实例的过程
 * 实现根据名称获取对象的方法
 *
 */
public abstract class AbstractBeanFactory implements BeanFactory {
    private  String filePath;
    private Map<String,BeanInfo> container;
    protected SourceReader reader;
    public AbstractBeanFactory(String filePath){
        this.filePath=filePath;
        setReader(reader);
    }

    /**
     * 由子类决定如果使用什么样的注册读取器
     * 这里使用了模板方法,父类定义抽象方法,但交给子类自由去设计方法内容
     * @param reader
     */
    protected abstract void setReader(SourceReader reader);

    //注册bean
    public void registerBeans(){
        this.container=this.reader.loadBeans(filePath);
    }

    @Override
    public Object getBean(String name) {
        BeanInfo beanInfo=this.container.get(name);
        if(beanInfo==null){

            return null;

        }else {
            return this.parseBean(beanInfo);
        }

    }

    /**
     * 解析生成并生成对象实例
     * 主要通过反射完成
     * 根据类名,加载指定类,并取得该类的Class对象
     * 使用Class对象实例化该类,获取一个对象。
     * 逐个设置对象字段的值,这里采用setter Method方式
     *
     * @param beanInfo 指定对象的描述信息
     * @return
     */
    protected  Object parseBean(BeanInfo beanInfo){
        Class clazz;
        try {
            //加载Bean的实例
            clazz=Class.forName(beanInfo.getType());
            Object bean=clazz.newInstance();

            //获取该对象下的所有方法,包括私有
            Method[] methods=clazz.getDeclaredMethods();

            for (String property:beanInfo.getProperties().keySet()){
                String setter="set"+ firstCharToUp(property);
                for(Method method:methods){
                    String methodName=method.getName();

                    if(methodName.equals(setter)){
                        Object value=beanInfo.getProperties().get(property);
                        //使用反射调用set方法
                        method.invoke(bean,value);
                    }
                }
            }
            return bean;

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
            return null;
    }

    private String firstCharToUp(String property) {
        System.out.println(property);
        char [] c=property.toCharArray();
        String first=String.valueOf(c[0]).toUpperCase();
        c[0]=first.charAt(0);
        System.out.println(String.valueOf(c));
        return String.valueOf(c);
    }
}
  

package ioc.context;

import ioc.factory.AbstractBeanFactory;
import ioc.reader.SourceReader;
import ioc.reader.XMLSourceReader;

/**
 * Created by zzf on 2016/10/26.
 * 上下文的构造方法
 * 该方法中指明注册读取器(这里采用的XML,读者可以根据兴趣去实现另外的方式如注解)
 * 并在构造该方法时一次性加载注册的对象
 */
public class XMLContext extends AbstractBeanFactory{

    public XMLContext(String filePath){
        super(filePath);
        this.setReader(new XMLSourceReader());
        super.registerBeans();
    }

    @Override
    protected void setReader(SourceReader reader) {
        super.reader=reader;
    }
}

  

package ioc.reader;

import ioc.info.BeanInfo;

import java.util.Map;

/**
 * Created by zzf on 2016/10/26.
 * 注册读取器接口
 * 负责读取用户注册的对象
 * 继承该接口的类可以实现多种读取方式,如从配置文件中读取,根据标注读取,从网络中读取等等
 */
public interface SourceReader {
    Map<String,BeanInfo> loadBeans(String filePath);
}

  

package ioc.context;

import ioc.factory.AbstractBeanFactory;
import ioc.reader.SourceReader;
import ioc.reader.XMLSourceReader;

/**
 * Created by zzf on 2016/10/26.
 * 上下文的构造方法
 * 该方法中指明注册读取器(这里采用的XML,读者可以根据兴趣去实现另外的方式如注解)
 * 并在构造该方法时一次性加载注册的对象
 */
public class XMLContext extends AbstractBeanFactory{

    public XMLContext(String filePath){
        super(filePath);
        this.setReader(new XMLSourceReader());
        super.registerBeans();
    }

    @Override
    protected void setReader(SourceReader reader) {
        super.reader=reader;
    }
}
package ioc.info;

import java.lang.Object;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by zzf on 2016/10/26.
 */
public class BeanInfo {
    private String id;
    private String type;
    private Map<String,Object> properties=new HashMap<String,Object>();

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Map<String, Object> getProperties() {
        return properties;
    }

    public void setProperties(Map<String, Object> properties) {
        this.properties = properties;
    }
    public void addProperty(String name, Object object)
    {
        this.properties.put(name, object);
    }
}
   

package ioc.reader;

import ioc.info.BeanInfo;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Created by zzf on 2016/10/26.
 * 使用 dom4j进行Xml的读取操作
 */
public class XMLSourceReader implements SourceReader {

    @Override
    public Map<String, BeanInfo> loadBeans(String filePath) {
        //读取指定的配置文件
        SAXReader reader = new SAXReader();
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        //从class目录下获取指定的xml文件
        InputStream ins = classLoader.getResourceAsStream(filePath);
        Document doc = null;
        try {
            doc = reader.read(ins);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        //获得根节点
        Element root = doc.getRootElement();
        Map<String,BeanInfo>beanInfoMap=new HashMap<String, BeanInfo>();
        //遍历bean
        for (Iterator i = root.elementIterator("bean"); i.hasNext();){
            Element element = (Element) i.next();
            //获取bean的属性id和class
            Attribute id = element.attribute("id");
            Attribute cls = element.attribute("class");
            try {
                //利用Java反射机制,通过class的名称获取Class对象
                Class bean=Class.forName(cls.getText());
                //获取对应class的信息
                java.beans.BeanInfo info= Introspector.getBeanInfo(bean);
                //获取其属性描述
                PropertyDescriptor [] propertyDescriptors=info.getPropertyDescriptors();
                Method method;
                Object object=bean.newInstance();
                BeanInfo beanInfo=new BeanInfo();
                for(Iterator iterator=element.elementIterator("property");iterator.hasNext();){
                    Element foo2= (Element) iterator.next();
                    //获取该property的name属性
                    Attribute name = foo2.attribute("name");

                    String value = null;
                    //获取该property的子元素value的值
                    for(Iterator ite1 = foo2.elementIterator("value"); ite1.hasNext();) {
                        Element node = (Element) ite1.next();
                        value = node.getText();
                        break;
                    }
                    System.out.println("name:"+name.getText()+"value"+value);
                for (int j=0;j<propertyDescriptors.length;j++){
                    if(propertyDescriptors[j].getName().equalsIgnoreCase(name.getText())){
                        method=propertyDescriptors[j].getWriteMethod();
                        //利用Java的反射极致调用对象的某个set方法,并将值设置进去
                        method.invoke(object,value);
                        //将获取的对象属性信息存入我们自定义的BeanInfo当中
                        beanInfo.addProperty(name.getText(),value);
                }
                }

                    beanInfo.setId(id.getText());
                    beanInfo.setType(cls.getText());
                    beanInfoMap.put(id.getText(),beanInfo);
                }
                return beanInfoMap;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IntrospectionException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

        return null;
    }
}
时间: 2024-11-05 18:53:05

简单模拟SpringIOC工作机制流程开发的相关文章

Java简单模拟Android中Handler-Message机制

在Android中主线程与子线程的通信十分重要,Google工程师为我们提供了Handler-Message机制来解决他们之间的交互问题.今天,我们就来简单理解Handler-Message机制的原理,在Java中简单模拟该机制.代码示例Github地址HandlerDemo 首先,看一下简单流程图(不太专业) 由上图可知,流程中主要相关类有Handler.Message.MessageQueue.Looper:下面,我们就围绕它们来简单分析该流程图: 1.我们一般在主线程创建Handler,接

Android7.0 Vold 进程工作机制分析之整体流程

Android7.0 Vold 进程工作机制分析之整体流程 一.Vold简介 Vold是Volume Daemon的缩写,负责管理和控制Android平台外部存储设备,包括SD插拨.挂载.卸载.格式化等.它是通过init进程解析init.rc脚本所启动的进程.它处于Native层. 二.基础架构 这里引用Gityuan博客的一张图. SystermServer进程和Vold进程是通过Socket进行通信的,Vold进程和Kernel是通过Netlink 进行通信的,Netlink 是一种特殊的S

工作中敏捷开发流程梳理

接触敏捷开发差不多一年了,对它也有了一些自己浅显的认识,写这篇文章来给自己梳理梳理工作中的敏捷开发流程. 迭代周期 工作中根据项目普遍任务的耗时,采用10个工作日作为1个迭代周期,包括迭代计划会议.迭代开发和迭代回顾会议 迭代任务 迭代任务通常在feature到task的级别,任务主要由以下几个方面来产生:产品功能开发计划.产品功能研究计划.测试提交的上轮迭代未解决的bug和客户反馈的产品问题 1)     开发任务由产品专员在上一轮迭代中确定产品功能点,并产出功能设计文档,由开发在本轮迭代完成

使用回调函数,简单模拟dbutils中Queryrunner的工作原理,并重写Queryrunner,使其使用起来更加简单方便

所谓回调,就是在执行某个程序时,具体的封装处理由第三方类来实现,简单一点说就是记录内部,再出来(由第三方类可以对数据进行处理),再返回去继续执行,这个过程就是回调.想要程序具有记录内部的功能就必须定义一个规范,也就是接口,即你的程序出来被其他类处理了,但你规定了还要返回原程序. 下面看一个简单的例子: /** * @描述:回调函数--记录内部,再出来返回去的过程就叫回调 * @author cxie */ public class CopyOfCallBackDemo { public stat

浏览器是怎样工作的 浏览器从头到尾的工作机制

浏览器是怎样工作的 浏览器从头到尾的工作机制 来源:互联网 作者:佚名 时间:12-12 14:44:10 [大 中 小] 前两天看到一篇不错的英文文章,叫做 How browsers work,该文概要的介绍了浏览器从头到尾的工作机制,包括HTML等的解析,DOM树的生成,节点与CSS的渲染等等,对于想学习浏览器源码的同学来说,实在是很棒的一篇科普文章,于是,我想分节挑重点翻译一下与大家分享 浏览器可以被认为是使用最广泛的软件,本文将介绍浏览器的工 作原理,我们将看到,从你在地址栏输入goog

应届生校招找工作完整流程总结

原文发表自我的个人主页,请看原文,多谢支持 http://purplesword.info/get-job 昨天有同学问我找工作方面的事,感觉有很多疑问,想想有必要把我找工作那段时间学到的东西简单做个总结,供有需要的同学参考. 在找工作之前,和很多同学一样我有很多疑问,比如什么时候找工作这种事都不了解,但是找到工作之后,又忘了当初有哪些疑问.为了让这篇写的完整一点,我特地让一位对找工作不太了解.不愿透漏姓名的.机智的学弟帮忙,把他的疑问全部说出来,然后我汇总进行一个完整的总结.尤其是很多"脑残&

JavaWeb学习总结(四十九)——简单模拟Sping MVC

在Spring MVC中,将一个普通的java类标注上Controller注解之后,再将类中的方法使用RequestMapping注解标注,那么这个普通的java类就够处理Web请求,示例代码如下: 1 /** 2 * 使用Controller注解标注LoginUI类 3 */ 4 @Controller 5 public class LoginUI { 6 7 //使用RequestMapping注解指明forward1方法的访问路径 8 @RequestMapping("LoginUI/Lo

java web学习总结(二十二) -------------------简单模拟SpringMVC

在Spring MVC中,将一个普通的java类标注上Controller注解之后,再将类中的方法使用RequestMapping注解标注,那么这个普通的java类就够处理Web请求,示例代码如下: 1 /** 2 * 使用Controller注解标注LoginUI类 3 */ 4 @Controller 5 public class LoginUI { 6 7 //使用RequestMapping注解指明forward1方法的访问路径 8 @RequestMapping("LoginUI/Lo

malloc 函数工作机制(转)

malloc()工作机制 malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表.调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块.然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节).接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上.调用free函数时,它将用户释放的内存块连接到空闲链上.到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空