Spring源码学习笔记之一

一,配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
default-lazy-init="false">
<!-- default-lazy-init="true" -->
		<bean id="personDao" class="com.xiva.Person.dao.impl.PersonDaoImpl" 
			lazy-init="false"  scope="prototype" init-method="init"
			destroy-method="destory"></bean>
		<bean id="beanFactory"	class="com.xiva.factory.SpringBeanFactory"/>
		<bean id="person" factory-bean="beanFactory"
			factory-method="createInstance"/>
		<bean id="moduleDao" factory-bean="beanFactory"
			factory-method="createModuleDao"/>
		
</beans>

二,初始化ApplicationContext

ApplicationContext context =
			new ClassPathXmlApplicationContext("services.xml");

 以上信息都可以在spring-framework-reference.pdf中查到;该文件在目录

spring-framework-3.0.4.RELEASE\docs\spring-framework-reference\pdf

scope="prototype",使用destroy-method是无效的。从源码中,我们可以清晰的看到。

context.close();调用了	doClose();其中的destroyBeans();是我们关心的方法。我们关心是如何销毁bean的。在这个方法中看到下面的方法。

protected void destroyBeans() {
		getBeanFactory().destroySingletons();
	}
可见spring的context在close时,只会帮助我们destroySingletons
 

三,控制反转与依赖注入

何为,控制反转;我现在的理解是:将自己的实现,交给外部容器去实现,好像有点套话。说的具体点,又怕说得有些局限性,不过还是具体的说吧,就是指,hibernate或者你的jdbc接口的实现类,交给spring来实现,而我们可以使用xml文件来配置接口的实现类。

<bean id="personDao" class="com.xiva.Person.dao.impl.PersonDaoImpl" 
			lazy-init="false"  scope="prototype" init-method="init"
			destroy-method="destory"></bean>
 

比如上面的配置中,我们可以从spring的context获取到personDao接口的实现类。

   这样我们在service中使用personDao时,我们不需要去实现这个接口,可以从外部注入。同样是依赖于spring的注入。

当然,控制反转和依赖注入的概念也许不是这几句话能说清楚的。

四,AbstractApplicationContext实例化bean

     在web,自认为spring使用servlet的过滤,读取xml文件配置,根据类反射机制来实例化bean。

		AbstractApplicationContext context =
			new ClassPathXmlApplicationContext("services.xml");
		PersonDao personDao = (PersonDao)context.getBean("personDao");
		context.close();

   从上面我们可以看出,初始化时,需要给出xml文件的名称,然后,从初始的context中可以获得这个bean的实例。

下面,我们可以大约的知道,spring通过xml利用反射帮我们实例化类,而我们获取时只需要这个配置id即可。

  从源码我们得知BeanDefinition这个类,就是定义我们的bean的相关属性的一个类。为了简化我们也定义一个相同功能的bean。

package com.xiva.bean;

/**
 * 
 * @author XIVA
 * @Description 用来存储bean相关信息
 */
public class MyBean {
	
	//ID
	private String beanId;
	
	//类名
	private String beanClass;
	
	public MyBean(){
	}
	
	public MyBean(String beanId, String beanClass){
		this.beanId = beanId;
		this.beanClass = beanClass;
	}
	
	public String getBeanId() {
		return beanId;
	}
	public void setBeanId(String beanId) {
		this.beanId = beanId;
	}
	public String getBeanClass() {
		return beanClass;
	}
	public void setBeanClass(String beanClass) {
		this.beanClass = beanClass;
	}
	
	
}
 

有了这个类后,我们就可以在读取xml时,将配置中的id和class属性放入我们上面类的实例中。至于读取xml信息,我们有很多方式,其中包括dom4J,以及DOM、SAX、JDOM。下面我分别采用了dom以及dom4j的方式来实现了读取xml。

首先定义一个抽象类。类似于AbstractApplicationContext。

package com.xiva.mySpring;

public abstract class XivaAbsAppContext {
	public abstract Object getBean(String beanName);
}

dom4j的方式,在apache下载dom4j;在工程中引入dom4j.jar以及相关引用到的包。

package com.xiva.mySpring;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;

import com.xiva.bean.MyBean;

