实现Spring 依赖注入:
1.读取xml配置文件,保存Bean数据
2.使用反射技术,生成bean对象池,对bean对象的属性赋值
xml配置文件读取器
依赖jar包: dom4j.jar; jaxen.jar
package com.skymr.spring.test.iocimpl;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
/**
* xml配置读取
* @author skymr
*
*/
public class XmlReader {
private Map<String,BeanDefinition> beans = new HashMap<String,BeanDefinition>();
@SuppressWarnings("unchecked")
public void readXml(String fileName) throws Exception{
SAXReader reader = new SAXReader();
Document doc = reader.read(this.getClass().getClassLoader().getResourceAsStream(fileName));
Map<String,String> nsMap = new HashMap<String,String>();
nsMap.put("ns", "http://www.springframework.org/schema/beans");
XPath xsub = doc.createXPath("//ns:beans/ns:bean");
xsub.setNamespaceURIs(nsMap);
List<Element> list = xsub.selectNodes(doc);
for(Element e: list){
String id = e.attributeValue("id");
String classPath = e.attributeValue("class");
BeanDefinition bean = new BeanDefinition();
bean.setId(id);
bean.setClazz(classPath);
XPath propertyPath = e.createXPath("ns:property");
propertyPath.setNamespaceURIs(nsMap);
List<Element> pList = propertyPath.selectNodes(e);
for(Element pe: pList){
PropertyDefinition pd = new PropertyDefinition();
pd.setName(pe.attributeValue("name"));
pd.setRef(pe.attributeValue("ref"));
pd.setValue(pe.attributeValue("value"));
bean.addProperty(pd);
}
beans.put(bean.getId(),bean);
}
}
public BeanDefinition getBean(String name){
return beans.get(name);
}
public Map<String,BeanDefinition> getAllBeans(){
return this.beans;
}
public static void main(String[] args) throws Exception{
new XmlReader().readXml("beans.xml");
}
}
package com.skymr.spring.test.iocimpl;
/**
* 属性定义类
* @author skymr
*
*/
public class PropertyDefinition {
private String name;
private String ref;
private String 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;
}
}
package com.skymr.spring.test.iocimpl;
import java.util.ArrayList;
import java.util.List;
/**
* Bean定义类
* @author skymr
*
*/
public class BeanDefinition {
private String id;
private String clazz;
private List<PropertyDefinition> propertyList = new ArrayList<PropertyDefinition>();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public List<PropertyDefinition> getPropertyList() {
return propertyList;
}
public void setPropertyList(List<PropertyDefinition> propertyList) {
this.propertyList = propertyList;
}
public void addProperty(PropertyDefinition property){
this.propertyList.add(property);
}
}
XmlReader能将spring 的bean配置读到内存中,然后根据这些配置创建实例
package com.skymr.spring.test.iocimpl;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.annotation.Resource;
public class ClassPathXml {
private XmlReader reader;
//Bean定义集合
private Map<String, BeanDefinition> beans;
//实例集合
private Map<String, Object> instanceMap = new HashMap<String, Object>();
public ClassPathXml(String fileName){
reader = new XmlReader();
try {
reader.readXml(fileName);
injectObject();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 注入所有
* @throws Exception
*/
public void injectObject() throws Exception{
beans = reader.getAllBeans();
Iterator<BeanDefinition> it = beans.values().iterator();
while(it.hasNext()){
BeanDefinition bean = it.next();
if(instanceMap.containsKey(bean.getId())){
continue;
}
injectObject(bean);
}
}
@SuppressWarnings("unchecked")
protected void injectObject(BeanDefinition bean) throws Exception{
Class clazz = Class.forName(bean.getClazz());
Object object = clazz.newInstance();
instanceMap.put(bean.getId(), object);
for(PropertyDefinition pd: bean.getPropertyList()){
if(pd.getValue() != null){
invoke(object, pd.getName(), pd.getValue());
}
if(pd.getRef() != null){
if(instanceMap.containsKey(pd.getRef())){
}
else{
injectObject(beans.get(pd.getRef()));
}
invoke(object, pd.getName(), instanceMap.get(pd.getRef()));
}
}
//注入含有Resource注释的属性
Field[] fields = clazz.getDeclaredFields();
for(Field f : fields){
Annotation an = f.getAnnotation(Resource.class);
if(an != null){
if(!instanceMap.containsKey(f.getName())){
injectObject(beans.get(f.getName()));
}
invoke(object, f, instanceMap.get(f.getName()));
}
}
}
protected void invoke(Object obj, String attrName, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(attrName);
field.setAccessible(true);
field.set(obj, value);
}
protected void invoke(Object obj, Field field, Object value) throws Exception{
field.setAccessible(true);
field.set(obj, value);
}
public Object getBean(String id) {
return instanceMap.get(id);
}
}
还蛮简单的,只是通过反射创建对象,然后对对象属性赋值,因为实现的IOC功能本来就小,不全面,但个人并不是为了真的做的一个spring IOC,为了学习而已.
测试
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<bean id = "userInfoDao" class = "com.skymr.spring.test.dao.impl.UserInfoDaoBean">
<property name="name" value = "userInfoDao"></property>
</bean>
<bean id = "userInfoDao1" class = "com.skymr.spring.test.dao.impl.UserInfoDaoBean">
<property name="name" value = "userInfoDao1"></property>
</bean>
<bean id = "userInfoService" class="com.skymr.spring.test.service.impl.UserInfoServiceBean">
<property name="name" value="skymr"></property>
</bean>
<context:component-scan base-package="springlive.learn.component"/>
<context:annotation-config></context:annotation-config>
</beans>
@org.junit.Test
public void springIOCOwn(){
ClassPathXml ctx = new ClassPathXml("beansTmp.xml");
com.skymr.spring.test.service.UserInfoService userInfoService = (com.skymr.spring.test.service.UserInfoService) ctx.getBean("userInfoService");
System.out.println(userInfoService);
userInfoService.save();
}