zoukankan      html  css  js  c++  java
  • TinySpring分析二

    step5

    看完了前面的几步,到如今我们必定要想到的问题就是,数据要是放在xml中怎么读?
    事实上依照正常思维一步一步来,从xml中读数据和之前手工配进去并没有什么大的差别,仅仅要读出来就OK了。


    先看測试程序,

    	public void Step5() throws Exception {
    		// 1.读取配置
    		XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader();
    		xmlBeanDefinitionReader.loadBeanDefinitions("bin/resources/tinyioc.xml");
    		 
    		// 2.初始化BeanFactory并注冊bean
    		BeanFactory beanFactory = new AbstractBeanFactory();
    		for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getBeanDefinitionMap().entrySet()) {
    		        ((AbstractBeanFactory)beanFactory).registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
    		}
    		 
    		// 3.获取bean
    		HelloWorldServiceImpl helloWorldService = (HelloWorldServiceImpl) beanFactory.getBean("helloWorldService");
    		helloWorldService.helloWorld3();
    	}

    关于路径问题
    在java中,获取文件(包含xml,jpg等等)有两种方式
    Class类下的getResource(String path)方法与
    ClassLoader类下的getResource(String path)方法


    先说后面一种,ClassLoader.getResource()參数中不带"/",默认就是根路径(在Eclipse中,跟路径就是project下的bin文件夹,在默认情况下,eclipse会把项目中的src下的内容复制到bin下,因此也能够理解为根文件夹就是src文件夹)

    第一种Class.getResource()能够带"/"也能够不带
    一旦带了/ 就默认从根路径(就是bin 就是src)下查找了
    假设没有/ 就从这个类本身的那个路径下查找
    具体资料见
    http://www.cnblogs.com/yejg1212/p/3270152.html
    在step5这个样例里
    InputStream is = new FileInputStream(local);这里的local是从项目文件夹算的,因此还得加上bin


    看了測试代码大家就会知道,我们的程序结构了吧,XmlBeanDefinitionReader的主要作用就是读取xml,然后转换成一个个BeanDefinition,再存储进BeanDefinitionMap,再创建一个BeanFactory,将BeanDefinitionMap中的记录一个一个再注冊一边。

    public class XmlBeanDefinitionReader {
    
    	//bean清单 就是前面说的学校里面的学生信息表
    	private Map<String, BeanDefinition> beanDefinitionMap;
    		
    	public XmlBeanDefinitionReader(){
    		beanDefinitionMap = new HashMap<String, BeanDefinition>();
    	}
    
    	public void loadBeanDefinitions(String local) throws IOException, ParserConfigurationException, SAXException {
    		InputStream is = new FileInputStream(local);
    		parseNode(is);
    	}


    看了loadBeanDefinitions,非常easy吧,就是建一个InputStream,连接到文件上,然后从文件里读数据。


    这里面的东西不难,可是比較繁杂,牵扯最多的就是对xml的解析
    相关知识见
    http://blog.csdn.net/dlf123321/article/details/39649089

    /**
    	 * 通过InputStream 获得每个bean
    	 * @param is
    	 * @throws ParserConfigurationException
    	 * @throws SAXException
    	 * @throws IOException
    	 */
    	public void parseNode(InputStream is) throws ParserConfigurationException, SAXException, IOException {
    		DocumentBuilderFactory domfac = DocumentBuilderFactory.newInstance();
    		DocumentBuilder domBuilder = domfac.newDocumentBuilder();
    
    
    		// 默认是project文件夹
    	//	InputStream is = new FileInputStream("bin/resources/tinyioc.xml");
    		Document doc = domBuilder.parse(is);
    		Element root = doc.getDocumentElement();
    		NodeList beans = root.getChildNodes();
    		for (int i = 0; i < beans.getLength(); i++) 
    			if (beans.item(i) instanceof Element) {
    				Element el=(Element)beans.item(i);
    				parseElement(el);
    			}
    		is.close();
    		
    	}
    	
    	/**
    	 * 分析每个bean的id class
    	 * @param el
    	 */
    	public void parseElement(Element el){
    		String id=el.getAttribute("id");
    		String classPath=el.getAttribute("class");
    	//	System.out.println(id+"  "+classPath);
    		BeanDefinition bd=new BeanDefinition();
    		bd.setBeanClassName(classPath);
    		parseProperties(el,bd);
    		beanDefinitionMap.put(id, bd);
    	}
    	
    	/**
    	 * 分析每个bean的參数  并增加到beandefinition的property里面
    	 * @param el
    	 * @param bd
    	 */
    	public void parseProperties(Element el,BeanDefinition bd){
    		NodeList bl=el.getElementsByTagName("property");
    		for (int i = 0; i < bl.getLength(); i++) 
    			if (bl.item(i) instanceof Element) {
    				Element property=(Element)bl.item(i);
    				String name=property.getAttribute("name");
        		//	System.out.print("   "+name+"  ");
    				if (property.getAttribute("ref")!="") {
    					BeanReference br=new BeanReference(property.getAttribute("ref"));	
    					PropertyValue pV=new PropertyValue(name,br);
    					bd.getPropertyValues().addPropertyValue(pV);
    			//		System.out.println("   "+br.getName()+"  ");
    				}
    				if (property.getAttribute("value")!="") {
    					String value=property.getAttribute("value");
    					PropertyValue pV=new PropertyValue(name, value);
    					bd.getPropertyValues().addPropertyValue(pV);
    				//	System.out.println(value);
    				}
    			}
    		
    	}
    
    	public Map<String, BeanDefinition> getBeanDefinitionMap() {
    		return beanDefinitionMap;
    	}


    再剩下的代码,參考step4就ok


    step6

    假设细致,比对XmlBeanDefinitionReader与AbstractBeanFactory,就能发现两个类里面都有beanDefinitionMap,重写两边,不合适。
    另外在step5中
    		// 2.初始化BeanFactory并注冊bean
    		BeanFactory beanFactory = new AbstractBeanFactory();
    		for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getBeanDefinitionMap().entrySet()) {
    		        ((AbstractBeanFactory)beanFactory).registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
    		}

    依照使用者与创建者分离的原则,初始化注冊的代码出如今client也不合适;
    怎么办?
    合起来呗。


    还是先写測试代码 例如以下

    <pre name="code" class="java">public void Step7() throws Exception {
    		ApplicationContext ac=new ApplicationContext("bin/resources/tinyioc.xml");
    		HelloWorldServiceImpl helloWorldService = (HelloWorldServiceImpl) ac.getBean("helloWorldService");
    		helloWorldService.helloWorld3();
    	}
    美丽!关键就是ApplicationContext,上面已经说了,要把XmlBeanDefinitionReader与AbstractBeanFactory合起来,也就是说要把getBean与loadBeanDefinitions装到一个类里面去
    package com.myspring.context;
    
    import java.util.Map;
    
    import com.bjsxt.spring.BeanFactory;
    import com.myspring.beans.BeanDefinition;
    import com.myspring.beans.factory.AbstractBeanFactory;
    import com.myspring.beans.xml.XmlBeanDefinitionReader;
    
    public class ApplicationContext implements BeanFactory {
    	
    	private AbstractBeanFactory abf=new AbstractBeanFactory();
    
    	public  ApplicationContext(String local) throws Exception {
    	//	InputStream is = new FileInputStream(local);
    		loadBeanDefinitions(abf,local);
    	}
    	
    	protected void loadBeanDefinitions(AbstractBeanFactory beanFactory,String configLocation) throws Exception {
    		XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader();
    		xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
    		for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : 
    			xmlBeanDefinitionReader.getBeanDefinitionMap().entrySet()) {
    			beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
    		}
    	}
    	@Override
    	public Object getBean(String id) {
    		// TODO Auto-generated method stub
    		Object obj=null;
    		try {
    			obj = abf.getBean(id);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		return obj;	
    	}
    }


    AbstractBeanFactory与ApplicationContext都继承了BeanFactory,然后我们不直接用BeanFactory,而是让ApplicationContext中装一个AbstractBeanFactory,这不就是最简单的代理模式么?
    代码到这里,就算是完毕了黄亿华大神的TinySpring中IoC的大部分代码
    之所以说是大部分,也就是说如今大家看到的代码另一些部分与TinySpring不同
    主要在这几个方面
    1 Resources部分
      在我完毕的代码里,读取xml的时候直接就是一个InputStream,TinySpring的方式是有一个Resource类,同一时候另一个LoadResource类用来载入资源,当然实现的内部机理都是inputstream;
    2 接口问题
      我一直觉得,良好的代码是一次一次重构出来的,依我如今的水平,确实不可以非常清晰地说出,分了那么多层接口,抽象类的实际作用,因此在我的代码里各个部分都非常"薄弱"(仅仅有一层)
    3 对于类的载入,有两种方式一种直接载入,一种延迟载入,TinySpring最開始的那几个step还是在getBean的时候才newInstance的,可是到后面
    	protected void onRefresh() throws Exception{
    	     beanFactory.preInstantiateSingletons();
    	  }
    
    
    	public void preInstantiateSingletons() throws Exception {
    		for (Iterator<String> it = this.beanDefinitionNames.iterator(); it.hasNext();) {
    			String beanName = (String) it.next();
    			getBean(beanName);
    		}
    	}
    所以的类都直接载入了;


    4 单例模式
    TinySpring中一个bean默认仅仅会载入一次,第二次getBean()的时候会取出之前已经creat的那个;
    public Object getBean(String name) throws Exception {
    		BeanDefinition beanDefinition = beanDefinitionMap.get(name);
    		if (beanDefinition == null) {
    			throw new IllegalArgumentException("No bean named " + name + " is defined");
    		}
    		Object bean = beanDefinition.getBean();
    		if (bean == null) {                     //******************查找beanDefinition
    			bean = doCreateBean(beanDefinition);
                bean = initializeBean(bean, name);
                beanDefinition.setBean(bean);
    		}
    		return bean;
    	}
    
    
    	protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
    		Object bean = createBeanInstance(beanDefinition);
    		beanDefinition.setBean(bean);            //******************写入beanDefinition
    		applyPropertyValues(bean, beanDefinition);
    		return bean;
    	}



    我写的代码中,没有上面的步骤,因此即使第二次get一个已经get过得bean,仍然会产生一个新的bena!


    我写的代码 下载地址

    http://download.csdn.net/detail/dlf123321/7992633

    參考资料

    http://www.cnblogs.com/yejg1212/p/3270152.html

    http://blog.csdn.net/dlf123321/article/details/39649089


  • 相关阅读:
    * 结束Activity
    进度条ProgressBar
    StackView实现叠加在一起的图片循环移动像循环队列一样
    AdapterViewFlipper功能 自动播放的图片库
    Spinner功能和用法
    SimpleAdapter 网络视图:带预览的图片浏览器
    AutoCompleteTextView
    Faster R-CNN
    Fast R-CNN
    100个大型机器学习数据集汇总(CV/NLP/音频方向)
  • 原文地址:https://www.cnblogs.com/lxjshuju/p/6851569.html
Copyright © 2011-2022 走看看