这课我们来实现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注入