近两个月一直被肠胃病折磨着,痛苦了好久,这段时间稍微好点了。身体不好,技术也就放下了。搞技术的朋友们啊,要保重好自己的身体啊,年轻并不代表可以挥霍健康。
好了,废话少说,今天,这几天尝试自己写了一点点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
分享到:
相关推荐
首先,我们需要理解IoC容器的基本工作原理。IoC容器是通过扫描应用程序上下文来发现所有需要管理的bean,并根据bean定义来创建和初始化这些bean。在Spring中,bean可以通过XML配置、Java配置或者注解进行定义。在...
首先,我们要了解IoC的基本概念。IoC是指应用程序的控制流程由框架接管,而不是由应用程序本身控制。在传统编程中,对象会自行创建和查找依赖的对象,而在IoC模式下,这些职责被反转,由外部容器负责创建对象以及...
下面,我们以一个简单的自定义IOC容器为例,说明其基本实现: ```java public class CustomIOCContainer { private Map, Object> beanRegistry; public void registerBean(Class<?> clazz, Object instance) { ...
3. **探索Ninject**: 熟悉Ninject的基本用法,如绑定、注入等。 4. **研究示例代码**: 分析"MvcIocDemo"中的每个组件,了解它们如何协同工作。 5. **实践项目**: 创建自己的MVC项目,尝试使用Ninject实现DI。 通过...
当Spring容器找不到匹配的bean时,会尝试根据类型进行注入。 4. `@Qualifier`:配合`@Autowired`一起使用,当有多个相同类型的bean时,可以通过指定bean的名称来精确注入。 5. `@Value`:可以直接注入基本类型的值或...
通过以上讲解,我们已经涵盖了Spring框架中IOC的基本概念以及Bean Scope的相关知识。理解这些内容对于开发和维护基于Spring的应用来说至关重要,它们将帮助你更好地掌握Spring容器对对象的管理和控制,从而提升你的...
在本文中,我们将探讨Spring IoC的基本概念、工作流程,并尝试手动实现一个简单的IoC容器。 首先,了解IoC的概念至关重要。IoC是一种设计模式,它将对象的创建和管理权从代码中分离出来,转交给一个外部容器(即IoC...
标题中的“自己写的类Struts的简易的MVC实现+一个类Spring的IOC和...对于有经验的开发者,这是一个有趣的尝试,可以了解如何从头实现这些复杂机制。通过研究这个实现,可以加深对软件设计原则的理解,提升编码能力。
最后,当用户尝试登录时,他们的输入会被传递到`TestUtil`控制器的`handleRequestInternal`方法中。如果输入的用户名和密码与配置的`User`对象中的信息匹配,那么用户将被重定向到登录成功页面;否则,他们会看到...
实际的Spring框架还提供了更多高级功能,如自动扫描、类型安全的依赖注入、事件传播、AOP代理等,这些都是在基本IoC容器的基础上扩展的。 总结起来,Spring的IoC容器是一个强大的工具,它通过反转控制权,简化了...
基于使用 PDFMiner 解压缩流,然后查看流内部的基本脚本 目前,它尝试提取 IP、哈希、URL 和主机名。 要求: pip 安装 dnspython 从获取 uniaccept pip安装pdfminer 完成此操作后,您可能希望获得最新的 TLD ...
一个很小的IoC容器是指Spring。 关于 tiny-spring是为了学习Spring的而开发的,可以认为是一个Spring的精简版。Spring的代码很多,层次复杂,阅读起来费劲。我尝试从使用功能的角度出发,参考Spring的实现,一步一步...
Spring框架是Java开发中最常用的轻量级框架之一,尤其在企业级应用开发中扮演着核心角色。本教程将带你深入理解...记得实践是检验真理的唯一标准,理论学习后,尝试自己动手编写Spring项目,将理论转化为实际技能。
首先,了解基本的Java术语是学习Java的第一步。例如,`Struts`是一个用于构建MVC(模型-视图-控制器)架构的开源框架,它的最新版本是Struts2,能够简化Web开发。`JSP`(Java Server Pages)是一种动态网页技术,...
- Spring Core Container:包含了Spring框架的基本组成部分,如IoC容器和依赖注入功能。 - Spring AOP:为面向切面的编程提供支持,允许定义方法拦截器和切点,以分离应用的业务逻辑。 - Spring MVC:提供了构建Web...
- 学习以上接口和类的作用后,可以尝试构建自己的IoC模块,模拟Spring的Bean管理功能,加深对Spring核心机制的理解。 9. **源码阅读**: - 掌握源码阅读能力对于深入理解Spring至关重要。可以从BeanDefinition的...
如果应用只需基本的IoC/DI 支持,引入et-service.jar和et-common.jar 文件就可以了。 3 et-web 这个jar 文件包含ET MVC 框架相关的所有类。包括框架的Servlets,Web MVC框架,控制器和视图...
我们可以尝试实现一个简单的BeanFactory接口,用于管理这些对象。 其次,Spring的AOP功能允许我们在不修改原有业务代码的情况下,插入额外的处理逻辑,如日志记录、事务管理等。在300行代码中,这可能通过定义切面...
通过以上步骤,我们可以手写一个简单的Spring框架,实现IOC和AOP的基本功能。虽然这仅是Spring庞大功能集的一个微小部分,但它足以让我们理解Spring的核心思想,为后续深入学习和使用Spring打下基础。在实际项目中,...
然而,有时当我们尝试导入Spring的源码时,可能会遇到编译错误,这通常是因为缺少了必要的依赖jar包。这两个关键的jar包对于理解Spring的工作原理以及进行自定义扩展至关重要。 Spring框架的核心组件依赖于多个第三...