`
阅读更多
         学过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  
模拟的很好

相关推荐

    Spring简单模拟Spring容器

    标题中的“Spring简单模拟Spring容器”意味着我们将探讨Spring框架的核心特性——IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入),以及如何通过编程方式模拟Spring容器的工作原理。...

    以注解方式模拟Spring IoC AOP

    模拟Spring的IoC,我们可以创建一个简单的容器类,其中包含一个Map来存储bean。然后使用注解处理器扫描带有特定注解(如`@Component`)的类,并将它们注册到容器中。当需要注入依赖时,容器可以解析注解并自动装配。...

    Java模拟spring实现

    在本文中,我们将探讨如何通过Java来模拟Spring框架的基本功能。Spring是一个广泛应用的开源框架,它主要为Java应用程序提供依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP...

    java模拟spring ioc

    1. **创建Bean工厂**:首先,我们需要一个类来模拟Spring的Bean工厂,它负责创建和管理对象。这个工厂可以包含一个Map,用于存储对象及其对应的类。 2. **定义Bean接口**:为每个需要管理的对象定义一个接口,接口...

    模拟Spring的IOC

    通过以上步骤,我们可以构建一个简单的IOC容器,模拟Spring的核心功能。这不仅有助于理解Spring的工作原理,也为我们自定义轻量级框架提供了可能。在实际开发中,了解并掌握Spring的IOC机制能够帮助我们更好地设计和...

    自己动手模拟spring

    【标题】:“自己动手模拟spring” 【描述】:在该主题中,我们将深入理解Spring框架的核心概念,并通过编码实践来模拟其工作原理。参考链接提供了一个CSDN博客文章,作者详细介绍了如何从零开始创建一个简易版的...

    模拟spring

    总的来说,“模拟Spring”不仅是一次学习之旅,也是一次提升开发技能的过程。通过对源码的阅读和实践,我们可以深入理解Spring的内部工作原理,进一步提升我们的编程水平和问题解决能力。无论你是Spring的新手还是...

    模拟Spring IoC

    在这个模拟Spring IoC的项目中,我们可以深入理解以下几个关键知识点: 1. **容器的概念**:Spring IoC容器是管理对象及其依赖关系的核心组件。在这个模拟项目中,会有一个类或接口扮演容器的角色,负责创建对象、...

    模拟spring ioc过程

    这个"模拟spring ioc过程"的学习例子是基于Java语言的,旨在帮助理解Spring框架中的这两个核心概念。在Java工程中,我们通常会通过配置文件(如XML或Java配置类)来定义bean的定义和它们之间的依赖关系。在实际运行...

    java 解析xml,模拟spring框架ioc

    模拟Spring的IOC功能,我们可以创建一个简单的解析器类,该类负责加载XML配置文件,解析Bean定义,实例化和注入依赖。为了实现这个功能,我们需要了解和使用Java的DOM或SAX解析库,以及反射API。这是一个很好的学习...

    模拟实现Spring的IOC

    Spring容器就是一个bean的Map:private Map, Object&gt; beans = new HashMap, Object&gt;(); 2、本工程,模拟实现Spring的IOC,将xml中配置的Bean读入到Spring容器中,并在测试用例中调用Spring容器中的bean。 3、开发...

    模拟spring和工具jar包

    本资源名为“模拟spring和工具jar包”,其目的是为了帮助我们理解Spring框架的核心概念——依赖注入,并通过一个简化版的实现来学习这一机制。 依赖注入是Spring框架的核心特性之一,它允许我们在不直接创建对象的...

    简单模拟spring cglib代理

    现在,我们来详细探讨如何简单模拟Spring框架中的CGLIB代理。要进行模拟,首先需要了解CGLIB代理的核心实现原理,包括代理类的生成、方法拦截和回调机制等。 1. 代理类的生成 CGLIB使用Enhancer类来生成代理对象。...

    使用反射和注解模拟Spring的依赖注入

    模拟Spring的依赖注入,我们可以创建一个简单的容器类,它使用反射来扫描带有特定注解的类,并根据这些注解管理bean。以下步骤概括了这个过程: 1. **定义注解**:创建自定义注解,如`@MyComponent`,用于标记需要...

    简单模拟Spring的beanFactory

    本文将通过模拟Spring的`BeanFactory`来深入理解其工作原理,帮助开发者更好地掌握Spring的核心概念。 `BeanFactory`是Spring框架中最基础的bean管理容器,它是所有更高级别的容器(如`ApplicationContext`)的基类...

    尚学堂_Spring_0100_模拟Spring

    "模拟Spring"可能意味着我们将通过一个简化版或实例化的Spring核心功能来学习其工作原理。这种实践性的方法有助于我们更直观地理解Spring如何管理对象和处理依赖关系。 首先,Spring中的“AbstractOrientedProgram...

    模拟Spring的依赖注入

    在模拟Spring的依赖注入时,我们可以创建一个类似于Spring容器的类,负责创建和管理对象以及它们的依赖关系。这个类可以包含一个注册方法,用于接收需要注入的对象及其依赖,然后在创建对象时进行注入。 **创建模拟...

    模拟spring aop技术

    **模拟Spring AOP技术** Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架中的一个重要组件,它提供了一种在不修改源代码的情况下,通过代理模式来实现横切关注点(如日志、事务管理等)的...

    模拟Spring架构的简易实现

    总的来说,这个"模拟Spring架构的简易实现"项目是一个很好的学习工具,可以帮助开发者深入理解Spring框架的工作原理,尤其是依赖注入和面向切面编程的概念。通过实际动手操作,可以更好地掌握这些核心概念,并为实际...

    模拟 Spring 的实现

    模拟Spring并不是重新创建一个完整的Spring框架,而是为了学习和理解Spring的工作原理,通过编写简单的代码来实现IOC(Inversion of Control,控制反转)和AOP(Aspect-Oriented Programming,面向切面编程)的核心...

Global site tag (gtag.js) - Google Analytics