第8讲 --编码剖析Spring装配基本属性的原理

xiaoxiao2026-08-15  32

 

    下面我们使用模拟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:huxl2009-05-30 11:08:47,187  INFO (PersionServiceBean.java:50) - age:262009-05-30 11:08:47,187  INFO (PersionDaoBean.java:15) - 执行了PersionDaoBean中的add()方法

 

转载请注明原文地址: https://www.6miu.com/read-5051257.html

最新回复(0)