这课我们来实现Spring第三课所讲的东西


  首先实现构造器注入

XmlParser.java

package com.ioc;



import com.ioc.util.FileUtil;

import org.dom4j.Document;

import org.dom4j.DocumentException;

import org.dom4j.Element;

import org.dom4j.io.SAXReader;



import java.io.File;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

import java.util.ArrayList;

import java.util.List;



//这个类负责解析xml

public class XmlParser {



BeanDefinitionRegistry registry;

Document document;



public XmlParser(BeanDefinitionRegistry registry,String xmlPath)

{

this.registry = registry;

xmlPath = FileUtil.resolveClassPath(xmlPath);

File file = new File(xmlPath);

if (file.exists())

{

SAXReader reader = new SAXReader();

try {

document = reader.read(file);

} catch (DocumentException e) {

e.printStackTrace();

}

}

}



/**

* 解析xml,将解析到的bean通过BeanDefinitionRegistry注册到IoC容器中

*/

public void parse() throws ClassNotFoundException, IllegalAccessException, InstantiationException {

//我们以xml标签为单位逐步解析

Element rootElement = document.getRootElement();

if (rootElement.getName().equals("beans"))

{

parseBeans(rootElement);

}



}



//解析beans标签

private void parseBeans(Element beansElement) throws ClassNotFoundException, InstantiationException, IllegalAccessException {

List<Element> bean = beansElement.elements("bean");

for (Element beanElement : bean)

{

parseBean(beanElement);

}

}



//解析bean标签

private void parseBean(Element beanElement) throws ClassNotFoundException, IllegalAccessException, InstantiationException {

//<bean id="student" class="resources.bean.Student"></bean>

//我们要得到id和class

String name = beanElement.attributeValue("id");

String className = beanElement.attributeValue("class");

Class<?> beanClass = Class.forName(className);

Object bean = null;



//这里开始实现依赖注入的部分

//先写构造器注入

bean = constructorInject(beanElement);



//这里开始实现setter注入的部分

//留做作业

setterInject(bean,beanElement);



//构造BeanDefinition对象

BeanDefinition beanDefinition = new BeanDefinition(name,beanClass,bean);



//注册BeanDefinition对象

registry.regist(name,beanDefinition);

}



//setter注入

private void setterInject(Object bean, Element beanElement)

{

//作业部分

}



//构造器注入

private Object constructorInject(Element beanElement) throws ClassNotFoundException, IllegalAccessException, InstantiationException

{

Object bean = null;

Class<?> beanClass = Class.forName(beanElement.attributeValue("class"));

List<Element> constuctorArgElements = beanElement.elements("constructor-arg");

if (constuctorArgElements != null && !constuctorArgElements.isEmpty())

{

//有constructor-arg标签

//获取构造器参数表

Object[] constructorArgs = parseConstructorArgs(constuctorArgElements);



//获取对应的构造器

Constructor<?>[] constructors = beanClass.getConstructors();

for (Constructor<?> constructor : constructors)

{

if (constructor.getParameterCount() == constructorArgs.length)

{

try {

//使用这个构造器来构造对象

//这里其实有个问题,就是constructorArgs里的元素全是String类型的,这里需要转换数据类型

Class<?>[] parameterTypes = constructor.getParameterTypes();

for (int i = 0; i < parameterTypes.length; i++)

{

//转换到合适的类型

constructorArgs[i] = castToSuitType(constructorArgs[i],parameterTypes[i]);

}

bean = constructor.newInstance(constructorArgs);

} catch (InvocationTargetException e) {

//这个构造器参数表类型不太对

continue;

}

break;

}

}

if (bean == null)

{

throw new RuntimeException("找不到对应的构造器,无法构造对应对象");

}

}

else

{

//这是没有constructor-arg标签的情况

//构造bean对象

bean = beanClass.newInstance();

}

return bean;

}



private Object castToSuitType(Object constructorArg, Class<?> parameterType)

{

//这个方法很枯燥,我就不带着写了,直接把我以前写过的拿过来算了

String arg = constructorArg.toString();

Object value;

if (parameterType == String.class)

{

value = arg;

}

else if(parameterType == Integer.class || parameterType == int.class)

{

value = Integer.parseInt(arg);

}

else if (parameterType == Float.class || parameterType == float.class)

{

value = Float.parseFloat(arg);

}

else if (parameterType == Double.class || parameterType == double.class)

{

value = Double.parseDouble(arg);

}

else if (parameterType == Short.class || parameterType == short.class)

{

value = Short.parseShort(arg);

}

else

{

//这里之所以写constructorArg而不是arg就是因为怕这个参数类型是非字符串可以转换到的类型

value = constructorArg;

}

return value;

}



//解析多个constructor-arg标签

private Object[] parseConstructorArgs(List<Element> constructorArgElements)

{

List<Object> constructorArgs = new ArrayList<>(constructorArgElements.size());

for (Element constructorArgElement : constructorArgElements)

{

constructorArgs.add(parseConstructorArg(constructorArgElement));

}

return constructorArgs.toArray();

}



//解析单个constructor-arg标签

private Object parseConstructorArg(Element constructorArgElement)

{

/*

这里其实还有个问题

构造器里的参数可能不是基本数据类型或包装类型或String,而是其他类比如自定义的class,这里 我们说过用ref

*/

String value = constructorArgElement.attributeValue("value");

if (value == null || "".equals(value))

{

Object ref = registry.get(constructorArgElement.attributeValue("ref"));

return ref;

}

return value;

}

}


作业: 实现setter注入