所用的环境 :dom4j spring 2.5.6 ,用的有:spring.jar dom4j.jar common-logging.jar
采用Junit-4对应用进行单元测试。并且采用面向接口编程(抽象出接口层)
Spring的配置文件:beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!--实例化bean,实现控制反转,即由spirng容器负责创建对象-->
<bean id="personService" class="com.sgl.imp.PersonServiceBean" ></bean>
<!--通过set方法进行依赖注入-->
<bean id="daoPerson" class="com.sgl.dao.imp.PersonDaoBean"></bean>
<bean id="personService4" class="com.sgl.imp.PersonServiceBean">
<property name="personDao" ref="daoPerson"></property>
</bean>
</beans>
所用到java源文件如下 :
1、自定义应用上下文(核心)
package sgl.spring.principle;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
/**
*
* @author administrator
*/
public class SglClassPathXmlApplicationContext {
private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();//存放所有的bean实例
private Map<String, Object> sinletons = new HashMap<String, Object>();//存放bean与之相关联的类实例的映射
public SglClassPathXmlApplicationContext(String fileName) {
this.readXml(fileName);
this.instanceBeans();
this.injectObject();
}
/**
* 读取xml配置文件
* @param fileName 配置文件名
*/
private void readXml(String fileName) {
SAXReader saxReader = new SAXReader();
Document document = null;
URL xmlPath = this.getClass().getClassLoader().getResource(fileName);
try {
document = saxReader.read(xmlPath);
Map<String, String> nsMap = new HashMap<String, String>();
nsMap.put("ns", "http://www.springframework.org/schema/beans");//加入命名空间
XPath xsub = document.createXPath("//ns:beans/ns:bean");//创建/beans/bean查询路径
xsub.setNamespaceURIs(nsMap);//设置命名空间
List<Element> beans = xsub.selectNodes(document);//获取文档下所有bean
for (Element element : beans) {
String id = element.attributeValue("id");//获取bean 的id属性
String className = element.attributeValue("class");//获取bean的class属性
XPath propertyPath = element.createXPath("ns:property");//创建bean/property查询路径
propertyPath.setNamespaceURIs(nsMap);//设置命名空间和根元素一致
List<Element> propertys = propertyPath.selectNodes(element);//取得element(即bean)下所有property
BeanDefinition beanDefine = new BeanDefinition(id, className);//实例化一个bean
//设置property的属性,因为可能有多个property,所以用循环
for (Element property : propertys) {
String name = property.attributeValue("name");//获得property的name属性
String ref = property.attributeValue("ref");//获得property的ref属性
System.out.println("" + name + " " + ref);
PropertyDefinition propertyDefine = new PropertyDefinition(name, ref);
beanDefine.getPropertys().add(propertyDefine);
}
beanDefines.add(beanDefine);//将bean实例加入数组中
}
} catch (Exception ex) {
Logger.getLogger(SglClassPathXmlApplicationContext.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* 完成bean实例化
*/
private void instanceBeans() {
System.out.println("实例化开始");
for (BeanDefinition beanDefine : beanDefines) {
if (beanDefine.getClassName() != null && !"".equals(beanDefine.getClassName().trim())) {
try {
//利用java反射技术来取得java类实例
System.out.println("beanID " + beanDefine.getId());
sinletons.put(beanDefine.getId(), Class.forName(beanDefine.getClassName()).newInstance());
} catch (Exception ex) {
Logger.getLogger(SglClassPathXmlApplicationContext.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
System.out.println("实例化结束");
}
/**
* 获取bean实例
* @param beanName
* @return
*/
public Object getBean(String beanName) {
return this.sinletons.get(beanName);
}
private void injectObject() {
for (BeanDefinition beanDefine : beanDefines) {//遍历所有的<bean>,因为所有的<bean>右能都有property属性
Object bean = getBean(beanDefine.getId());//由bean的id,取得bean实例
if (bean != null) {
try {
//如果从<property>中取出的属性(存储在name字段中)在<bean>所对应类的属性(字段),也就是说我们一定人保证
//<property name="属性"………………>中的“属性”在<bean>所指向类中有对应的定义
//取得bean对应类的所有属性的描述(即bean类定义的所有字段)
PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
for (PropertyDefinition property : beanDefine.getPropertys()) {//一个bean可以有多个<property>
//PropertyDescriptor中有很多字段,找出与<property name="属性">所对应的字段
for (PropertyDescriptor propertyDes : ps) {//propertyDes是<bean>所指向类的定义字段的描述
System.out.println("ps "+propertyDes.getName());
//如果property的name字段在<bean>有对应字段的定义,就进行注入
if (property.getName().equals(propertyDes.getName())) {
//根据propety中的ref属性进行依赖
//取得当前bean类的property属性的name属性对应值的属性(在此指personDao)setter方法
Method setter = propertyDes.getWriteMethod();
//取得ref对应类实例
if (setter != null) {
Object value = sinletons.get(property.getRef());
setter.setAccessible(true);//让私有方法变得透明
setter.invoke(bean, value);
}
break;//找到对应属性,其它的属性不用比较
}
}
}
} catch (Exception ex) {
Logger.getLogger(SglClassPathXmlApplicationContext.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
2、PersonDao.java(接口程序)
package com.sgl.dao;
public interface PersonDao {
void add();
}
3、PersonDaoBean.java(接口层实现程序)
package com.sgl.dao.imp;
import com.sgl.dao.PersonDao;
public class PersonDaoBean implements PersonDao {
public void add(){
System.out.println("执行PersonDaoBean中add()方法");
}
}
4、 PersonService.java(业务层接口)
package com.sgl;
public interface PersonService {
void save();
void save2();
}
5、PersonServiceBean.java(业务层实现程序)
package com.sgl.imp;
import com.sgl.PersonService;
import com.sgl.dao.PersonDao;
public class PersonServiceBean implements PersonService {
private PersonDao personDao;
public void save(){
System.out.println("我是PersonServiceBean中的save()方法");
personDao.add();
}
public void save2(){
System.out.println("这是PersonServiceBean中的Save2方法");
}
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
}
6配置文件中,对应属性的类封装( id、class、property)
1)、BeanDefinition.java
package sgl.spring.principle;
import java.util.ArrayList;
import java.util.List;
public class BeanDefinition {
private String id;
private String className;
private List<PropertyDefinition> propertys=new ArrayList<PropertyDefinition>();
public BeanDefinition() {
}
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> getPropertys() {
return propertys;
}
public void setPropertys(List<PropertyDefinition> propertys) {
this.propertys = propertys;
}
}
2)、PropertyDefinition.java(<property>的定义)
package sgl.spring.principle;
public class PropertyDefinition {
private String name;
private String ref;
public PropertyDefinition(String name, String ref) {
this.name = name;
this.ref = ref;
}
public PropertyDefinition() {
}
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;
}
}
7、单元测试类文件 SglSpringTest.java,是junit-4.x
package junit.test;
import com.sgl.PersonService;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import sgl.spring.principle.SglClassPathXmlApplicationContext;
public class SglSpringTest {
public SglSpringTest() {
}
@BeforeClass
public static void setUpClass() throws Exception {
}
@AfterClass
public static void tearDownClass() throws Exception {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
@Test
public void instanceBeans() {
SglClassPathXmlApplicationContext ctx=new SglClassPathXmlApplicationContext("beans.xml");
//测试控制反转,即由容器创建对象
PersonService personService=(PersonService)ctx.getBean("personService");
personService.save2();
//测试控制反转和依赖注入
PersonService personService4=(PersonService)ctx.getBean("personService4");
personService4.save();
}
}