上篇我们自己写了一个很简单的spring容器,该容器只是做了简单的bean的实例化,并没有spring的核心之一的IOC(依赖注入),也叫做控制反转,这里我就不讲这个的具体含义,不知道的园友可以自行百度,百度上有很多介绍spring IOC的,在这里我们要实现的就是spring的IOC

首先,我们需要准备一个bean的配置文件,在上篇额配置文件基础上加入了Dao的内容,现在我们要做的就是service对Dao的依赖注入。

1   <bean id="personService" class="com.yangyang.service.impl.PersonServiceImpl">
<property name="personDao" ref="personDao"></property>
<property name="age" value="10"></property>
</bean>
<bean id="personDao" class="com.yangyang.dao.impl.PersonDaoImpl">
</bean>

分析这个xml文件,知需要建立一个PropertyDefinition类,用来存储Property的属性,在此只列举了name,ref,value三个简单的属性,对集合类型的属性暂时没有做处理。

 package com.juit;

 /**
* 属性模型
* @author Administer
*
*/
public class PropertyDefinition { /**
* 属性名称
*/
private String name;
/**
* 属性引用值
*/
private String ref; /**
* 属性value值
*/
private String value;
public PropertyDefinition(String name, String ref,String value) {
this.name = name;
this.ref = ref;
this.value=value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRef() {
return ref;
}
public void setRef(String ref) {
this.ref = ref;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
};
}

当然,由于property 在bean 的下面,因此需要在BeanDefinition中加入PropertyDefinition:

完整的BeanDefinition如下:

 package com.juit;

 import java.util.ArrayList;
import java.util.List; /**
* Bean对象
* @author Administer
*
*/
public class BeanDefinition { private String id;//bean的id
private String className;//bean的类
private List<PropertyDefinition> propertyDefinitions=new ArrayList<PropertyDefinition>();//bean对象的属性 public BeanDefinition(String id, String className) {
this.id = id;
this.className = className;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public List<PropertyDefinition> getPropertyDefinitions() {
return propertyDefinitions;
}
public void setPropertyDefinitions(List<PropertyDefinition> propertyDefinitions) {
this.propertyDefinitions = propertyDefinitions;
}
}

并在解析xml文件的地方加入对property的解析,完整的readXml如下:

 private void readXml2(String fileName) {
//创建一个读取器
SAXReader saxReader=new SAXReader();
Document document=null;
try {
//获取要读取的配置文件的路径
URL xmlPath=this.getClass().getClassLoader().getResource(fileName);
//读取文件内容
document=saxReader.read(xmlPath);
//获取xml中的根元素
Element rootElement=document.getRootElement();
for (Iterator iterator = rootElement.elementIterator(); iterator.hasNext();) {
Element element = (Element) iterator.next();
String id=element.attributeValue("id");//获取bean的id属性值
String clazz=element.attributeValue("class");//获取bean的class属性值
BeanDefinition beanDefinition=new BeanDefinition(id,clazz);
//获取bean的Property属性
for (Iterator subElementIterator = element.elementIterator(); subElementIterator.hasNext();) {
Element subElement = (Element) subElementIterator.next();
String propertyName=subElement.attributeValue("name");
String propertyRef= subElement.attributeValue("ref");
String propertyValue=subElement.attributeValue("value");
PropertyDefinition propertyDefinition=new PropertyDefinition(propertyName, propertyRef,propertyValue);
beanDefinition.getPropertyDefinitions().add(propertyDefinition);
}
beanDefines.add(beanDefinition);
}
} catch (Exception e) {
e.printStackTrace();
}
}
接下来就要来实现关键的对依赖对象的注入功能的逻辑了。
 public YhdClassPathXmlApplicationContext(String fileName){

         //1.读取spring的配置文件
this.readXml(fileName);
//2.实例化bean
this.instanceBeans();
//3.实现对依赖对象的注入功能
this.injectObject();
}

下面来完成injectObject这个功能:

