上篇我们自己写了一个很简单的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. python元类分析

    刚開始接触到Python新式类中的元类的概念的时候非常是纠结了下..不知道这是个啥东西... 用下面几个定义来说明吧: (1)Python中,类也是对象..仅仅只是这样的对象比較的特殊,他用于创建别的 ...

  2. Android设备连接Unity Profiler性能分析器

    Unity提供两种方式让Developer的Android设备连接Profiler进行性能分析: 1.通过wifi,Android设备和计算机处于同一个Wlan中. 2.通过USB ADB 普通情况我 ...

  3. GDI+ 摘要: 保存图像文件

    要保存图像文件,必须先获得图像的编码格式信息.可是GDI+没有直接提供这个函数:GetEncoderClsid(const WCHAR* format, CLSID* pClsid) 因此须要我们自己 ...

  4. 删除sql server中重复的数据

    原文:删除sql server中重复的数据 with list_numbers as( select Name, AuthorOrTime, Url, Price, EstimatePrice, Si ...

  5. .Net类的序列化和反序列化 - 进阶者系列 - 学习者系列文章

    今天看了下以前的一个工具的代码,其中涉及到.NET类的序列化和反序列化问题,所以就写一下. 这里说一下.NET类序列化的好处..NET类在序列化之前只是一个相对狭义的类.通过序列化,能够更好的保存该类 ...

  6. css3学习文档

    什么是CSS3? CSS3是CSS2的升级版本,3只是版本号,它在CSS2.1的基础上增加了很多强大的新功能. 目前主流浏览器chrome.safari.firefox.opera.甚至360都已经支 ...

  7. 我的Android 4 学习系列之使用 Internet 资源

    目录 连接Internet资源 分析XML资源 使用Download Manager下载文件 查询Download manager 使用Account Manager 对 Google App Eng ...

  8. 《互联网初创企业password》书评

    今天试用了一下<互联网初创企业password>这本书.我觉得这本书开始的很真实,从学校刚毕业那会儿.它是生命,他们的牛b时间,一直想做点什么来证明自己.具体地,并且现在是在最好的时候.互 ...

  9. Hudson+Maven+Svn搭建持续集成环境

    Hudson+Maven+Svn搭建持续集成环境 博客分类: 配置管理 mavenSVNTomcat项目管理配置管理 一.所用开发工具 1.    Hudson: Hudson 是一种革命性的开放源码 ...

  10. 百度Web App在线生成平台Site App体验

    最近收到百度开发者中心邮件,告知之前的百度移动建站服务已经升级为Site App了,Site  App顾名思义是可以创建APP的站点,之前想建立一个APP要么是自己制作,要么是选用国外的在线Web A ...