下面我们使用模拟spring容器,来完成Spring容器基本类型的注入,还是使用 ItcastClassPathXMLApplicationContext.java 来模拟spring 容器 注入String类型,int类型.等基本类型,以前我们都是注入的ref引用的 依赖对象
步骤:首先给PersionServiceBean.java 增加string 类型的变量 name,和int类型的变量 age
package cn.com.xinli.service.impl;
import org.apache.log4j.Logger;
import cn.com.xinli.dao.PersionDao;
import cn.com.xinli.service.PersionSevice;
public class PersionServiceBean implements PersionSevice
{
Logger log=Logger.getLogger(PersionServiceBean.class);
private PersionDao persionDao;
private String name;
private int age;
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public PersionDao getPersionDao()
{
return persionDao;
}
public void setPersionDao(PersionDao persionDao)
{
this.persionDao = persionDao;
}
public void init()
{
log.info("初始化资源");
}
public PersionServiceBean()
{
log.info("我被实例化了");
}
public void save()
{
log.info("name:"+name);
log.info("age:"+age);
this.persionDao.add();
}
public void destory()
{
log.info("释放资源");
}
}
(2) 修改 ItcastClassPathXMLApplicationContext 容器代码,主要是修改在容器读beans.xml配置文件的时候读到属性的值,和在注入时候完成对基本类型的注入.还需要修改 PropertyDefinition.java 加上一个value属性,和get,set方法 .
package junit.test;
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 org.apache.commons.beanutils.ConvertUtils;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
import org.springframework.core.Conventions;
/**
* 实现的spring容器一样的功能
*
*/
public class ItcastClassPathXMLApplicationContext
{
Logger log=Logger.getLogger(ItcastClassPathXMLApplicationContext.class);
private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();
private Map<String, Object> sigletons = new HashMap<String, Object>();
public ItcastClassPathXMLApplicationContext(String filename){
this.readXML(filename);
this.instanceBeans();
this.injectObject();
}
/**
* 为属性注入值
*/
private void injectObject()
{
for(BeanDefinition beanDefinition : beanDefines){
Object bean = sigletons.get(beanDefinition.getId());
if(bean!=null)
{
try
{
//得到bean对象所有的属性声明,返回的是一个数组
PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
for(PropertyDefinition propertyDefinition : beanDefinition.getPropertys())
{
for(PropertyDescriptor properdesc : ps)
{
//如果xml中读取的属性名字是bean对象属性的名字
if(propertyDefinition.getName().equals(properdesc.getName()))
{
//setter方法是写方法
Method setter = properdesc.getWriteMethod();
//获取属性的setter方法 ,如果方法是private需要调用
if(setter!=null)
{
if(propertyDefinition.getRef()!=null && !"".equals(propertyDefinition.getRef()))
{
Object value = sigletons.get(propertyDefinition.getRef());
setter.setAccessible(true);
setter.invoke(bean, value);//把引用对象注入到属性
}
else
{
Object value = ConvertUtils.convert(propertyDefinition.getValue(), properdesc.getPropertyType());
setter.setAccessible(true);
setter.invoke(bean, value);//把引用对象注入到属性
}
}
break;
}
}
}
}
catch (Exception e)
{
}
}
}
}
/**
* 完成bean的实例化
*/
private void instanceBeans() {
for(BeanDefinition beanDefinition : beanDefines){
try {
if(beanDefinition.getClassName()!=null && !"".equals(beanDefinition.getClassName().trim()))
sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 读取xml配置文件
* @param filename
*/
private void readXML(String filename) {
SAXReader saxReader = new SAXReader();
Document document=null;
try{
URL xmlpath = this.getClass().getClassLoader().getResource(filename);
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");//获取id属性值
String clazz = element.attributeValue("class"); //获取class属性值
BeanDefinition beanDefine = new BeanDefinition(id, clazz);
XPath propertysub = element.createXPath("ns:property");
propertysub.setNamespaceURIs(nsMap);//设置命名空间
List<Element> propertys = propertysub.selectNodes(element);
for(Element property : propertys){
String propertyName = property.attributeValue("name");
String propertyref = property.attributeValue("ref");
String propertyValue = property.attributeValue("value");
log.info(propertyValue);
PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName, propertyref,propertyValue);
beanDefine.getPropertys().add(propertyDefinition);
}
beanDefines.add(beanDefine);
}
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 获取bean实例
* @param beanName
* @return
*/
public Object getBean(String beanName){
return this.sigletons.get(beanName);
}
}
注意:
a.红色加粗的 的代码 我们使用了 commons-beanutils.jar 提供的方法,它能根据属性的类型完成转换,可以把String->int 等,因为我们在配置文件一般都是这样写的 <property name="age" value="26"/> 这个工具方法就可以帮助我们把26 这个string类型转换为 int类型.
b.蓝色的代码 表示 当ref不为空的情况下 我们为属性注入引用对象,否则直接注入配置文件中属性所代表的值.
c. 咖啡色 代码 标识我们构造属性bean的使用在加一个类型.
(3) 在 PersionServiceBean.java 中我们使用bean.xml中的name和age属性, 看看自己的 ItcastClassPathXMLApplicationContext 使用完成了属性的注入
package cn.com.xinli.service.impl;
import org.apache.log4j.Logger;
import cn.com.xinli.dao.PersionDao;
import cn.com.xinli.service.PersionSevice;
public class PersionServiceBean implements PersionSevice
{
Logger log=Logger.getLogger(PersionServiceBean.class);
private PersionDao persionDao;
private String name;
private int age;
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public PersionDao getPersionDao()
{
return persionDao;
}
public void setPersionDao(PersionDao persionDao)
{
this.persionDao = persionDao;
}
public void init()
{
log.info("初始化资源");
}
public PersionServiceBean()
{
log.info("我被实例化了");
}
public void save()
{
log.info("name:"+name);
log.info("age:"+age);
this.persionDao.add();
}
public void destory()
{
log.info("释放资源");
}
}
(4)测试
ItcastClassPathXMLApplicationContext ctx = new ItcastClassPathXMLApplicationContext("beans.xml");
PersionSevice ps=(PersionSevice)ctx.getBean("persionServiceBean");
ps.save();
(5) 结果
2009-05-30 11:08:46,203 INFO (PersionServiceBean.java:44) - 我被实例化了
2009-05-30 11:08:47,187 INFO (PersionServiceBean.java:49) - name:huxl
2009-05-30 11:08:47,187 INFO (PersionServiceBean.java:50) - age:26
2009-05-30 11:08:47,187 INFO (PersionDaoBean.java:15) - 执行了PersionDaoBean中的add()方法