自己实现spring核心IOC部分

原创 2015年11月18日 11:04:46

bean

package cn.itcast.bean;

public class A {
		
	
		public A() {
				System.out.println("A对象被创建了!");
	}

		private int name;

		public int getName() {
			return name;
		}

		public void setName(int name) {
			this.name = name;
		}
		
		
		
		
}

package cn.itcast.bean;

public class B {
	
	
	
	public B() {
		System.out.println("B对象被创建了!");
	}

	private A a;

	public A getA() {
		return a;
	}

	public void setA(A a) {
		this.a = a;
	}
	
	
}
package cn.itcast.bean;

public class C {
	
	
	public C() {
		System.out.println("C对象被创建了!");
	}

	private B b;

	public B getB() {
		return b;
	}

	public void setB(B b) {
		this.b = b;
	}
	
	
}

config

package cn.itcast.config;

import java.util.ArrayList;
import java.util.List;

public class Bean {
	private String name;
	private String className;
	private String scope = "singleton";
	
	private List<Property> properties = new ArrayList<Property>();

	
	
	public String getScope() {
		return scope;
	}

	public void setScope(String scope) {
		this.scope = scope;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}

	public List<Property> getProperties() {
		return properties;
	}

	public void setProperties(List<Property> properties) {
		this.properties = properties;
	}

	@Override
	public String toString() {
		return "Bean [name=" + name + ", className=" + className + ", scope="
				+ scope + ", properties=" + properties + "]";
	}


	
}


package cn.itcast.config;

public class Property {
	private String name;
	private String value;
	private String ref;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getValue() {
		return value;
	}
	public void setValue(String value) {
		this.value = value;
	}
	public String getRef() {
		return ref;
	}
	public void setRef(String ref) {
		this.ref = ref;
	}
	@Override
	public String toString() {
		return "Property [name=" + name + ", value=" + value + ", ref=" + ref
				+ "]";
	}
}

parse

package cn.itcast.config.parse;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import cn.itcast.config.Bean;
import cn.itcast.config.Property;
/**
 * dom4j实现步骤
 * 1创建解析器
 * 2.加载配置文件==>document对象
 * 3.定义xpath表达式,取出所有的Bean元素
 * 4.对Bean元素进行遍历
 *   将Bean元素的name/class 属性封装到Bean对象中
 *   获得bean元素下所有的Property子元素,将属性name/value封装到Property对象中
 *   将Property对象封装到Bean对象中
 * 5.在将Bean对象封装到Map中(用于返回的map)
 * 6.返回map
 * @author lzqiangPC
 *
 */
public class ConfigManager {
	// 读取 配置文件 => 并返回读取结果

	public static Map<String, Bean> getConfig(String path) {
		// 创建一个用于返回的map对象
		Map<String, Bean> map = new HashMap<String, Bean>();
		// dom4j实现
		// 1 创建解析器
		SAXReader reader = new SAXReader();
		// 2 加载配置文件=>document对象
		InputStream is = ConfigManager.class.getResourceAsStream(path);
		Document doc = null;
		try {
			doc = reader.read(is);
		} catch (DocumentException e) {
			e.printStackTrace();
			throw new RuntimeException("客官!请检查您的xml配置是否正确!");
		}
		// 3 定义xpath表达式,取出所有Bean元素
		String xpath = "//bean";
		// 4 对Bean元素进行遍历
		List<Element> list = doc.selectNodes(xpath);
		if (list != null) {
			for (Element beanEle : list) {
				Bean bean = new Bean();
				// 将bean元素的name/class 属性封装到Bean对象中
				String name = beanEle.attributeValue("name");
				String className = beanEle.attributeValue("class");
				String scope = beanEle.attributeValue("scope");

				bean.setName(name);
				bean.setClassName(className);
				if (scope != null) {
					bean.setScope(scope);
				}

				// 获得Bean元素下的所有Property子元素 ,将属性name/value/ref封装到Property对象中
				List<Element> children = beanEle.elements("property");

				if (children != null) {
					for (Element child : children) {
						Property prop = new Property();

						String pName = child.attributeValue("name");
						String pValue = child.attributeValue("value");
						String pRef = child.attributeValue("ref");

						prop.setName(pName);
						prop.setRef(pRef);
						prop.setValue(pValue);

						// 将Property封装到Bean对象
						bean.getProperties().add(prop);
					}
				}
				// 将Bean对象封装到Map中(用于返回的map)
				map.put(name, bean);
			}
		}
		// 5 返回Map结果
		return map;

	}
}

