`
阅读更多
         学过Java的人对SSH都不会陌生,其中Spring备受青昧除了它的"轻"之外,还因为他的IOC与AOP两大功能的强大。IOC是Spring的核心概念,全称“Inversion Of Control”,翻译成中文是“控制反转”,很多人都把它叫做“依赖注入(Dependency Injection)”。而它的抽象概念是“依赖关系的转移”。转移是相对于过去不良的应用程序设计来说的,象“高层模块不应该依赖于低层模块,而模块必须都依赖于抽象”是IOC的一种表现,“实现必须依赖于抽象,而不是抽象依赖于实现”是IOC的另一种表现。
          举一个例子,控制层调用业务逻辑组件,应该只知道业务逻辑组件的接口,而不知道其具体实现类,同样业务逻辑组件调用DAO组件时也应该只知道DAO组件的接口,这称为“依赖于抽象”。把他们原来的高层依赖于低层的关系转移到xml配置文件与一个大的工厂中(Spring本身就是一个工厂),由它们进行实例化与属性的注入,当要修改他们的依赖关系时,无需修改客户端,只需要修改xml配置文件即可。符合OCP原则的“开放-封闭”。
         
          下面来模拟Spring如何把几层模块之间的依赖关系转移到xml文件中去。
首先设计一个VO--Person.java
import java.io.Serializable;
import java.sql.Date;

public class Person implements Serializable {

	private String name;   //名字
 
	private int age;       //年龄

	private Date birthday; //出生年月

	private double salary; //月薪

	//对应的get,set方法
	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public double getSalary() {
		return salary;
	}

	public void setSalary(double salary) {
		this.salary = salary;
	}
}


DAO组件接口与DAO的实现类,只是简单模拟一下,并没有真的与数据库进行交互
public interface PersonDao  {

	public void save(Person p);

	public void delete(Person p);
}


public class PersonDaoImpl implements PersonDao {

	public void delete(Person p) {
		System.out.println("现在进行删除的操作...姓名:" + p.getName()
				+ ",年龄:" + p.getAge()+",出生年月:"+p.getBirthday()+",月薪:"+p.getSalary());
	}

	public void save(Person p) {
		System.out.println("现在进行保存的操作...姓名:" + p.getName() + ",年龄:"
				+ p.getAge()+",出生年月:"+p.getBirthday()+",月薪:"+p.getSalary());
	}
}


业务逻辑组件接口与实现类,这里只是简单地调用DAO组件的方法
public interface PersonService {
       
	public void save(Person p);

	public void delete(Person p);
}


public class PersonServiceImpl implements PersonService{
    
	private PersonDao personDao;  //依赖于抽象
	
	public void delete(Person p) {
		personDao.delete(p);
	}

	public void save(Person p) {
		personDao.save(p);
	}

	public PersonDao getPersonDao() {
		return personDao;
	}

	public void setPersonDao(PersonDao personDao) {
		this.personDao = personDao;
	}
}


简单模拟Spring工厂的代码

import java.io.File;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class SpringFactory {
	
	//存储Bean的实例
	private Map<String, Object> appMap = new HashMap<String, Object>();
    
	//储存xml配置文件中Bean实例的信息
	private Map<String, String> beans = new HashMap<String, String>();
    
	//存储xml配置文件中Bean的属性的信息
	private Map<String, String> properties = new HashMap<String, String>();

	
    //工厂采用单例模式
	private static SpringFactory df;
    
	//私有构造函数
	private SpringFactory() throws Exception {
		//采用Dom4j对xml文件进行解析
		Document doc = new SAXReader().read(new File("beanContext.xml"));
		Element root = doc.getRootElement();
		List el = root.elements();
		for (Iterator it = el.iterator(); it.hasNext();) {
			Element em = (Element) it.next();
			String id = em.attributeValue("id");
			String impl = em.attributeValue("class");
			beans.put(id, impl);
			// 开始第2次遍历
			List e2 = em.elements();
			// 储存属性的内容
			StringBuilder s = new StringBuilder();
			boolean flag = false;
			for (Iterator i = e2.iterator(); i.hasNext();) {
				Element em2 = (Element) i.next();
				String name = em2.attributeValue("name");
				String ref = em2.attributeValue("ref");
				String value = em2.attributeValue("value");
				if (ref != null) {
					s.append("ref,").append(name + ",").append(ref + ";");
				} else if (value != null) {
					s.append("value,").append(name + ",").append(value + ";");
				}
				flag = true;
			}
			if (flag == true) {
				properties.put(id, s.toString());
			}
		}
		//实例化Bean并注入Bean的属性
		initBeans();
	}

	private final void initBeans() throws Exception {
		// 初始化Bean
		for (String id : beans.keySet()) {
			try {
				Object o = Class.forName(beans.get(id)).newInstance();
				appMap.put(id, o);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
        
		//这里按照配置文件注入Bean中的属性
		for (String id : properties.keySet()) {
			String[] property = properties.get(id).split(";");
			for (int i = 0; i < property.length; i++) {
				String[] part = property[i].split(",");
				String type = part[0];
				String name = part[1];
				String value = part[2];
				// 从已经实例化好的appMap里面取出要设置属性的Object
				Object bean = appMap.get(id);
				// 获取对应的set方法名称
				String methodName = "set" + name.substring(0, 1).toUpperCase()
						+ name.substring(1, name.length());

				Method[] methods = bean.getClass().getMethods();
				for (Method m : methods) {
					if (m.getName().equals(methodName)) {
						Class[] typeParam = m.getParameterTypes();
						// 获取非对象类型的属性转换为对应类型后的值
						Object param = null;
						if (type.equals("ref")) {
							param = appMap.get(value);
						} else {
							param = getParameter(typeParam[0], value);
						}
						//捕捉一下参数类型不正确的异常
						try {
							m.invoke(bean, param);
						} catch (IllegalArgumentException e) {
                            System.out.println("参数<"+name+">类型不正确,依赖注入失败!");
						}
					}
				}
			}
		}
	}

	
	// 输入参数的源对象与值(String类型),转换为正确类型的值(只列出常用的几种)
	public Object getParameter(Class c, String value) {
		String typeName = c.getName();
		if (typeName.equals("int") || typeName.equals("java.lang.Integer")) {
			return Integer.valueOf(value);
		} else if (typeName.equals("java.lang.String")) {
			return value;
		} else if (typeName.equals("java.lang.Boolean")||typeName.equals("boolean")) {
			return Boolean.valueOf(value);
		} else if(typeName.equals("java.lang.Long")||typeName.equals("long")){
			return Long.valueOf(value);
		}
		else if(typeName.equals("java.lang.Double")||typeName.equals("double")){
			return Double.valueOf(value);
		}
		else if(typeName.equals("java.lang.Float")||typeName.equals("float")){
			return Float.valueOf(value);
		}
		//捕捉SimpleDateFormat转换日期失败的异常
		else if(typeName.equals("java.util.Date")){
			try{
				SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); 
				return formatter.parse(value);
			}catch(ParseException e){
				System.out.println("日期参数转换类型失败!请输入\"yyyy-MM-dd\"的格式");
				return null;
			}
		}
		////捕捉ava.sql.Date转换日期失败的异常
		else if(typeName.equals("java.sql.Date")){
			try{
				return java.sql.Date.valueOf(value);
			}
			catch(IllegalArgumentException e){
				System.out.println("日期参数转换类型失败!请输入\"yyyy-MM-dd\"的格式");
				return null;
			}
		}
		else{
			return null;
		}		
	}

	// 返回SpringFactory的实例
		public static synchronized SpringFactory getInstance() throws Exception {
		if (df == null) {
			df = new SpringFactory();
		}
		return df;
	}

	// 获取Map中实例的方法
	public Object getBean(String id) {
		return appMap.get(id);
	}
}


这里有几点要注意:
第一,其实这里主要就用到了Java的反射+xml解析的技术,xml解析用到Dom4j,因此项目要加入Dom4j的jar包才能执行。
第二,工厂是先解析完xml文件,然后再进行Bean与组件的实例化和注入属性,并非边解析边实例化,所以代码多了很多:)
第三,获取要注入属性的类型时,并没有依赖于该私有属性的类型去查找,而是按照该属性的set方法中的参数类型,这正是Spring的做法。因此在不按照Java规范书写时,Spring也能进行注入,如
private String name;

	public void setYourName(String yourName) {
		name = yourName;
	}

当然在xml配置文件你要设置为yourName而并非name
第四,有没看到中间一大段很臃肿的代码,这里是进行属性的类型转换时的操作,因为从xml获取属性的值是String类型,要根据各个Bean不同的属性类型而进行正确的转换,这也是难点之一。本来想用策略模式改造,或者加入一个类似类型转换的系统,但又太麻烦,迟下再完善一下。Spring是用BeanUtils进行类型转换,但性能方面BeanUtil并不是最好的选择。对此大家有什么好的建议
第五,Spring有“singleton”与“prototype”两种模式设置(针对Web应用还有request,session等),上面的例子只是仿照“singleton”模式产生单一实例,而“prototype”是每次请求到来的时候都产生单一实例。单例模式能节省更多的内容空间,但如果涉及到保存数据需要维护状态的时候,就要采用prototype的方式。对于上述例子,把生成实例的代码放到getBean()中去就可以了。


<?xml version="1.0" encoding="GBK"?>
<beanContext>
   <bean id="person1" class="spring.simulate.Person">
       <property name="name" value="Jam"/>
       <property name="age"  value="18"/>
       <property name="birthday" value="1985-8-8"/>
       <property name="salary" value="10000"/>
   </bean>
   
   <bean id="person2" class="spring.simulate.Person">
        <property name="name" value="Wjm"/>
        <property name="age" value="20"/>
        <property name="birthday" value="1985-9-9"/>
        <property name="salary" value="9000"/>
   </bean>
   
   <bean id="personDao" class="spring.simulate.PersonDaoImpl">   
   </bean>
   <bean id="personService" class="spring.simulate.PersonServiceImpl">
      <property name="personDao" ref="personDao"/>
   </bean>
</beanContext>




客户端测试代码:
public class Client {
    public static void main(String[] args) throws Exception {
		SpringFactory factory = SpringFactory.getInstance();
		//实例化Service组件,Dao组件已经注入到Service的组件中
		PersonService service = (PersonService) factory.getBean("personService");
		//获取一些Person
		Person p1 = (Person) factory.getBean("person1");
		Person p2 = (Person) factory.getBean("person2");
		
		service.save(p1);
		service.delete(p2);		
	}
}


结果显示:
现在进行保存的操作...姓名:Jam,年龄:18,出生年月:1985-08-08,月薪:10000.0
现在进行删除的操作...姓名:Wjm,年龄:20,出生年月:1985-09-09,月薪:9000.0
分享到:
评论
2 楼 wangd2006 2013-01-07  
很有价值,很有用。
1 楼 悲剧了 2010-10-30  
模拟的很好

相关推荐

Global site tag (gtag.js) - Google Analytics