Spring学习笔记 IOC原理实现

20 篇文章 0 订阅

实现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();
	}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值