main

package cn.itcast.main;

public interface BeanFactory {
	//根据Bean的name获得 Bean对象的方法
	Object getBean(String beanName);
}

package cn.itcast.main;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import cn.itcast.config.Bean;
import cn.itcast.config.Property;
import cn.itcast.config.parse.ConfigManager;
import cn.itcast.utils.BeanUtils;

public class ClassPathXmlApplicationContext implements BeanFactory {

	// 希望在ClassPathXmlApplicationContext类一创建
	// 就初始化spring容器(装载Bean实例的)
	// 配置信息
	private Map<String, Bean> config;
	// 使用一个map来做spring的容器=> 放置我们spring所管理的对象
	private Map<String, Object> context = new HashMap<String, Object>();
	
	/**
	 * 1.读取配置文件获得需要初始化的Bean信息
	 * 2.遍历配置,初始化Bean
	 * 3.将初始化的Bean放入容器中
	 * @param path
	 */
	public ClassPathXmlApplicationContext(String path) {
		// 1 读取配置文件获得需要初始化的Bean信息
		config = ConfigManager.getConfig(path);
		// 2 遍历配置 初始化Bean
		if (config != null) {
			for (Entry<String, Bean> en : config.entrySet()) {
				// 获得配置中的Bean信息
				String beanName = en.getKey();
				Bean bean = en.getValue();

				Object existBean = context.get(beanName);
				// 因为createBean方法中也会向Context中放置Bean
				// 我们在初始化之前先要判断容器中是否已经存在了这个Bean.再去完成初始化的工作
				// 并且我们的Bean的scope属性值为singleton,才将Bean放入容器中
				if (existBean == null && bean.getScope().equals("singleton")) {
					// 根据bean配置 创建bean对象
					Object beanObj = createBean(bean);
					// 3 将初始化好的Bean放入容器中
					context.put(beanName, beanObj);
				}
			}
		}
	}

	// 根据Bean配置创建Bean实例
	/*
	 * <bean name="A" class="cn.itcast.bean.A" > <!--
	 * 将A的属性配置,spring会自动将配置的值注入到A中 --> <property name="name" value="tom"
	 * ></property> </bean>
	 * ###########################################
	 * 1.获得要创建的Bean的class
	 * 2.获得Bean的属性,将其注入
	 */
	private Object createBean(Bean bean) {
		// 1 获得要创建的Bean的Class
		String className = bean.getClassName();
		Class clazz = null;
		try {
			clazz = Class.forName(className);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			throw new RuntimeException("客官!请检查您Bean的Class配置是否正确!" + className);
		}
		// 获得class=> 将class对应的对象创建出来
		Object beanObj = null;
		try {
			beanObj = clazz.newInstance();// 调用空参构造
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("客官!您的Bean没有空参构造!" + className);
		}

		// 2 需要获得Bean的属性,将其注入
		if (bean.getProperties() != null) {
			for (Property prop : bean.getProperties()) {
				// 注入分两种情况
				// 获得要注入的属性名称
				String name = prop.getName();
				String value = prop.getValue();
				String ref = prop.getRef();
				// 注入值类型属性方式2:使用BeanUtils工具类完成属性的注入
				if (value != null) {// 说明有值类型的属性需要注入
					Map<String, String[]> paramMap = new HashMap<String, String[]>();
					paramMap.put(name, new String[] { value });
					// 调用BeanUtils方法将值类型的属性注入(该种注入=>可以自动完成类型转换)
					try {
						org.apache.commons.beanutils.BeanUtils.populate(
								beanObj, paramMap);
					} catch (Exception e) {
						e.printStackTrace();
						throw new RuntimeException("客官!请检查您的" + name + "属性!");
					}
				}

				// 用于注入Bean类型的属性
				if (prop.getRef() != null) {
					// 2> 麻烦=> 其他Bean的注入
					// 根据属性名称获得注入属性对应的Set方法
					Method setMethod = BeanUtils.getWriteMethod(beanObj, name);
					// 因为要注入其他bean到当前bean中,我们先从容器中查找当前要注入的Bean是否已经创建,并放入容器中
					Object existBean = context.get(prop.getRef());

					if (existBean == null) {
						// 说明容器中还不存在我们要注入的Bean
						// 将Bean创建
						existBean = createBean(config.get(prop.getRef()));
						// 将创建好的Bean放入容器中
						if (config.get(prop.getRef()).getScope()
								.equals("singleton")) {
							context.put(prop.getRef(), existBean);
						}
					}

					// 调用set方法注入即可
					try {
						setMethod.invoke(beanObj, existBean);
					} catch (Exception e) {
						e.printStackTrace();
						throw new RuntimeException("客官!您的Bean的属性" + name
								+ "没有对应的set方法,或方法参数不正确" + className);
					}
				}

				/*
				 * // 根据属性名称获得注入属性对应的Set方法 Method setMethod =
				 * BeanUtils.getWriteMethod(beanObj,name); // 创建一个需要注入到Bean中的属性
				 * Object param = null; if(prop.getValue()!=null){ //1> 简单=>
				 * value属性注入 //获得要注入的实行值 String value = prop.getValue(); param =
				 * value; } if(prop.getRef()!=null){ //2> 麻烦=> 其他Bean的注入
				 * 
				 * // 因为要注入其他bean到当前bean中,我们先从容器中查找当前要注入的Bean是否已经创建,并放入容器中
				 * Object existBean = context.get(prop.getRef());
				 * 
				 * if(existBean == null ){ //说明容器中还不存在我们要注入的Bean //将Bean创建
				 * existBean = createBean(config.get(prop.getRef()));
				 * //将创建好的Bean放入容器中
				 * if(config.get(prop.getRef()).getScope().equals("singleton")){
				 * context.put(prop.getRef(), existBean); } }
				 * 
				 * param = existBean; }
				 * 
				 * 
				 * // 调用set方法注入即可 try { setMethod.invoke(beanObj, param); }
				 * catch (Exception e) { e.printStackTrace(); throw new
				 * RuntimeException
				 * ("客官!您的Bean的属性"+name+"没有对应的set方法,或方法参数不正确"+className); }
				 */
			}
		}

		return beanObj;
	}

