您的位置:首页 > 编程语言 > Java开发

自己实现spring核心IOC部分

2015-11-18 11:04 706 查看
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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: