其实 对于spring 的依赖注入是很简单的实现,通过学习后,查找后找到了一个不错的对于DI的模拟实现。所以分享过来和大家一起学习进步。
首先总结下主要的步骤就是3步。
1.分别为 对于xml文档的解析
2.对于所有bean对象的初始化构造(需要无参的构造方法,或者默认的构造方法)。
3.把配置的属性注入到对象中。
对于最终的Bean的生命周期暂时不做讨论,在下一篇中会着重讨论对于bean的管理和生命周期的问题。
1.首先通过dom4j的sax解析xml 拿到所有的属性,保存到List<BeanInformation>中。
2.通过反射机制通过对于List<BeanInformation>中所有的name来初始化这个对象
(bean),初始化后的对象的属性都是默认值,或者为空,因为是通过默认为空的构造方
法去初始化这个类的。
3.把上面初始化为空的对象的属性注入进来。那么这个过程可能涉及很多问题,(有可
能把一个本来没有注入完成的(所有属性都没有注入完成)再注入到其他的对象中,最
后导致“虚注入”.不知道spring 是怎么解决这个问题的,此处暂时不做过多的研究。)此
处指关于通过List<BeanInformation>中对于对象配置的propertity的注入,通过propertity
的name 映射到要初始化对象的属性和对应的setter方法上,或者找到构造方法,然后,
通过相应的参数,匹配相应的方法,注入进去。
最后 我做了一个实验来验证spring注入顺序的问题,是当对象注入完成后才注入下一个还是只要遇到就注入不管本对象是否完整。 通过判断是后者。 我的实验室这样做的,2个对象互相持有对方,相当于死锁。但是仍然能相互注入成功。这样开发者对于相互注入的问题就变的很简单了。
这里是关键spring框架模拟的实现的一些原理!!!
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.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
public class ApplicationContext {
List<BeanInformation> beansInformation = new ArrayList<BeanInformation>();
Map<String,Object> singleton = new HashMap<String,Object>();
public ApplicationContext(){};
public ApplicationContext(String filename){
readXml(filename);
initBean();
this.injectObject();
}
public void readXml(String filename){
SAXReader saxReader = new SAXReader();
Document document = null;
try{
//使用反射机制,通过文件名加载文件路径
URL xmlPath = this.getClass().getClassLoader().getResource(filename);
//通过文件路径获得这个文件的document对象
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){
System.out.println(element.attributeValue("id"));
System.out.println(element.attributeValue("class"));
BeanInformation beanInformation = new BeanInformation();
beanInformation.setId(element.attributeValue("id"));
beanInformation.setName(element.attributeValue("class"));
XPath xref = element.createXPath("ns:property");//创建properties查询路径
xref.setNamespaceURIs(nsMap);//设置命名空间
List<Element> propertys = xref.selectNodes(element);
for(Element property : propertys){
PropertyInformation propertyInformation = new PropertyInformation();
propertyInformation.setName(property.attributeValue("name"));
propertyInformation.setRef(property.attributeValue("ref"));
propertyInformation.setValue(property.attributeValue("value"));
beanInformation.getPropertyInformation().add(propertyInformation);
}
beansInformation.add(beanInformation);
}
} catch(Exception e){
e.printStackTrace();
}
}
public void initBean(){
for(BeanInformation beanInformation: beansInformation){
if(beanInformation.getName()!=null && !"".equals(beanInformation.getName())){
//通过反射机制,根据名字初始化这个类
try {
singleton.put(beanInformation.getId(), Class.forName(beanInformation.getName()).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 关于注入的实现
*/
private void injectObject() {
for(BeanInformation beanInformation : beansInformation){
Object bean = singleton.get(beanInformation.getId());
if(bean!=null){
try {
PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
for(PropertyInformation propertyInformation : beanInformation.getPropertyInformation()){
for(PropertyDescriptor properdesc : ps){
if(propertyInformation.getName().equals(properdesc.getName())){
Method setter = properdesc.getWriteMethod();//获取属性的setter方法 ,private
if(setter!=null){
Object value = null; <span style="font-family: Arial, Helvetica, sans-serif;"> if(propertyInformation.getRef()!=null&&!"".equals(propertyInformation.getRef().trim())){</span>
value = singleton.get(propertyInformation.getRef());
}else{
value = ConvertUtils.convert(propertyInformation.getValue(), properdesc.getPropertyType());
}
setter.setAccessible(true);
setter.invoke(bean, value);//把引用对象注入到属性
}
break;
}
}
}
} catch (Exception e) {
}
}
}
}
public Object getBean(String id){
return this.singleton.get(id);
}
}