天天看点

初步理解spring ioc原理(读完可自己实现依赖注入部分的spring框架)

spring  的核心原理是ioc 和aop(面向切面编程),近段时间学习了spring的ioc部分,这篇文章也是自己对spring  原理的一个理解整理,希望对大家有所帮助。aop待学习之后再发表文章。

ioc(控制反转) 是指有依赖关系的两个对象A和B,A对象的实现依赖B对象的实现,那么在通常开发中,我们会实例化一个b对象来让a对象进行调用,a对象掌握着b对象的生命周期,也就是说a对象控制着d对象,而这是高耦合性的。而在ioc中,将b对象的创建和管理交于第三者来代理(比如一个框架或者工具类),而b对象的实例化交给代理者来管理,a对象只负责使用b对象来进行业务处理,a对象对b对象的控制则交给了代理者,这就是控制反转的体现。而依赖注入,则是代理者利用ioc原理和类反射来动态注入a对象所依赖的对象(这里是b)。同时b对象只要是满足某一个接口(即a对象需要的部分)即可,那么可以将b对象作为一个接口类。这样更容易进行扩展。下面我会进一步剖析spring 的ioc部分,并带领大家完成自己 的ioc部分的spring框架。

首先新建一个web 工程, 导入dom4j.jar 和jaxen.jar 包,这是saxreader所依赖的包。saxreader 是一个优秀的xml解析api,我们使用它来解析spring bean配置文件。

在src下新建一个ms.xml文件作为spring 的配置文件

新建一个包,包里有以下两个文件

1.proxyXML.class  用于解析xml文件  

2.BeanFactory.class 用于获取xml文件的bean并注入所需实际引用对象

代码如下

1.proxyXML.class

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

public class ProxyXML {
	private static Document xmldoc;
	static{
		//解析ms配置文件
		SAXReader saxReader = new SAXReader();
		try {
			xmldoc = saxReader.read(ProxyXML.class.getResourceAsStream("/ms.xml"));
		} catch (DocumentException e) {
			// TODO: handle exception
		}
	}
	
	//获取 配置文件中 beans节点里 name属性值为name 的bean的属性值并保存到map中返回
	public static Map getProperty(String name){
		String nodepath = "//beans/bean[@name='"+name+"']/property";
		//获取bean节点中所有的property子节点并保存到es中
		List<Element> es = xmldoc.selectNodes(nodepath);
		Map map = new HashMap();
		//对es进行遍历
		for(Element e :es){
			//如果该property有ref属性,那么保存ref的值并放在map中
			if(e.attribute("ref")!=null){
				map.put(e.attributeValue("name"),e.attributeValue("ref"));
				
			}else{//如果没有ref属性,那么认为是普通字符串进行保存
				Element ev = (Element) e.selectNodes("value").get(0);
				map.put(e.attributeValue("name"),ev.getText());
			}
		}
		return map;
	}
}
           

2.BeanFactory.class 

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;


public class BeanFactory {
	//根据传入的类名进行实例并返回类的实例,同时进行属性注入
	public Object getBeans(String name) throws Exception{
		//利用类反射机制实例类
		String classname = ProxyXML.getClass(name);
		Class clzz = Class.forName(classname);
		Object obj = clzz.newInstance();
		//获取该类的所有属性并进行注入实例
		Map map = ProxyXML.getProperty(name);
		if(map.size()>0){
			getMethod(obj,clzz,map);
		}
		return obj;
	}

	private void getMethod(Object obj, Class clzz, Map map) throws Exception {
		//获取clzz类的所有属性并进行遍历
		Field[] fs = clzz.getDeclaredFields();
		for(Field f :fs){
			//获取f的名字
			String mn = f.getName();
			//设置set方面名字为set和mn(mn第一个字母大写)
			String methodname = "set" +mn.substring(0,1).toUpperCase() + mn.substring(1);
			//生成method对象
			Method m =clzz.getMethod(methodname,f.getType());
			//如果f的类型是String那么直接掉用clzz的set方法,进行f属性注入
			if(f.getType().toString().endsWith("String")){
				m.invoke(obj, map.get(mn).toString());
			}else{//如果是类则先进行属性获取,再进行属性注入
				m.invoke(obj, getBeans(map.get(mn).toString()));
			}
		}
	}
}
           

3.ms.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<bean name="print" class="com.sp.ms.Print">
		<property name="mes">
			<value>Hello SSH</value>
		</property>
		<property name="p" ref="paper"/>
		<property name="b" ref="box"/>
	</bean>
	
	<bean name="paper" class="com.sp.ms.A4Paper">
	</bean>
	<bean name="box" class="com.sp.ms.BlackBox">
	</bean>
</beans>
           

现在我们来对以上进行测试,先创建以几个类

1.Paper 接口类

2.Box接口类

3.A4paper 类 实现Paper 接口

4.Blackbox 类,实现 Box接口

1.Paper.class

package com.woniuxy.ms;

public interface Paper {
	
	public abstract void doPaper();

}
           

2.Box.class  

package com.woniuxy.ms;

public interface Box {
	
	public abstract void doBox();

}
           

3.A4paper.class

public class A4Paper implements Paper{

	@Override
	public void doPaper() {
		System.out.print("此处约等于1000行代码-->");
		System.out.println("A4Paper");
	}

}
           

4.Blackbox.class

public class BlackBox implements Box{
	
	@Override
	public void doBox() {
		System.out.print("此处约等于1000行代码-->");
		System.out.println("黑色墨盒");
	}

}
           

5.print.class

import com.sp.ms.util.BeanFactory;

public class Print {
	
	//依赖注入
	private String mes;
	private Paper p;
	private Box b;
	
	public void setMes(String mes) {
		this.mes = mes;
	}

	public void setP(Paper p) {
		this.p = p;
	}

	public void setB(Box b) {
		this.b = b;
	}
	
	public void doPrint(){
		p.doPaper();
		b.doBox();
		System.out.println(mes);
	}

	public static void main(String[] args) throws Exception {
		Print p = (Print) new BeanFactory().getBeans("print");
		p.doPrint();
	}

}
           

运行后结果如下:

//此处约等于1000行代码-->B5Paper
//此处约等于1000行代码-->黑色墨盒
//Hello SSH
           

以上就是对于spring ioc部分的整理,自己也有很多东西还没学透,各位观众老爷看看就好哈。

初步理解spring ioc原理(读完可自己实现依赖注入部分的spring框架)