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

来源:互联网 发布:iso9001 软件开发 编辑:程序博客网 时间:2024/06/07 11:18

使用过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 0
原创粉丝点击