	@Override
	// 根据Bean的名称获得Bean实例
	public Object getBean(String beanName) {

		Object bean = context.get(beanName);

		// 如果bean的scope配置为prototype .那么 context中就不会包含该Bean对象
		if (bean == null) {
			// 如果不存在该Bean对象,那么就创建这个Bean对象
			bean = createBean(config.get(beanName));
		}

		return bean;
	}

}

package cn.itcast.main;

import cn.itcast.bean.A;
import cn.itcast.bean.B;
import cn.itcast.bean.C;

public class Test {
	@org.junit.Test
	public void fun1(){
		BeanFactory bf = new ClassPathXmlApplicationContext("/applicationContext.xml");
		
		A a = (A) bf.getBean("A");
		/*A a2 = (A) bf.getBean("A");
		A a3 = (A) bf.getBean("A");*/
		
		System.out.println(a.getName());//tom
		
	}
	
	
	@org.junit.Test
	public void fun2(){
		BeanFactory bf = new ClassPathXmlApplicationContext("/applicationContext.xml");
		
		B b = (B) bf.getBean("B");
		B b2 = (B) bf.getBean("B");
		B b3 = (B) bf.getBean("B");
		B b4 = (B) bf.getBean("B");
		
		System.out.println(b.getA().getName());//jerry
		
	}
	
	@org.junit.Test
	public void fun3(){
		BeanFactory bf = new ClassPathXmlApplicationContext("/applicationContext.xml");
		
		C c = (C) bf.getBean("C");
		C c2 = (C) bf.getBean("C");
		C c3 = (C) bf.getBean("C");
		C c4 = (C) bf.getBean("C");
		
		System.out.println(c.getB().getA().getName());//jerry
		
	}
}

test;

package cn.itcast.test;

import java.util.Map;

import cn.itcast.config.Bean;
import cn.itcast.config.parse.ConfigManager;

public class Test {
	//测试读取配置文件的ConfigManager.java 是否正确
	@org.junit.Test
	public void fun1(){
		Map<String, Bean> config = ConfigManager.getConfig("/applicationContext.xml");
		
		System.out.println(config);
		
	}
}

utils

package cn.itcast.utils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
/**
 * 反射:就是一套用来描述类的API
 * 内省:基于反射技术,用于操作Bean属性的一套api
 * @author lzqiangPC
 *
 */
