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