模拟Spring 的bean工厂模式与自动装配

使用过Spring框架进行开发的朋友都知道,Spring实例化各种JavaBean,可以通过基于配置文件的方式也可以通过基于注解的方式,让Spring帮我们实例化对应的Bean。

org.springframework.beans.factory.BeanFactory 是Spring IoC容器的实际代表者,IoC容器负责容纳此前所描述的bean,并对bean进行管理。

在Spring中,BeanFactory是IoC容器的核心接口。 它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

Spring为我们提供了许多易用的BeanFactory实现, XmlBeanFactory就是最常用的一个。该实现将以XML方式描述组成应用的对象 以及对象间的依赖关系。XmlBeanFactory类将获取此XML配 置元数据,并用它来构建一个完全可配置的系统或应用。
这里写图片描述

从上图可以看到,Spring IoC容器将读取配置元数据; 并通过它对应用中各个对象进行实例化、配置以及组装。通常情况下我们使用简单直观 的XML来作为配置元数据的描述格式。在XML配置元数据中我们可以对那些我们希望通过 Spring IoC容器管理的bean进行定义。
Spring读取配置文件是用反射机制读的jvm的.class文件(采用classLoader调用类似的方法),用这种方法能取消类对象的创建与取出,依靠bean工厂就可以实现。

这里采用dom4j/jdom方式模拟Spring的工作原理。

查看Spring的API可以知道,Spring生产Bean的工厂为BeanFactory,所以我们首先创建一个模拟Spring的Bean工厂的BeanFactory接口:
1.BeanFactory接口

public interface BeanFactory {
    public Object getBean(String name);
}

基于读取配置文件来实例化JavaBean,那自然少不了配置文件。这里自定义为beans.xml,没有用默认的applicationContext.xml命名。
2.beans.xml文件

<beans>
    <bean id="u" class="com.dao.impl.UserDaoImpl"></bean>
    <bean id="userService" class="com.service.UserService">
        <property name="UserDao" bean="u"></property>
    </bean>
</beans>

property标签可以实现bean的自动装配,依据bean的id将属性注入。property指set方法,即UserService中有个方法setUserDao(),而该方法调用时应该将id名为“u”的bean传进来。
具体的实现方法是:

UserService service = (UserService) factory.getBean(“userService”);
UserDao dao = (UserDao) factory.getBean(“u”);

测试类从工厂里取出

Spring需要知道开发者写的是哪个配置文件,所以需要ClassPathXmlApplicationContext来读取配置文件,这里同样对ClassPathXmlApplicationContext进行模拟。
3.ClassPathXmlApplicationContext 类

//模拟Spring的ClassPathXmlApplicationContext,它实现了BeanFactory接口
public class ClassPathXmlApplicationContext implements BeanFactory{

    //模拟Spring装载bean实例的容器  
    private Map<String,Object> beans = new HashMap<String,Object>();

    public ClassPathXmlApplicationContext() throws Exception{
        //创建SAXBuilder组建器  
        SAXBuilder sb = new SAXBuilder();
        //加载配置文件 
        Document doc = sb.build(this.getClass().getClassLoader().getResourceAsStream("beans.xml"));
        //解析配置文件
        Element root = doc.getRootElement();
        List list = root.getChildren("bean");
        //遍历文件各个bean节点
        for(int i=0;i<list.size();i++){
            Element element = (Element) list.get(i);
            String id = element.getAttributeValue("id");
            String clazz = element.getAttributeValue("class");
            System.out.println(id+":"+clazz);
            //根据类路径clazz创建该类的对象,实例化bean
            Object o = Class.forName(clazz).newInstance();
            //将实例化好的bean存入容器(map)中
            beans.put(id, o);

            //遍历每个bean下的property节点
            for(Element propertyElement:(List<Element>)element.getChildren("property")){
                String name = propertyElement.getAttributeValue("name");
                String bean = propertyElement.getAttributeValue("bean");
                根据property节点的bean名称,从容器map中取出实例化的bean
                Object beanObject = beans.get(bean);
                //取得name值对应的set方法
                String methodName = "set"+name.substring(0, 1).toUpperCase()+name.substring(1);
                System.out.println("method name="+methodName);
                /**
                *  获取set方法所属的类所实现的接口数组。o为主bean,beanObject为需要装配的bean
                *  beanObject对象为UserDaoImpl对象,获取其接口数组的第一个值(这里只实现了UserDao接口)
                */
                Method m = o.getClass().getMethod(methodName,beanObject.getClass().getInterfaces()[0]);
                m.invoke(o, beanObject);
        }
        }
    }

    @Override
    public Object getBean(String name) {
        return beans.get(name);
    }

}

4.建立测试类
BeanFactory factory = new ClassPathXmlApplicationContext(“beans.xml”);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值