`
cxshun
  • 浏览: 724165 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

基本IOC尝试

 
阅读更多

近两个月一直被肠胃病折磨着,痛苦了好久,这段时间稍微好点了。身体不好,技术也就放下了。搞技术的朋友们啊,要保重好自己的身体啊,年轻并不代表可以挥霍健康。

好了,废话少说,今天,这几天尝试自己写了一点点IOC的实现,当然只是很基本的属性注入的,对象的那些还没有去处理。但起码把自己一直以来想要深入理解一个思想的想法付诸行动了。

搞JAVA的朋友肯定都知道IOC是啥来的,如果不知道的,看看这个http://baike.baidu.com/view/146665.htm#sub6386770。简要的说一下就是把对象之间的关联交给容器来处理,而不是我们以前代码那样,直接来set或new一个。

知道了它是什么来的,我们肯定很希望知道它是怎么实现的,用过spring的朋友当然都知道。拿个xml文件,配置一下,然后加载,再getBean,一切Ok,啥都不用管,或者web中用contextLoaderListener或者DispatcherServlet都可以搞定,但停留在使用的层面上,显然不是我们想要的。

我们知道容器只是帮我们处理了一些依赖,如set,new等等,如此而已(听起来很简单,但有很多东西需要考虑的)。

下面我们就一起来看看,实现一个基本的可以注入属性的IOC容器,我们先不管注入依赖对象。

1)要注入属性,我们一般是通过调用setXXX方法,这里我们也是这样的(暂时不考虑构造函数注入),我们通过反射来调用相应的set方法。

我们这里的配置载体还是最流行的XML了,注解也很流行,但暂时还是不弄了。

我们有一个Bean来保存所有bean的配置属性等,就如同spring的BeanDefinitionHolder:

package com.shun.bean;

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

public class BeanDefinition {

	private String name;//保存bean的id
	private String type;//保存class的值
	private List<Map<String,Object>> properties;//保存property标签的相关配置
	public String getName(){
		return name;
	}
	public void setName(String name){
		this.name = name;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public List<Map<String,Object>> getProperties() {
		return properties;
	}
	public void setProperties(List<Map<String,Object>> properties) {
		this.properties = properties;
	}
	
}

  当然,很简陋,只保存了相当于bean的id,class还有一系列property标签的配置。但已经足够我们来学习基本的属性注入了。

2)我们是通过反射来调用相应的类的属性的set方法,当然这时属性的首字母会变大写,如属性为name,则set方法是setName,我写了一个工具类来处理首字母大写:

package com.shun.utils;

public class DataUtils {

	/**
	 * 将传入的字符串首字母大写
	 * @param str
	 * @return
	 */
	public static String capitalize(String str) {
		return str.substring(0,1).toUpperCase()+str.substring(1);
	}
	
}

  3)然后最主要的当然是数我们的IOC处理类了MyIocProcessor:

首先我们来看看读取配置文件的方法:

	/**
	 * 读取配置文件,并把配置文件中的相关配置保存到beanDefinitionList中
	 * @param configPath
	 * @return
	 */
	public List<BeanDefinition> processConfig(String configPath){
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		List<BeanDefinition> beanDefinitionList = new ArrayList<BeanDefinition>();
		try {
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(new File(configPath));
			NodeList nodeList = doc.getElementsByTagName("bean");
			//分析处理每一个bean标签
			for (int i = 0; i < nodeList.getLength(); i ++) {
				Node node = nodeList.item(i);
				NamedNodeMap attributes = node.getAttributes();
				BeanDefinition beanDefinition = new BeanDefinition();
				beanDefinition.setName(attributes.getNamedItem("id").getNodeValue());//取得bean的id
				beanDefinition.setType(attributes.getNamedItem("class").getNodeValue());//取得class
				
				NodeList properties = node.getChildNodes();
				List<Map<String,Object>> propertyMapList = new ArrayList<Map<String,Object>>();
				//处理bean标签下的property标签
				for (int j = 0; j < properties.getLength(); j ++) {
					Node property = properties.item(j);
					Map<String,Object> propertyMap = new HashMap<String,Object>();
					if (property instanceof Element) {
						NamedNodeMap propertyAttributes = property.getAttributes();
						propertyMap.put("name",propertyAttributes.getNamedItem("name").getNodeValue());
						propertyMap.put("value",propertyAttributes.getNamedItem("value").getNodeValue());
						propertyMapList.add(propertyMap);
					}
				}
				beanDefinition.setProperties(propertyMapList);
				beanDefinitionList.add(beanDefinition);
			}
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return beanDefinitionList;
	}

  这段代码只是读取xml配置文件,并把相应的配置属性放到beanDefinition中,这里我们都把name,value写死在代码里面,这没关系,因为我们只是一个例子,但当你真正想做一个框架级别的东西,绝对不要这样。

我们的配置文件类似下面的:

<beans>
	<bean id="person" class="com.shun.test.Person" >
		<property name="name" value="shun"/>
		<property name="age" value="25" />
	</bean>
	
	<bean id="person2" class="com.shun.test.Person" >
		<property name="name" value="shun2" />
		<property name="age" value="24" />
	</bean>
</beans>

  我们就不搞那些什么schema和namespace了。

 

上面的代码应该不难理解,只是读取文件,然后解析bean标签,再接着解析property标签,保存name和value。

 

下面我们再来看看如何取得我们定义的bean,方法如下:

	@SuppressWarnings({  "rawtypes", "unchecked" })
	public Object getBean(String beanName){
		Object obj = null;
		//循环取得定义的bean TODO 这里考虑用map来实现会好点
		for (BeanDefinition beanDefinition:beanDefinitionList) {
			if (beanName.equals(beanDefinition.getName())) {
				String typeName = beanDefinition.getType();
				try {
					//通过指定的class类型生成对象
					Class bean = Class.forName(typeName);
					obj = bean.newInstance();
					List<Map<String,Object>> propertyMapList = beanDefinition.getProperties();
					//这里通过反射调用相应属性的set方法
					for (Map<String,Object> propertyMap:propertyMapList) {
						Method[] methods = bean.getMethods();
						for (Method method:methods){
							//这里取得所有方法,判断相应的setXXX方法,然后取得参数类型再执行
							if (("set"+DataUtils.capitalize(propertyMap.get("name").toString())).equals(method.getName())) {
								//取得set方法参数类型
								Class[] parameterTypes = method.getParameterTypes();
								if (parameterTypes[0].isAssignableFrom(String.class)) {
									method.invoke(obj, propertyMap.get("value"));
								} else {
									method.invoke(obj, Integer.valueOf(propertyMap.get("value").toString()));
								}
							}
						}
					}
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				} catch (InstantiationException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (SecurityException e) {
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			}
		}
		return obj;
	}

  这段代码主要是用了反射,通过配置的class属性,生成相应的类的实例,然后再根据property配置的name调用相应的set方法,然后再返回对象。因为没涉及到对象依赖,所以代码不复杂。

当然,当我们真正实现的时候,需要判断boolean,float,double等等类型,还有集合List,Array,Map,Properties等。这些都是我们现在没考虑的。

 

这几个方法都在我们的MyIocProcessor类中,它的代码如下:

package com.shun.bean;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.shun.utils.DataUtils;

public class MyIocProcessor {

	private List<BeanDefinition> beanDefinitionList;
	
	public MyIocProcessor(){}
	
	public MyIocProcessor(String configPath){
		this.beanDefinitionList = processConfig(this.getClass().getResource("/").getPath()+configPath);
	}
	
	//上面的两个方法,这里省略了
}

  这里处理的只是classpath里面的文件,根据传入的文件名,读取相应的xml文件,把读取的相应的bean信息放入到beanDefinitionList中,我们getBean的时候就根据它来取得。

 

我们例子中用到的bean只是一个简单的JAVABEAN:

package com.shun.test;

public class Person {

	private String name;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	public String toString(){
		return "Name:"+name+",Age:"+age;
	}
	
}

 

3)基本实现后,我们就来测试一下:

package com.shun.test;

import org.junit.Test;

import com.shun.bean.MyIocProcessor;


public class TestIoc {

	@Test
	public void test(){
		MyIocProcessor myIoc = new MyIocProcessor("beans.xml");
		Person person = (Person)myIoc.getBean("person2");
		System.out.println(person);
	}
	
}

  运行后,我们可以看到:

  我们可以修改,发现它都可以根据我们修改的值,打印出来,这证明我们的最基本的IOC是实现了,并且功能没问题。

 

依赖对象的注入,我们将会继续下来研究,如果大家有兴趣,可以自己研究。

 

最后再提醒大家,要注意身体,只有身体好,才谈得上赚钱。与广大javaeye上的朋友共勉。

  • 大小: 8.3 KB
0
0
分享到:
评论

相关推荐

    模拟Spring的IoC容器实现注解自动装配

    首先,我们需要理解IoC容器的基本工作原理。IoC容器是通过扫描应用程序上下文来发现所有需要管理的bean,并根据bean定义来创建和初始化这些bean。在Spring中,bean可以通过XML配置、Java配置或者注解进行定义。在...

    简单模拟springIoc容器

    首先,我们要了解IoC的基本概念。IoC是指应用程序的控制流程由框架接管,而不是由应用程序本身控制。在传统编程中,对象会自行创建和查找依赖的对象,而在IoC模式下,这些职责被反转,由外部容器负责创建对象以及...

    自定义ioc容器,spring ioc容易模拟程序

    下面,我们以一个简单的自定义IOC容器为例,说明其基本实现: ```java public class CustomIOCContainer { private Map, Object&gt; beanRegistry; public void registerBean(Class&lt;?&gt; clazz, Object instance) { ...

    MVC.net + IOC(Ninject) 示例源码

    3. **探索Ninject**: 熟悉Ninject的基本用法,如绑定、注入等。 4. **研究示例代码**: 分析"MvcIocDemo"中的每个组件,了解它们如何协同工作。 5. **实践项目**: 创建自己的MVC项目,尝试使用Ninject实现DI。 通过...

    手写ioc xml版和注解版 详情见说明save.txt

    当Spring容器找不到匹配的bean时,会尝试根据类型进行注入。 4. `@Qualifier`:配合`@Autowired`一起使用,当有多个相同类型的bean时,可以通过指定bean的名称来精确注入。 5. `@Value`:可以直接注入基本类型的值或...

    尚学堂_Spring_0600_IOC_Bean_Scope

    通过以上讲解,我们已经涵盖了Spring框架中IOC的基本概念以及Bean Scope的相关知识。理解这些内容对于开发和维护基于Spring的应用来说至关重要,它们将帮助你更好地掌握Spring容器对对象的管理和控制,从而提升你的...

    Spring-IoC-Learning:手动实现IoC容器

    在本文中,我们将探讨Spring IoC的基本概念、工作流程,并尝试手动实现一个简单的IoC容器。 首先,了解IoC的概念至关重要。IoC是一种设计模式,它将对象的创建和管理权从代码中分离出来,转交给一个外部容器(即IoC...

    自己写的类struts的简易的mvc实现+一个类Spring的IOC和简单AOP

    标题中的“自己写的类Struts的简易的MVC实现+一个类Spring的IOC和...对于有经验的开发者,这是一个有趣的尝试,可以了解如何从头实现这些复杂机制。通过研究这个实现,可以加深对软件设计原则的理解,提升编码能力。

    利用Spring IOC技术实现用户登录验证机制

    最后,当用户尝试登录时,他们的输入会被传递到`TestUtil`控制器的`handleRequestInternal`方法中。如果输入的用户名和密码与配置的`User`对象中的信息匹配,那么用户将被重定向到登录成功页面;否则,他们会看到...

    mytinyspring

    实际的Spring框架还提供了更多高级功能,如自动扫描、类型安全的依赖注入、事件传播、AOP代理等,这些都是在基本IoC容器的基础上扩展的。 总结起来,Spring的IoC容器是一个强大的工具,它通过反转控制权,简化了...

    scrape_pdf:从 PDF 中提取各种 IOC 的 Python 脚本

    基于使用 PDFMiner 解压缩流,然后查看流内部的基本脚本 目前,它尝试提取 IP、哈希、URL 和主机名。 要求: pip 安装 dnspython 从获取 uniaccept pip安装pdfminer 完成此操作后,您可能希望获得最新的 TLD ...

    tiny-spring:一个很小的IoC容器指的是Spring

    一个很小的IoC容器是指Spring。 关于 tiny-spring是为了学习Spring的而开发的,可以认为是一个Spring的精简版。Spring的代码很多,层次复杂,阅读起来费劲。我尝试从使用功能的角度出发,参考Spring的实现,一步一步...

    spring快速入门教程

    Spring框架是Java开发中最常用的轻量级框架之一,尤其在企业级应用开发中扮演着核心角色。本教程将带你深入理解...记得实践是检验真理的唯一标准,理论学习后,尝试自己动手编写Spring项目,将理论转化为实际技能。

    javase笔记javaSE的基本知识

    首先,了解基本的Java术语是学习Java的第一步。例如,`Struts`是一个用于构建MVC(模型-视图-控制器)架构的开源框架,它的最新版本是Struts2,能够简化Web开发。`JSP`(Java Server Pages)是一种动态网页技术,...

    Spring系列面试题129道(附答案解析)

    - Spring Core Container:包含了Spring框架的基本组成部分,如IoC容器和依赖注入功能。 - Spring AOP:为面向切面的编程提供支持,允许定义方法拦截器和切点,以分离应用的业务逻辑。 - Spring MVC:提供了构建Web...

    spring第二天.pdf

    - 学习以上接口和类的作用后,可以尝试构建自己的IoC模块,模拟Spring的Bean管理功能,加深对Spring核心机制的理解。 9. **源码阅读**: - 掌握源码阅读能力对于深入理解Spring至关重要。可以从BeanDefinition的...

    et-framework.zip

    如果应用只需基本的IoC/DI 支持,引入et-service.jar和et-common.jar 文件就可以了。 3 et-web  这个jar 文件包含ET MVC 框架相关的所有类。包括框架的Servlets,Web MVC框架,控制器和视图...

    用300行代码手写Spring V1.0版本

    我们可以尝试实现一个简单的BeanFactory接口,用于管理这些对象。 其次,Spring的AOP功能允许我们在不修改原有业务代码的情况下,插入额外的处理逻辑,如日志记录、事务管理等。在300行代码中,这可能通过定义切面...

    zdy-spring.rar

    通过以上步骤,我们可以手写一个简单的Spring框架,实现IOC和AOP的基本功能。虽然这仅是Spring庞大功能集的一个微小部分,但它足以让我们理解Spring的核心思想,为后续深入学习和使用Spring打下基础。在实际项目中,...

    spring源码缺失的jar包

    然而,有时当我们尝试导入Spring的源码时,可能会遇到编译错误,这通常是因为缺少了必要的依赖jar包。这两个关键的jar包对于理解Spring的工作原理以及进行自定义扩展至关重要。 Spring框架的核心组件依赖于多个第三...

Global site tag (gtag.js) - Google Analytics