自己动手写spring容器(2)
2013-08-27 23:18
351 查看
上篇我们自己写了一个很简单的spring容器,该容器只是做了简单的bean的实例化,并没有spring的核心之一的IOC(依赖注入),也叫做控制反转,这里我就不讲这个的具体含义,不知道的园友可以自行百度,百度上有很多介绍spring IOC的,在这里我们要实现的就是spring的IOC
首先,我们需要准备一个bean的配置文件,在上篇额配置文件基础上加入了Dao的内容,现在我们要做的就是service对Dao的依赖注入。
分析这个xml文件,知需要建立一个PropertyDefinition类,用来存储Property的属性,在此只列举了name,ref,value三个简单的属性,对集合类型的属性暂时没有做处理。
当然,由于property 在bean 的下面,因此需要在BeanDefinition中加入PropertyDefinition:
完整的BeanDefinition如下:
并在解析xml文件的地方加入对property的解析,完整的readXml如下:
下面来完成injectObject这个功能:
这里用到了commons-beanutils-core-1.8.3.jar、commons-logging-1.1.1.jar这两个jar,大家可以到apache的网站上进行下载,主要是用到了ConvertUtils.convert将任意类型转化为需要的类型的方法。
其实依赖注入的思想也很简单,它是通过反射机制实现的。
最后还剩下一步测试,同理
personService接口代码:
PersonServiceImpl实现的代码:
在控制台上我们可以看到:
age:10
service中的save方法调用成功
好,这样依赖注入就完成了,下篇就要来实现比这个稍微复杂的注解的依赖注入的实现,敬请期待。。。
首先,我们需要准备一个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容器(1)
- 自己动手写个spring IOC容器
- 自己动手写spring容器(3)
- 自己动手写个spring IOC容器
- 自己动手搭建一个简易的SpringBoot环境
- 自己动手写一个Spring (Spring 到底是怎么跑起来的)
- 自己动手写Web容器之TomJetty之一:服务内功经脉
- 自己动手写Web容器之TomJetty之五:包装请求参数
- Spring(二)自己动手模拟spring
- 自己动手写代码,整合Spring和Hibernate(二)之配置数据源
- 自己动手写Web容器之TomJetty之一:服务内功经脉
- Spring Boot部署至自己的Tomcat容器
- 自己动手实现Spring IoC框架
- 自己动手写一个SpringIOC!
- 容器学习(一):动手模拟spring的IoC
- 动手实现自己的 STL 容器《2》---- list
- Java程序员从笨鸟到菜鸟之(六十八)细谈Spring(二)自己动手模拟spring
- spring - 自己动手写spring
- 自己动手写ASP.NET的IOC容器!
- 深入理解Spring--动手实现一个简单的SpringIOC容器-非注解版