public class BeanUtils {
	//参数1 bean对象
	//参数2 要获得的Bean对象对应的属性名称
	public static Method getWriteMethod(Object beanObj, String name) {
		Method method = null;
		//使用内省技术来实现该方法
			try {
				//1. 分析Bean对象=> BeanInfo
				BeanInfo info = Introspector.getBeanInfo(beanObj.getClass());
				//2. 根据BeanInfo获得所有属性的描述器
				PropertyDescriptor[] pds = info.getPropertyDescriptors();
				//3. 遍历这些属性描述器
				if(pds!=null){
					for(PropertyDescriptor pd : pds){
						//判断当前遍历的描述器描述的属性是否是我们要找的属性
						//获得当前描述器描述的属性名称
						String pName = pd.getName();
						//使用要找的属性名称与当前描述器描述的属性名称比对
						if(pName.equals(name)){
							//比对一致=>找到了,获得写入属性的set方法
							method = pd.getWriteMethod();
						}
					}
				}
				
				//4. 返回找到的set方法
			} catch (IntrospectionException e) {
				e.printStackTrace();
			}
			//如果没有找到=>抛出异常提示用户 检查是否创建属性对应的set方法
			if(method==null){
				throw new RuntimeException("客官!请检查"+name+"属性的set方法是否创建!");
			}
			
			
		return method;
	}

}

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<!-- 将A配置到配置文件中 -->
	<bean name="A" class="cn.itcast.bean.A"  >
		<!-- 将A的属性配置,spring会自动将配置的值注入到A中 -->
		<property name="name" value="123" ></property>
	</bean>

	<bean name="B" class="cn.itcast.bean.B" scope="prototype" >
		<!-- ref标识 要将Bean A注入 -->
		<property name="a" ref="A" ></property>
	</bean>
	
	
	<bean name="C" class="cn.itcast.bean.C" scope="prototype"  >
		<!-- ref标识 要将Bean B注入 -->
		<property name="b" ref="B" ></property>
	</bean>
</beans>


Spring核心学习IOC部分

  • 2015年05月11日 16:55
  • 95KB
  • 下载

(精)Spring IOC核心源码学习III:bean标签和自定义标签实现原理

本文将解析spring bean定义标签和自定义标签的解析实现原理。 这里说的标签仅限于以xml作为bean定义描述符的spring容器,继承AbstractXmlApplicationContext...
  • it_man
  • it_man
  • 2012年05月17日 22:38
  • 7061

Spring技术内幕2Spring Framework的核心:IoC容器的实现

1SpringIoC容器概述 IoC容器和依赖反转模式: 早在2004年,Martin Fowler就提出了“哪些方面的控制被反转了?”这个问题。他总结出是依赖对象的获得被反转了。基于这个结论...

02_spring核心技术-IOC.ppt

  • 2013年12月30日 16:21
  • 432KB
  • 下载

Spring IOC部分经典教程

  • 2011年11月23日 14:44
  • 817KB
  • 下载

初步理解spring ioc原理(读完可自己实现依赖注入部分的spring框架)

spring  的核心原理是ioc 和aop(面向切面编程),近段时间学习了spring的ioc部分,这篇文章也是自己对spring  原理的一个理解整理,希望对大家有所帮助。aop待学习之后再发表文...

spring 核心与源码解析(1):IoC之BeanFactory

Spring两个最重要的特性之一——控制反转(Inversion of Control)。 不仅是Spring,几乎任何web框架都实现了IoC,这一特性的最大便利就是不需要手动的创建单例对象。 ...

Spring应用、原理以及粗读源码系列(一)--框架总述、以Bean为核心的机制(IoC容器初始化以及依赖注入)

总述:spring框架是如今J2EE开发最重要框架之一,为企业级应用提供一系列轻量级解决方案,比如:基于依赖注入的核心机制、基于AOP的声明式事务管理、与多种持久层技术整合、整合后端各种组件等等。贯穿...

Spring 核心知识点 IOC容器入门与了解

知识体系:一: Spring框架的简介  1.什么是Spring? 2.Spring 的主要功能有哪些?   二:  容器和Bean管理   1.Spring容器的简介 2.Spring 容器的实例化...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:自己实现spring核心IOC部分
举报原因:
原因补充:

(最多只允许输入30个字)