/**
 * 
 * @author XIVA
 * @Description 简化的Spring容器
 */
public class XivaContext extends XivaAbsAppContext{

	private List<MyBean> beanList = new ArrayList<MyBean>();
	
	private Map<String, Object> sigletons = new HashMap<String, Object>();
	
	public XivaContext(String xmlPath){
		this.readXML(xmlPath);
		this.instanceBean();
	}
	
	/**
	 * @Description 解析spring配置文件,初始化bean
	 * @author XIVA
	 * @param fileName
	 */
	@SuppressWarnings("unchecked")
	private void readXML(String fileName){
		SAXReader saxReader = new SAXReader();
		Document document = null;
		try{
			URL xmlPath = this.getClass().getClassLoader().getResource(fileName);
			document = saxReader.read(xmlPath);
			Map<String, String> nsMap = new HashMap<String, String>();
			nsMap.put("ns", "http://www.springframework.org/schema/beans");//加入命名空间
			XPath xsub = document.createXPath("//ns:beans/ns:bean");//
			xsub.setNamespaceURIs(nsMap);//设置命名空间
			List<Element> beans = xsub.selectNodes(document);//获取节点
			for(Element element:beans){
				String id = element.attributeValue("id");
				String clazz = element.attributeValue("class");
				MyBean bean = new MyBean(id, clazz);
				beanList.add(bean);
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	/**
	 * 
	 * @Description 实例化bean
	 * @author XIVA
	 */
	private void instanceBean(){
		Object object = null;
		for(MyBean bean:beanList){
			try{
				String clazzStr = bean.getBeanClass();
				Class<?> clazz = Class.forName(clazzStr);
				object = clazz.newInstance();
				sigletons.put(bean.getBeanId(), object);
			}catch(Exception e){
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 获取Bean实例
	 */
	@Override
	public Object getBean(String beanName) {
		// TODO Auto-generated method stub
		
		return sigletons.get(beanName);
	}

}

 dom的解析,这个好处就是不需要引入dom4j这个包,spring就这样做的。

package com.xiva.mySpring;

import java.io.InputStream;
import java.util.Hashtable;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.xiva.bean.MyBean;

public class XivaClassXmlApplicationContext extends XivaAbsAppContext{
	
	private static Hashtable<String,MyBean> beans = new Hashtable<String,MyBean>();
	
	public XivaClassXmlApplicationContext(String xmlPath){
		readXML(xmlPath);
	}
	
	private void readXML(String xmlPath){
		InputStream is = XivaClassXmlApplicationContext.class.getClassLoader().getResourceAsStream(xmlPath);
		DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
		try{
        DocumentBuilder dombuilder        = domFactory.newDocumentBuilder();  
        Document document = dombuilder.parse(is);  
        Element root      = document.getDocumentElement();
        NodeList nodes    = root.getElementsByTagName("bean");
        int length = nodes.getLength();
        for(int i=0;i<length;i++){
        	Node childNode = nodes.item(i);
        	NamedNodeMap attrs = childNode.getAttributes();
        	MyBean bean = new MyBean();
        	for(int j=0;j<attrs.getLength();j++){
        		Node attrNode = attrs.item(j);
                if("id".equals(attrNode.getNodeName())){  
                	bean.setBeanId(attrNode.getNodeValue());  
                }else if("class".equals(attrNode.getNodeName())){  
                	bean.setBeanClass(attrNode.getNodeValue());  
                }       
        	}
        	if(bean!=null){
        		beans.put(bean.getBeanId(), bean);
        	}
        	
        }
		}catch(Exception e){
			System.out.println("error");
		}
	}
	
	@Override
	public Object getBean(String beanName){
		MyBean bean = beans.get(beanName);
		String className = bean.getBeanClass();
		Class<?> clazz = null;
		Object obj = null;
		try {
			clazz = Class.forName(className);
			obj = clazz.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return obj;
	}
}
 

第二种,方式没有给出类似于启动spring时,就实例化所有的bean。实现方式其实通方式一。当然这里和spring差距还是很大的,但其核心原理就是上面这样。

猜你喜欢

转载自xiva.iteye.com/blog/1089832