 /**
* 为bean对象的属性注入值
*
* Administer
* 2013-8-18 下午7:59:03
*/
private void injectObject() {
//遍历配置文件中定义的所有的bean
for (BeanDefinition beanDefinition : beanDefines) {
//找到要注入的bean
Object bean=sigletons.get(beanDefinition.getId());
if (bean != null) {
try {
BeanInfo info = Introspector.getBeanInfo(bean.getClass());//通过类Introspector的getBeanInfo方法获取对象的BeanInfo 信息
//通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反射机制来调用这些方法。
PropertyDescriptor[] pds = info.getPropertyDescriptors();//获得 bean所有的属性描述
//遍历要注入的bean的所有属性
for (PropertyDefinition propertyDefinition : beanDefinition.getPropertyDefinitions()) {
//遍历要注入bean通过属性描述器得到的所有属性以及行为
for (PropertyDescriptor propertyDescriptor : pds) {
//用户定义的bean属性与java内省后的bean属性名称相同时
if (propertyDefinition.getName().equals(propertyDescriptor.getName())) {
Method setter=propertyDescriptor.getWriteMethod();//获取属性的setter方法
//取到了setter方法
if (setter != null) {
Object value=null;//用来存储引用的值
if (propertyDefinition.getRef() != null && !propertyDefinition.getRef().equals("")) {
value=sigletons.get(propertyDefinition.getRef());//获取引用的对象的值
}else {
//ConvertUtil依赖两个jar包,一个是common-beanutils,而common-beanutils又依赖common-logging
//ConvertUtil将任意类型转化为需要的类型
value=ConvertUtils.convert(propertyDefinition.getValue(), propertyDescriptor.getPropertyType());
}
setter.setAccessible(true);//保证setter方法可以访问私有
try {
setter.invoke(bean, value);//把引用对象注入到属性
} catch (Exception e) {
e.printStackTrace();
}
}
break;//找到了注入的属性后,跳出循环
}
}
}
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
}
}

这里用到了commons-beanutils-core-1.8.3.jar、commons-logging-1.1.1.jar这两个jar,大家可以到apache的网站上进行下载,主要是用到了ConvertUtils.convert将任意类型转化为需要的类型的方法。

其实依赖注入的思想也很简单,它是通过反射机制实现的。

最后还剩下一步测试,同理

     @Test
public void testInstanceSping() {
YhdClassPathXmlApplicationContext ctx=new YhdClassPathXmlApplicationContext("resources/beans.xml");
PersonService personService=(PersonService)ctx.getBean("personService");
personService.savePerson();
}

personService接口代码:

 package com.yangyang.service;

 public interface PersonService {
public void savePerson(); }

PersonServiceImpl实现的代码:

 package com.yangyang.service.impl;

 import com.yangyang.dao.PersonDao;
import com.yangyang.service.PersonService; public class PersonServiceImpl implements PersonService{
private PersonDao personDao;
private Integer age; public PersonDao getPersonDao() {
return personDao;
} public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} @Override
public void savePerson() {
System.out.println("age:"+age);
System.out.println("service中的save方法调用成功");
personDao.savePerson();
} }

在控制台上我们可以看到:

age:10

service中的save方法调用成功

好,这样依赖注入就完成了,下篇就要来实现比这个稍微复杂的注解的依赖注入的实现,敬请期待。。。

自己动手写spring容器(2)的更多相关文章

  1. 自己动手写spring容器(3)

    好久没有写博客了,今天闲下来将之前未完成的表达出来. 在之前的文章自己动手写spring容器(2)中完成了对spring的依赖注入的实现,这篇将会介绍spring基于注解的依赖注入的实现. 在一般的J ...

  2. 自己动手写spring容器(1)

    毕业刚刚一年多一点,毕业了后也顺利的进入了一家著名的互联网公司,做的是后台系统,用的呢也是SSI(struts2,spring)框架,平时做做项目,也已足够了,但是感觉越来越没动力了,越来越没有激情了 ...

  3. 自己动手写Spring框架--IOC、MVC

    对于一名Java开发人员,我相信没有人不知道 Spring 框架,而且也能够轻松就说出 Spring 的特性-- IOC.MVC.AOP.ORM(batis). 下面我想简单介绍一下我写的轻量级的 S ...

  4. 自己动手编写spring IOC源码

    前言:对于spring IOC概念不是很了解的朋友可以阅读我上一篇博客--轻松理解spring IOC(这两篇博客也是由于我的个人原因导致现在才发布,惭愧啊).通过这篇博客的理解之后,相信大家会对sp ...

  5. [原]容器学习(一):动手模拟spring的IoC

    介绍 学习经典框架的实现原理以及设计模式在其实际中的运用,是非常有必要的,可以让我们更好进行面向对象. 本篇文章就来模拟Spring的IOC功能,明白原理后,可以更好的使用它,进而为进行面向对象提供一 ...

  6. 容器学习(一):动手模拟spring的IoC

    介绍 学习经典框架的实现原理以及设计模式在事实上际中的运用,是很有必要的,能够让我们更好进行面向对象. 本篇文章就来模拟Spring的IOC功能.明确原理后,能够更好的使用它,进而为进行面向对象提供一 ...

  7. 我自横刀向天笑,手写Spring IOC容器,快来Look Look!

    目录 IOC分析 IOC是什么 IOC能够带来什么好处 IOC容器是做什么工作的 IOC容器是否是工厂模式的实例 IOC设计实现 设计IOC需要什么 定义接口 一:Bean工厂接口 二:Bean定义的 ...

  8. 手写Spring,定义标记类型Aware接口,实现感知容器对象

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 同事写的代码,我竟丝毫看不懂! 大佬的代码,就像 "赖蛤蟆泡青蛙,张的丑玩 ...

  9. 自己动手开发IOC容器

    前两天写简历.写了一句:精通Spring IoC容器.怎么个精通法?还是自己动手写个IOC容器吧. 什么是IoC(Inversion of Control)?什么是DI(Dependency Inje ...

随机推荐

  1. CSS3 制作向左、向右及关闭图标的效果

    先看一下效果 1.鼠标移入前的效果 2.鼠标移入的效果 3.制作步骤如下: 轮廓的CSS,就是利用圆角和宽度高度,制作出一个圆: <style> /*显示方式为 inline-block* ...

  2. NGUI使用教程(2) 使用NGUI创建2D场景而且加入标签和button

    1.创建2D场景 要使用NGUI创建2D场景,首先咱们必须新建一个项目,而且导入NGUI作为这个项目的插件,相信假设看过上一篇教程都知道怎么导入NGUI了,这里就不赘述,假设有疑问的能够去看上一篇教程 ...

  3. POJ 1947 树DP获得冠军

    特定N点,N-1的关系.建立了一棵树,问至少减去几个边缘节点可以被作为得到P树.树典型DP称号 dp[cur][j] :记录cur节点,为了得到一个j除去该子树的节点的边的最小数目 对当前树的每个子树 ...

  4. SQL Server 数据库定时自动备份

    原文:SQL Server 数据库定时自动备份 SQL Server 数据库定时自动备份——每天定时备份,保留前8天的备份 利用SQL Server代理新建作业来定期备份 1)在数据库库的[SQL S ...

  5. mysql基础之对库表操作

    原文:mysql基础之对库表操作 查看一下所有的库,怎么办? Mysql>Show databases; 选库语句: Use 库名 创建一个数据库: create database 数据库名 [ ...

  6. android的版本控制

    在一个团队项目中,项目的版本控制,一方面促进团队的协同能力,另一方面提高项目的进度 即使一个人的项目也最好使用SVN这样的版本控制,可以清楚的知道自己的修改的代码,和项目进度等.合理的托管,也让优秀的 ...

  7. Date与SimpleDateFormat

    Date常用的方法 返回类型 方法名称 备注 Date New Date() 创建当前日期对象 Date New date(long dt) 使用自1970.1.1以后的指定毫秒数创建日期 boole ...

  8. Mysql 嵌套游标添以及任意位置声明变量的方法

    在写存储过程的时候,会遇到某个游标的筛选条件来自于 先前语句运行的结果,比较常见的方式是 再写一个存储过程,通过调用来完成 动态参数的配置, 或者使用 动态sql的功能,而这两种方式都不能很好的解决这 ...

  9. javaIO流实现读写txt文件

    javaIO流实现文件读写 文件写入: InputStreamReader BufferedReader 文件读取: FileOutputStream package javatest.basic22 ...

  10. 一个Shift的后门程序,可以让你可以进入你不知道密码的电脑

    1.前提 你可以在平时亲身接触状态电脑,哪怕是在电脑主人不在的时候(虽然主人不在,或者关机了,进入电脑是要密码的). 2.原理 利用电脑连续按5次Shift会触发粘滞键,它会运行c:\winows\s ...