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部分的整理,自己也有很多东西还没学透,各位观众老爷看看就好哈。