简单实现Spring中BeanFactory原理

上一篇文章介绍了Java反射机制在Spring IOC中的应用,知道了BeanFactory底层的实现原理。

Spring的工厂类会帮我们完成配置文件的读取、利用反射机制注入对象等工作,我们可以通过bean的名称获取对应的对象。 

原理搞懂了,对spring IOC理解起来也很容易。

先来看看Java代码获取Spring中Bean的代码(一共有五种方式,这里只展示其中一种方法):


有没有发现上面的代码与利用反射实现工厂模式的代码很相似。对,你没有看错,Spring中的BeanFactory用到的就是简单工厂模式

现在的思路就更加清晰了,要想实现Spring中的BeanFactory,无非就用到了以下几个技术:

        1.使用简单工厂模式来处理bean容器。

        2.解析xml文件,获取配置中的元素信息。

        3.利用反射获实例化配置信息中的对象。

        4.如果有对象注入,使用invoke()方法。

        5.实例化的对象放入bean容器中,并提供getBean方法。

通过以上步骤就实现了spring的BeanFactory功能,只要在配置文件中配置好,实例化对象的事情交给BeanFactory来实现,用户不需要通过new对象的方式实例化对象,直接调用getBean方法即获取对象实例。

具体实现代码:

新建一个xml文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>  
<beans>  
     <bean id="courseDao" class="com.qcjy.learning.Dao.impl.CourseDaoImpl">  
    <bean id="courseService" class="com.qcjy.learning.service.impl.CourseServiceImpl">  
         <!-- 控制调用setCourseDao()方法,将容器中的courseDao bean作为传入参数 -->  
         <property name="courseDao" ref="courseDao"></property>  
    </bean>   
</beans>  
接下来实现BeanFactory工厂,提供init方法,和getBean方法,在init方法中解析xml,利用反射实例话对象,存入bean容器中,代码如下:

import java.beans.BeanInfo;  
import java.beans.PropertyDescriptor;  
import java.io.InputStream;  
import java.lang.reflect.Method;  
import java.util.HashMap;  
import java.util.Iterator;  
import java.util.Map;  
import org.dom4j.Attribute;  
import org.dom4j.Document;  
import org.dom4j.Element;  
import org.dom4j.io.SAXReader;  
[java] view plain copy
public class BeanFactory {  
      //bean容器  
    private Map<String, Object> contianer = new HashMap<String, Object>();  
    /** 
     * <p>Discription:bean工厂的初始化</p> 
     * @param xml xml配置文件路径 
     * @author       : lcma 
     * @update       : 2016年9月20日上午9:04:41 
     */  
    public void init(String xml) {  
        try {  
            // 读取指定的配置文件  
            SAXReader reader = new SAXReader();  
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();  
            // 从class目录下获取指定的xml文件  
            InputStream ins = classLoader.getResourceAsStream(xml);  
            Document doc = reader.read(ins);  
            Element root = doc.getRootElement();  
            Element foo;  
            // 遍历bean  
            for (Iterator i = root.elementIterator("bean"); i.hasNext();) {  
                foo = (Element) i.next();  
                // 获取bean的属性id和class  
                Attribute id = foo.attribute("id");  
                Attribute cls = foo.attribute("class");  
                // 利用Java反射机制,通过class的名称获取Class对象  
                Class<?> bean = Class.forName(cls.getText());  
                // 获取对应class的信息  
                java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean);  
                // 获取其属性描述  
                java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();  
                // 设置值的方法  
                Method mSet = null;  
                // 创建一个对象  
                Object obj = bean.newInstance();  
                // 遍历该bean的property属性  
                for (Iterator ite = foo.elementIterator("property"); ite.hasNext();) {  
                    Element foo2 = (Element) ite.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;  
                    }  
                    for (int k = 0; k < pd.length; k++) {  
                        if (pd[k].getName().equalsIgnoreCase(name.getText())) {  
                            mSet = pd[k].getWriteMethod();  
                            // 利用Java的反射机制调用对象的某个set方法,并将值设进去  
                            mSet.invoke(obj, value);  
                        }  
                    }  
                }  
                // 将对象放入beanMap中,其中key为id值,value为对象  
                contianer.put(id.getText(), obj);  
            }  
        } catch (Exception e) {  
            System.out.println(e.toString());  
        }  
    }    
    /** 
     * <p>Discription:通过bean的id在容器中获取bean对象</p> 
     * @param beanName bean的唯一标识id 
     * @return 
     * @author       : lcma 
     * @update       : 2016年9月20日上午9:05:00 
     */  
    public Object getBean(String beanName) {  
        Object obj = contianer.get(beanName);  
        return obj;  
    }  
}  
测试 方法:
/** 
 * <p>Discription:测试方法</p> 
 * @param args 
 * @author       : lcma 
 * @update       : 2016年9月20日上午9:06:06 
 */  
public static void main(String[] args) {  
       //实例化BeanFactory  
    BeanFactory factory = new BeanFactory();  
    //调用初始化方法,传入xml路径  
    factory.init("spring.xml");  
    //通过bean id 获取对象  
    CourseService courseService = (CourseService) factory.getBean("courseService");  
    //调用对象方法  
    courseService.findAll();  
}  
还要提供CourseService和CourseDao两个接口及实现类,这里就不提供了。

上面的代码已经简单的模拟实现了BeanFactory的功能啦,Spring框架里面的代码要比我们这个复杂的多,因为要考虑到安全性、稳定性、异常等等因素,但是原理都一样。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值