一,配置文件
<?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差距还是很大的,但其核心原理就是上面这样。