一.前言

通过前两篇文章的学习,我们已经对Java中这三个模块的知识有了初步的了解。为了将巩固之前的知识,今天我们将综合运用这三个模块的知识,来实现一个类似Spring中注入的案例。

二.项目结构

简单的描绘了一下项目流程图,如下

spring如何注入带泛型的bean spring泛型注入原理_嵌套


流程说明:Ipraser是一个接口,其中定义了一个praserBeans(),返回的是List<Bean>集合,两种数据源分别为XML和注解,对应的是AnnotationPraser和XmlPraser两个解析注解和XML的类,两个类都实现了Ipraser接口,与AnnotationPraser关联的是解析注解相关的辅助类,包括代表各种数据类型的各种注解定义类,还有一个是ClassUtil类用来获取指定包下的Java类。解析数据必须的类有Exception用于定义解析中出现的各种异常,Generator定义了生成类名和方法名称的接口,有两个实现类,Constant用于定义各种常量,Property代表一个bean中定义的所有属性,CollectionProperty是其中的一个变量,代表Java类中的集合属性,BaseProperty继承自CollectionProperty,定义了List、Map和Set中共有的属性,ListProperty、MapProperty和SetProperty继承自BaseProperty分别定义了List、Map和Set中特有的属性。

Config等类使用Builder方式定义了外界的一些配置信息,其中IConfigBuilder是抽象建造,定义了建造流程,Config是最终组装的信息类,其中的内部类ConfigBuilder是具体的构建类,所有信息最终被封装在ConfigEntry中。Method中是ConfigEntry的一个属性,通过枚举形式定义了XML和annotation两种注入方式。

PraserFactory是一个解析器的工厂类,使用策略方式通过参数Method返回不同的具体解析类。

ObjectFactory通过参数List<Bean>作为数据源生成各种对象,类的出口是将生成的对象放入ObjectPool对象池中,该对象实现Ipool接口定义了存取对象的规范,ObjectManager是外界访问的类,可以设置加载参数,然后调用各个PraserFactory、ObjectFactory完成对象的生成,还定义了访问对象的方法,通过访问对象Pool获取对象,然后返回。

三.具体实现

(1).XML读取

首先来看XML解析部分,对应的是XmlPraser,返回的是List<Bean>数据类型。我们这里使用Dom4j这个包来进行XML的解析,XML是和Spring中使用的XML基本一致,下面是缩略的xml。

<bean id="Family" class="com.sunjinxi.spring.test.Family">
        <property name="number" value="4" />
        <property name="familySalary" value="258.6" />
    <!--set和List完全相同 set代表set结合,List代表List集合-->
<property name="employs">
            <list>
                <!--验证List中存放字符串 
                       可以指定所有基本类型的值
-->
                <value>张三丰</value>
                <value>李白</value>
            </list>
        </property>
        <!-- List嵌套bean List存放的是引用类型-->
<property name="employs2">
<list>
        <bean></bean>
        <bean></bean>
</list>
</property>
  <!-- List嵌套引用,List存放的是引用-->
<property name="employs3">
<list>
        <ref></ref>
        <ref></ref>
</list>
</property>
  <!-- List嵌套List或者Set或者Map,List中存放的是List,Set或者Map-->
<property name="employs3">
<list>
        <List></List>
        <set></set>
        <map><entry> <key></key>
                <value></value></entry></map>
</list>
   <!--map标签对应HashMap-->
   <property name="map">
<map>
   <!--entry标签对应HashMap中的一个映射,key代表键,Value代表值-->
<entry><key>123</key><value>100</value></entry>
   <!--Map中的Key可以为引用类型,对应<value-ref>和<value-bean>标签-->
<entry><key>address1</key>
<value_ref>user1</value_ref></entry>
<value_bean><bean></bean></value_bean>

</property>
<!-- set标签代表无序集合,支持基本类型,引用类型,List,Set,Map类型,配置和List标签完全相同--->
<set></set>

我们的注入在XML中支持基本类型的值,List集合,Set集合,Map类型,List嵌套List,Set和Map,引用类型,Set嵌套List,Set和Map,Map的key和value分别支持基本类型和引用类型,不支持和其他集合类型的嵌套。
首先是入口方法

@Override
    public List<Bean> praserBeans(String param) {
        // TODO Auto-generated method stub
        File file=file=new File(param);
        SAXReader saxReader=new SAXReader();
        Document document=null;
        Element rootElement=null;
        try {
            document=saxReader.read(file);
            rootElement=document.getRootElement();
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return inflateAll(rootElement);
    }

首先根据xml的位置参数,创建File对象,使用SaxReader对象读取xml,生成Document文档对象,获取根节点,即RootElement,调用inflateAll方法遍历所有的元素节点。

private List<Bean> inflateAll(Element rootElement) {
        List<Bean> beans=null;
        beans=new ArrayList<Bean>();
        Iterator<Element> beanIterator=rootElement.elementIterator();
        while (beanIterator.hasNext()) {
            Element beanElement=beanIterator.next();
            Bean bean=inflateSingleBean(beanElement);
            beans.add(bean);
        }
        return beans;
    }
这段代码拿到所有的bean节点对应的Element对象,调用inflateSingleBean方法把返回的bean属性对象添加到集合中。
private Bean inflateSingleBean(Element beanElement) {
        Bean bean=new Bean();
        //首先解析各种各样的属性
        String objectId=beanElement.attributeValue(Constant.XmlKey.ElementBean.KEY_ATTRIBUTE_ID);
        String className=beanElement.attributeValue(Constant.XmlKey.ElementBean.KEY_ATTRIBUTE_CLASS);
        String initMethod=beanElement.attributeValue(Constant.XmlKey.ElementBean.KEY_ATTRIBUTE_METHOD_INIT);
        String initDestory=beanElement.attributeValue(Constant.XmlKey.ElementBean.KEY_ATTRIBUTE_METHOD_DESTORY);        
//初始化属性集合
        List<Property> properties=new ArrayList<Property>();
        bean.setClassAddress(className);
        bean.setDestoryMethod(initDestory);
        bean.setInitMethod(initMethod);
        bean.setId(objectId);
        bean.setProperties(properties);
        //拿到子元素,变量子元素
        Iterator<Element> propertyIterator=beanElement.elementIterator();
        while (propertyIterator.hasNext()) {
            //遍历每一个属性
            Element propertyElement=propertyIterator.next();                //初始化Property属性 
            Property property=new Property();
            List<Element> elements=propertyElement.elements();
            Element collectionElement=null;
            //设置属性的名称
            String propertyName=propertyElement.attributeValue(Constant.XmlKey.ElementProperty.KEY_ATTRIBUTE_NAME);
            property.setName(propertyName);
    //判断Property是否有子节点,有代表是一个集合属性,否则是普通属性       
            if (elements!=null&&elements.size()!=0) {
                //属性值为集合,获取集合节点
                collectionElement=elements.get(0);
                CollectionProperty collectionValue=null;
                String collectionName=collectionElement.getName();
                if (collectionName.equals(Constant.XmlKey.ElementCollection.KEY_ELEMENT_LIST)) {
                    //处理List集合
                    collectionValue=inflatePropertyListAndSet(collectionElement,new ListProperty());
                    property.setType(Constant.Property.TYPE_LIST);
                }else if (collectionName.equals(Constant.XmlKey.ElementCollection.KEY_ELEMENT_SET)) {
                    //处理set集合
                    collectionValue=inflatePropertyListAndSet(collectionElement,new SetProperty());
                    property.setType(Constant.Property.TYPE_SET);
                }else if (collectionName.equals(Constant.XmlKey.ElementCollection.KEY_ELEMETN_MAP)) {
                    //处理Map集合
                    collectionValue=inflatePropertyMap(collectionElement);
                    property.setType(Constant.Property.TYPE_MAP);
                }

                property.setCollectionValue(collectionValue);
                properties.add(property);
                continue;
            }
            //如果属性值为引用值或者基本数据类型
            String propertyValue=propertyElement.attributeValue(Constant.XmlKey.ElementProperty.KEY_ATTRIBUTE_VALUE);
            String propertyRef=propertyElement.attributeValue(Constant.XmlKey.ElementProperty.KEY_ATTRIBUTE_REF);
            property.setValue(propertyValue);
            property.setRef(propertyRef);
            if (propertyRef==null) {
                property.setType(Constant.Property.TYPE_VALUE);
            }else {
                property.setType(Constant.Property.TYPE_REF);
            }
            properties.add(property);   
            //取出list
        }
        return bean;
    }

这段代码首先从Element对象中获取相应的属性,包括id,class,init-method和destroy-method,这些常量都被封装在Constant类中方便查找和更改,然后初始化List<Property>,准备将所有的属性放入该集合中。之后取出属性节点,判断属性节点下是否存在子节点,如果存在则说明属性的值是Set,List或者Map类型,如果是List或者Set则调用inflatePropertyListAndSet,是Map则调用inflatePropertyMap方法,返回的是一个CollectionProperty上转型对象。如果是基本类型的数值的话,则直接取出属性中的值,设置到Property对象中即可。
再来看解析List和Set标签属性的方法inflatePropertyListAndSet

private CollectionProperty inflatePropertyListAndSet(Element element,BaseProperty result) {
        // TODO Auto-generated method stub
        Iterator<Element> iterator=element.elementIterator();
        List<String> valueList=null;
        List<String> refList=null;
        List<Bean>   beans=null;
        List<CollectionProperty> collectionProperties=null;
        while (iterator.hasNext()) {
            Element childElement=iterator.next();
            String childElementName=childElement.getName();
            String value=childElement.getText();
            int type=getCollectinValueType(childElementName);
            result.setType(type);
            switch (type) {
            case Constant.Property.TYPE_VALUE:
                if (valueList==null) {
                    valueList=new ArrayList<String>();
                }
                valueList.add(value);
                result.setValueList(valueList);
                break;
            case Constant.Property.TYPE_REF:
                if (refList==null) {
                    refList=new ArrayList<String>();
                }
                refList.add(value);
                result.setRefList(refList);
                break;
            case Constant.Property.TYPE_BEAN:
                if (beans==null) {
                    beans=new ArrayList<Bean>();
                }
                Bean bean=inflateSingleBean(childElement);
                beans.add(bean);
                result.setBeans(beans);
                break;
            case Constant.Property.TYPE_SET:
                if (collectionProperties==null) {
                    collectionProperties=new ArrayList<CollectionProperty>();
                }

                CollectionProperty setProperty=inflatePropertyListAndSet(childElement,new SetProperty());
                collectionProperties.add(setProperty);
                result.setCollectionProperties(collectionProperties);
                break;
            case Constant.Property.TYPE_LIST:
                if (collectionProperties==null) {
                    collectionProperties=new ArrayList<CollectionProperty>();
                }
                CollectionProperty listProperty=inflatePropertyListAndSet(childElement,new ListProperty());
                collectionProperties.add(listProperty);
                result.setCollectionProperties(collectionProperties);
                break;
            case Constant.Property.TYPE_MAP:
                if (collectionProperties==null) {
                    collectionProperties=new ArrayList<CollectionProperty>();
                }
                CollectionProperty mapProperty=inflatePropertyMap(childElement);
                collectionProperties.add(mapProperty);
                result.setCollectionProperties(collectionProperties);
                break;
            default:
                break;
            }
        }
        return result;
    }

这段代码首先遍历list或者set标签下的元素,list或者set标签支持基本数据类型value标签,引用数据类型ref标签和bean标签,以及set,list或者map标签,在这里是调用getCollectinValueType获取标签的类型,其实就是为每个标签对应了相应的数值常量,方便我们使用switch语句分类讨论,如果是value标签,我们则将对应的值放到valueList集合中,ref标签则放到refList中,bean标签则放到beans集合中,set或list标签我们会递归调用inflatePropertyListAndSet方法,然后把对应的属性放到collectionProperties集合中,map标签也是一样,只不过调用的是inflatePropertyMap方法。接着来看inflatePropertyMap方法的实现。

private CollectionProperty inflatePropertyMap(Element element) {
        // TODO Auto-generated method stub
        Iterator<Element> iterator=element.elementIterator();
        MapProperty mapProperty=new MapProperty();
        List<MapEntryProperty> mapEntryProperties=new ArrayList<MapEntryProperty>();
        mapProperty.setEntrys(mapEntryProperties);
        while (iterator.hasNext()) {
            Element childElement=iterator.next();
            Iterator<Element> entryIterator=childElement.elementIterator();
            MapEntryProperty mapEntryProperty=null;
            //解析Entry对象中的key,value 
            Element keyElement=entryIterator.next();                
            Element valueElement=entryIterator.next();
            String keyName=keyElement.getName();
            String valueName=valueElement.getName();
            int keyType=getMapValueType(keyName);
            int valueType=getMapValueType(valueName);
            if (keyType==Constant.Property.TYPE_BEAN&&valueType==Constant.Property.TYPE_BEAN) {
                mapEntryProperty=new MapEntryProperty<Bean, Bean>();
            }else if (keyType==Constant.Property.TYPE_BEAN) {
                mapEntryProperty=new MapEntryProperty<Bean, String>();
            }else if (valueType==Constant.Property.TYPE_BEAN) {
                mapEntryProperty=new MapEntryProperty<String, Bean>();
            }else {
                mapEntryProperty=new MapEntryProperty<String, String>();
            }
            switch (keyType) {
            case Constant.Property.TYPE_VALUE:
                mapEntryProperty.setKeyType(MapEntryType.value);
                mapEntryProperty.setKey(keyElement.getText());
                break;
            case Constant.Property.TYPE_REF:
                mapEntryProperty.setKey(keyElement.getText());
                mapEntryProperty.setKeyType(MapEntryType.ref);
                break;
            case Constant.Property.TYPE_BEAN:
                Bean bean=inflateSingleBean(keyElement.element(Constant.XmlKey.ElementBean.KEY_ELEMENT_NAME));
                mapEntryProperty.setKey(bean);
                mapEntryProperty.setKeyType(MapEntryType.bean);
                break;
            default:
                break;
            }
            switch (valueType) {
            case Constant.Property.TYPE_VALUE:
                mapEntryProperty.setValueType(MapEntryType.value);
                mapEntryProperty.setValue(valueElement.getText());
                break;
            case Constant.Property.TYPE_REF:
                mapEntryProperty.setValueType(MapEntryType.ref);
                mapEntryProperty.setValue(valueElement.getText());
                break;
            case Constant.Property.TYPE_BEAN:
                Bean bean=inflateSingleBean(valueElement.element(Constant.XmlKey.ElementBean.KEY_ELEMENT_NAME));
                mapEntryProperty.setValue(bean);
                mapEntryProperty.setValueType(MapEntryType.bean);
                break;
            default:
                break;
            }
            System.out.println(mapEntryProperty.toString());
            mapEntryProperties.add(mapEntryProperty);
        }
        return mapProperty;
    }

这段代码首先遍历map下的所有entry元素,之后取出entry下的key和value键值对,在这里key和value支持三种标签,key,value代表的是基础数据类型,value_bean和value_ref代表值是引用类型,key_ref和key_bean代表键是引用类型。每一个entry标签对应的是一个MapEntryProperty对象,首先看看MapEntryProperty对象。

//代表一个map属性
public class MapProperty extends CollectionProperty{
    private List<MapEntryProperty> entrys;
    public List<MapEntryProperty> getEntrys() {
        return entrys;
    }

    public void setEntrys(List<MapEntryProperty> entrys) {
        this.entrys = entrys;
    }


    public static class Support{
        public static Class<?>[] TYPE_SUPPORT={HashMap.class,LinkedHashMap.class};
        public static Class<?> TYPE_SUPPORT_INTERFACE=Map.class;
    }

    @Override
    public String toString() {
        return "MapProperty [entrys=" + entrys + "]";
    }


    /**
     * @author Administrator
     *代表键和值都是基本类型
     */
    public static class MapEntryProperty<k,v>{
        @Override
        public String toString() {
            return "MapEntryProperty [keyType=" + keyType + ", valueType="
                    + valueType + ", key=" + key + ", value=" + value + "]";
        }
        private MapEntryType keyType;
        private MapEntryType valueType;
        private k key;
        private v value;


        public MapEntryType getValueType() {
            return valueType;
        }
        public void setValueType(MapEntryType valueType) {
            this.valueType = valueType;
        }
        public MapEntryType getKeyType() {
            return keyType;
        }
        public void setKeyType(MapEntryType keyType) {
            this.keyType = keyType;
        }
        public k getKey() {
            return key;
        }
        public void setKey(k key) {
            this.key = key;
        }
        public v getValue() {
            return value;
        }
        public void setValue(v value) {
            this.value = value;
        }


    }

    /**键和值的两种类型
     * @author Administrator
     *
     */
    public enum MapEntryType{
          value,
          ref,
          bean
    }



}

MapProperty类代表的是map标签,成员变量entrys存放的是entry键值对的集合,静态内部类MapEntryProperty代表的是一个entry标签,内部有keyType和valueType两个属性,分别代表键和值的类型,MapEntryType是一个枚举类,有ref,value和bean三种类型,由于在初始化对象的时候,三种类型的处理是不同的所以这里分割开来。key和value代表的是真实值,因为类型不同则类型可能是字符串类型也可能是bean类型,所以使用泛型参数来代替。Support内部类代表支持的集合类型的字节码对象,我们这里支持JavaBean声明的类型可以是HashMap或者LinkedHashMap,也可以支持Map接口声明,会默认以HashMap类型来处理。
回到inflatePropertyMap中,我们会根据key和value类型的不同来在初始化MapEntryProperty传入不同的泛型实参,之后对key和value分别分类讨论,根据不同的类型,mapEntryProperty对象设置不同的MapEntryType和value,key值。基本类型则调用Element对象的getText()方法取值,引用类型则递归调用inflateSingleBean方法获得Bena对象。
到这里,xml的解析工作已经做完了,最终返回的是List<Bean>对象,所有的属性都放在这里。
(2).Annotation读取
接着来看注解读取的部分,这里主要使用注解和反射的知识来完成。

@Override
    public List<Bean> praserBeans(String param) {
        // TODO Auto-generated method stub
        List<Bean> beans=new ArrayList<Bean>();
        List<Class<?>> clazzs=ClassUtil.getClasses(param);
        for (int i = 0; i < clazzs.size(); i++) {
            Class clazz=clazzs.get(i);
            Bean bean=getBeanByClass(clazz);
            if (bean!=null) {
                beans.add(bean);
            }
        }

        return beans;
    }

首先根据包,获取指定包下的所有类的Class字节码对象,然后调用getBeanByClass方法获取指定类的Bean对象。

private Bean getBeanByClass(Class<?> clazz){
        Annotation clazzAnnotation=clazz.getAnnotation(BeanType.class);
        if (clazzAnnotation==null) {
            return null;
        }
        Bean bean=new Bean();
        BeanType beanType=(BeanType) clazzAnnotation;
        String beanId=beanType.id();
        bean.setId(beanId);
        bean.setClassAddress(clazz.getPackage().getName()+"."+clazz.getSimpleName());
        System.out.println(bean.getClassAddress());
        Field[] declaredFields = clazz.getDeclaredFields();
        List<Property> properties=new ArrayList<Property>();
        bean.setProperties(properties);
        for (int j = 0; j < declaredFields.length; j++) {
            Field field=declaredFields[j];
            Annotation[] annotations=field.getAnnotations();
            if (annotations.length==0) {
                continue;
            }
            Property property=new Property();
            properties.add(property);
            String fieldName=field.getName();
            property.setName(fieldName);
            for (int k = 0; k < annotations.length; k++) {
                Annotation annotation=annotations[k];
                if (field.isAnnotationPresent(BasicType.class)) {
                    BasicType basicType=(BasicType) annotation;     
                    String value=getBasicProperty(basicType);               
                    property.setValue(value);
                     property.setType(Constant.Property.TYPE_VALUE);
                }else if (field.isAnnotationPresent(ListType.class)) {
                    ListType listType=(ListType) annotation;
                    ListProperty listProperty=getListProperty(listType);
                    property.setCollectionValue(listProperty);
                    property.setType(Constant.Property.TYPE_LIST);
                }else if (field.isAnnotationPresent(SetType.class)) {
                    SetType setType=(SetType) annotation;
                    SetProperty setProperty=getSetProperty(setType);
                    property.setCollectionValue(setProperty);
                    property.setType(Constant.Property.TYPE_SET);
                }else if (field.isAnnotationPresent(MapType.class)) {
                    MapType mapType=(MapType) annotation;
                    MapProperty mapProperty=getMapProperty(mapType);
                    property.setCollectionValue(mapProperty);
                    property.setType(Constant.Property.TYPE_MAP);
                }else if (field.isAnnotationPresent(RefType.class)) {
                    RefType refType=(RefType) annotation;
                    String ref=getRefProperty(refType);
                    property.setRef(ref);
                    property.setType(Constant.Property.TYPE_REF);
                }
            }
        }

        return bean;
    }

可以看到注解的解析相对简单,因为注解的局限性,暂时无法注入集合嵌套集合这种类型的数据类型,因为注解的值不能是注解元素本身,所以无法完成递归调用。这段代码首先获取BeanType注解,只有添加这个注解的才会被我们注入,如果没有这个注解则注解返回。之后调用getDeclaredFields方法获取该类的所有属性,然后遍历所有的属性。获取属性上作用的所有Annotation,遍历所有的Annotation,调用Filed的isAnnotationPresent方法判断是否有指定的注解作用在Field上。类型分别是BasicType,ListType,SetType,MapType,RefType,分别调用对应的读取注解的方法,然后给Property设置获取的注解值。
获取引用类型

private String getRefProperty(RefType refType){
           return refType.id();
}

获取基本数据类型

private String getBasicProperty(BasicType basicType){

              return basicType.value();
    }

获取list类型

private ListProperty getListProperty(ListType listType){
        ListProperty listProperty=new ListProperty(); 
        listProperty.setType(Constant.Property.TYPE_VALUE);
        String[] values = listType.value();
        List<String> valueList=new ArrayList<String>();
        for (int i = 0; i < values.length; i++) {
            String value=values[i];
            valueList.add(value);
        }
        listProperty.setValueList(valueList);
        return listProperty;
    }

获取set类型

private SetProperty getSetProperty(SetType setType){
        SetProperty setProperty=new SetProperty(); 
        setProperty.setType(Constant.Property.TYPE_VALUE);
        String[] values = setType.value();
        List<String> valueList=new ArrayList<String>();
        for (int i = 0; i < values.length; i++) {
            String value=values[i];
            valueList.add(value);
        }
        setProperty.setValueList(valueList);
        return setProperty;
    }

获取map类型

private MapProperty getMapProperty(MapType mapType){
         MapProperty mapProperty=new MapProperty(); 

         List<MapEntryProperty> mapEntryProperties=new ArrayList<MapProperty.MapEntryProperty>();
         MapEntry[] mapEntries=mapType.entry();
         for (int i = 0; i < mapEntries.length; i++) {
             MapEntryProperty<String, String> mapEntryProperty=new MapEntryProperty<String, String>();
             mapEntryProperty.setKeyType(MapEntryType.value);
             mapEntryProperty.setValueType(MapEntryType.value);
             MapEntry mapEntry=mapEntries[i];
             String key=mapEntry.key();
             String value=mapEntry.value();
             mapEntryProperty.setKey(key);
             mapEntryProperty.setValue(value);
             mapEntryProperties.add(mapEntryProperty);
         }
         mapProperty.setEntrys(mapEntryProperties);
         return mapProperty;
     }

到这里,我们的注解读取的工作也完成了。
(3).反射注入
接着是最核心的工作,所有的反射注入工作都在ObjectFactory类中完成。
首先看构造方法

public ObjectFactory(List<Bean> beans) {
        // TODO Auto-generated constructor stub
        classMap=new HashMap<String, Class<Object>>();
        this.mBeans=beans;
        this.mObjectManager=ObjectManager.getInstance();
        this.mWrapClasses=new Class[]{Integer.class,Double.class,Float.class,
                Short.class,Long.class,Byte.class,Boolean.class,Character.class};
        this.mBasiClasses=new Class[]{int.class,double.class,float.class,
                short.class,long.class,byte.class,boolean.class,char.class};
    }
classMap是用来缓存Class字节码对象的,获取Class对象时首先会去缓存中查找如果没有再去调用方法加载。mWrapClasses和mBasiClasses是两个数组,前者放的是基础数据类型的包装类对象,后者是基础数据类型的Class对象。因为int.class和Integer.class不是一个对象,为了方便我们从字符串中解析出对应的数据类型值,我们需要将其转换成对应的包装类型,然后通过反射调用包装类型的静态方法valueOf方法获取真实的数据。
 入口方法
public Object loadObject(Bean bean) throws ReferenceException, FieldTypeException{
        String classAddress=bean.getClassAddress();
        Class<Object> clazz=classMap.get(classAddress);
        Object object=null;
        if (clazz==null) {
            ClassLoader classLoader=ObjectFactory.class.getClassLoader();
            try {
                //不进行类的初始化
                //clazz=(Class<Object>) Class.forName(classAddress);
                clazz=(Class<Object>) classLoader.loadClass(classAddress);
                classMap.put(classAddress, clazz);
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return null;
            }
        }
        //首先创建对象
        try {
            object = clazz.newInstance();
        } catch (Exception e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } 
        List<Property> properties=bean.getProperties();
        for (int i = 0; i < properties.size(); i++) {
            Property property=properties.get(i);
            int type=property.getType();
            String fieldName=property.getName();
            Field field=null;
            Class rawType=null;

            try {
                field = clazz.getDeclaredField(fieldName);
                rawType=field.getType();
            } catch (Exception e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            } 
            switch (type) {
            case Constant.Property.TYPE_SET:
                //注入set集合
                Type setType=field.getGenericType();
                SetProperty setProperty=(SetProperty) property.getCollectionValue();
                Collection setResult=getListAndSet(setType,setProperty,SetProperty.Support.TYPE_SUPPORT_CLASS,SetProperty.Support.TYPE_SUPPORT_INTERFACE);
                inject(clazz, object, fieldName, rawType, setResult);
                break;
            case Constant.Property.TYPE_LIST:
                //注入List集合
                Type listType=field.getGenericType();
                ListProperty listProperty=(ListProperty) property.getCollectionValue();
                Collection listResult=getListAndSet(listType,listProperty,
                        ListProperty.Support.TYPE_SUPPORT_CLASS,ListProperty.Support.TYPE_SUPPORT_INTERFACE);
                inject(clazz, object, fieldName, rawType, listResult);
                break;
            case Constant.Property.TYPE_MAP:
                //注入Map集合
                //key key-ref key可以使基本数据类型,也可以是引用类型
                //value 基本数据类型  value-ref配置 中的引用类型
                //1.首先判断对应的变量类型是不是map,并确定targetClass
                //2.判断泛型参数的类型与xml文件中是否一致
                //3.填充数据
                //1
                Type mapType=field.getGenericType();
                MapProperty mapProperty=(MapProperty) property.getCollectionValue();

                Map map = getMap(mapProperty,mapType);

                inject(clazz, object, fieldName, rawType, map);
                break;
            case Constant.Property.TYPE_REF:
                //value是引用值
                Object refObject=getRefObject(property.getRef());
                try {
                    System.out.println(fieldName);
                    Class fieldClazz=field.getType();
                    inject(clazz, object, fieldName, fieldClazz, refObject);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } 
                break;
            case Constant.Property.TYPE_VALUE:
                //Vlaue是基本类型的值
                System.out.println("rawType:"+rawType);
                Object objectBasic=pareseBasicValue(getWrapFromBasic(rawType), property.getValue());
                inject(clazz, object, fieldName, rawType, objectBasic);
            }

        }
        return object;

    }

首先根据指定的全类名从缓存Map中查找对应的Class字节码对象,如果为空则去加载Class对象,然后放到缓存map中。首先创建出对象,之后遍历List<Property>属性集合 ,开始注入各种值。然后取出属性的名称,调用getDeclaredField方法,根据属性的名称获取Field对象,调用Field对象的getType方法获取属性的数据类型,这里获取的是一个原始数据类型。
接下来调用Property的getType方法获取属性的类型,然后分类讨论。
首先讨论set集合,如果是set集合,则必须获取泛型参数的类型,这里是调用的Field的getGenericType方法,然后调用getListAndSet方法,该方法返回的是一个Collection上转型对象,这个对象便是根据属性类型创建出来的对象,其中已经设定好了值,然后进行注入。List集合的处理和Set集合基本相同。我们重点来看getListAndSet方法。

private Collection<?> getListAndSet(Type paramType,
            BaseProperty listProperty,Class[] supportClasses,Class supportInterface)
                    throws FieldTypeException, ReferenceException {
        //首先进行类型校验和Class选取
        //第一步进行校验
        ParameterizedType parameterizedType=null;
        if (!(paramType instanceof ParameterizedType)) {
            //不是List或set接口的子类,或者没有指定要注入的类型形参
            throw new FieldTypeException(Constant.Exeception.EXECEPTION_FIELDTYPE);
        } else {
            parameterizedType=(ParameterizedType) paramType;
        }
        Class paramClazz=(Class) parameterizedType.getRawType();

        //第二步 确定集合的Class对象
        Type[] types=parameterizedType.getActualTypeArguments();
        Type genericParamType= types[0];
        Collection resultCollection=null;
        //类型错误抛出异常
        //注入集合类型的值
        //集合中的数据类型  基本数据类型<value></value>、集合类型 List Map set、引用类型<ref></ref> 、bean
        //获取泛型数据类型
        //获取修饰符
        //如果Class是一个List接口,默认创建ArrayList创建数据
        //否则分为ArrayList和LinkeList来处理
        //如果指定变量不是一个List集合类型则抛出异常
        //为了保持数据的原有类型,在初始化对象的时候分别采用ArrayList和LinkeList的字节码来初始化
        //但是寻找方法的时候依旧采用原始类型
        //只处理ArrayList和LinkList,其他全部抛出异常
        //注入前首先判断变量类型是否是集合类型

        Class<?> targetClass=null;

        //支持ArrayList和LinkedList,其余类型抛出异常
        for (int i = 0; i < supportClasses.length; i++) {
            Class<?> support= supportClasses[i];
            if (support.isAssignableFrom(paramClazz)) {
                targetClass=support;
                break;
            }
        }
        if (targetClass==null) {
            if (supportInterface.isAssignableFrom(paramClazz)) {
                targetClass=supportClasses[0];
            }else {
                throw new FieldTypeException(Constant.Exeception.EXECEPTION_FIELDTYPE);
            }
        }
        //根据不同类型的值开始创建对象
        int listValueType=listProperty.getType();
        switch (listValueType) {
        case Constant.Property.TYPE_VALUE:
            //集合中是基本类型的值
            try {
                List<String> valueList=listProperty.getValueList();
                Class genericParamClass=(Class) genericParamType;
                resultCollection=getBasicList(genericParamClass, valueList, targetClass);
            } catch (InstantiationException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            } catch (IllegalAccessException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            break;
        case Constant.Property.TYPE_BEAN:
            //集合中的值是一个bean
            try {
                //元素是bean类型
                resultCollection=(Collection) targetClass.newInstance();
                List<Bean> beanList=listProperty.getBeans();
                for (int j = 0; j < beanList.size(); j++) {
                    Bean beanValue=beanList.get(j);
                    Object objectValue=loadObject(beanValue);
                    resultCollection.add(objectValue);
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
            break;
        case Constant.Property.TYPE_REF:
            //集合中的值是一个引用
            try {
                resultCollection=(Collection) targetClass.newInstance();
                List<String> list=listProperty.getRefList();
                for (int j = 0; j <list.size(); j++) {
                    String ref=list.get(j);
                    Object resultObject=null;
                    for (int k = 0; k <mBeans.size(); k++) {
                        Bean beanRef=mBeans.get(k);
                        if (beanRef.getId().equals(ref)) {
                            if (beanRef.isInject()) {
                                resultObject=mObjectManager.getObjectById(ref);
                                //退出内层循环
                                break;
                            }else {
                                resultObject=loadObject(beanRef);
                                break;
                            }

                        }
                    }
                    resultCollection.add(resultObject);}
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
            break;
        case Constant.Property.TYPE_LIST:
            try {
                resultCollection=(Collection) targetClass.newInstance();
                List<CollectionProperty>  properties=listProperty.getCollectionProperties();
                for (int j = 0; j <properties.size(); j++) {
                    ListProperty collectionProperty=(ListProperty) properties.get(j);
                    Collection<?> result=getListAndSet(genericParamType,collectionProperty,ListProperty.Support.TYPE_SUPPORT_CLASS,ListProperty.Support.TYPE_SUPPORT_INTERFACE);
                    resultCollection.add(result);
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
            break;
        case Constant.Property.TYPE_SET:
            try {
                resultCollection=(Collection) targetClass.newInstance();
                List<CollectionProperty>    propertiesSet=listProperty.getCollectionProperties();
                for (int j = 0; j <propertiesSet.size(); j++) {
                    SetProperty collectionProperty=(SetProperty) propertiesSet.get(j);
                    Collection<?> result=getListAndSet(genericParamType,collectionProperty,SetProperty.Support.TYPE_SUPPORT_CLASS,SetProperty.Support.TYPE_SUPPORT_INTERFACE);
                    resultCollection.add(result);
                }

            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 


            break;
        case Constant.Property.TYPE_MAP:
            try {
                resultCollection=(Collection) targetClass.newInstance();
                List<CollectionProperty>    propertiesMap=listProperty.getCollectionProperties();
                for (int j = 0; j <propertiesMap.size(); j++) {
                    MapProperty mapProperty=(MapProperty) propertiesMap.get(j);
                    Map result=getMap(mapProperty, genericParamType);
                    resultCollection.add(result);
                }

            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
            break;
        default:
            break;
        }
        return resultCollection;
    }
这段代码可以分为三个步骤,首先是JavaBean中声明的属性类型是否和相应的集合类型对应。首先判断paramType是不是ParameterizedType类型的实例,ParameterizedType代表的是包含泛型参数的类型,如果在定义该属性时没有指定泛型参数,则无法确定元素的数据类型,也就是无法进行后续的注入,所有直接抛出异常。
 第二部确定要使用的Clas类型,也就是在反射时我们要使用的是ArrayList字节码还是LinkedList字节码这个问题。在这里我们支持ArrayList和LinkedList以及HashSet以及LinkedHashSet类型,对于声明为接口类型,则默认为ArrayList和HashSet字节码。isAssignableFrom是用来判断支持的类型和实际的类型是否相同,如果是接口类型则使用默认的字节码对象进行初始化。
 第三部根据配置的不同类型的值开始初始化对象,基本类型的值调用getBasicList方法获取对应的集合。bean引用类型需要我们递归调用loadObject方法,然后将返回的Object对象添加到集合中。ref类型我们要首先判断对应的对象是否已经被初始化,没有则加载该对象,有则将对象添加到集合张。对于List,set和map类型则需要递归调用getListAndSet和getMap方法。
private Map getMap(MapProperty mapProperty,Type mapType)
            throws FieldTypeException, ReferenceException {
        //确定TargetClass

        ParameterizedType parameterizedType=null;
        if (!(mapType instanceof ParameterizedType)) {
            //没有泛型直接抛出异常
            throw new FieldTypeException(Constant.Exeception.EXECEPTION_FIELDTYPE);
        } else {
            parameterizedType=(ParameterizedType) mapType;
        }
        Class targetClass=null;
        Class mapClazz=(Class)parameterizedType.getRawType();
        Class[] supportClass=MapProperty.Support.TYPE_SUPPORT;
        for (int j = 0; j < supportClass.length; j++) {
            if (mapClazz.equals(supportClass[j])) {
                targetClass=supportClass[j];
                break;
            }
        }
        if (targetClass==null) {
            if (!MapProperty.Support.TYPE_SUPPORT_INTERFACE.isAssignableFrom(mapClazz)) {
                throw new FieldTypeException(Constant.Exeception.EXECEPTION_FIELDTYPE);
            }else {
                targetClass=supportClass[0];
            }
        }
        //2进行初步的验证
        Type[] mapTypes=parameterizedType.getActualTypeArguments();
        Class keyClazz=(Class) mapTypes[0];
        Class valueClazz=(Class) mapTypes[1];
        List<MapEntryProperty> mapEntryProperties=mapProperty.getEntrys();
        MapEntryProperty mapEntryProperty=mapEntryProperties.get(0);
        int valueType=getGenericParamType(valueClazz);
        int keyType=getGenericParamType(keyClazz);
        MapEntryType keyMapType=mapEntryProperty.getKeyType();
        MapEntryType valueMapType=mapEntryProperty.getValueType();

        if ((keyType!=-1&&(keyMapType==MapEntryType.ref||keyMapType==MapEntryType.bean))
                ||(valueType!=-1&&(valueMapType==MapEntryType.ref||valueMapType==MapEntryType.bean))) {
            throw new FieldTypeException(Constant.Exeception.EXECEPTION_FIELDTYPE);
        }
        if ((keyType==-1&&keyMapType==MapEntryType.value)||(valueType==-1&&valueMapType==MapEntryType.value)) {
            throw new FieldTypeException(Constant.Exeception.EXECEPTION_FIELDTYPE);
        }
        //.填充数据
        //直接通过对应的calss对象初始化对象,不存在泛型类型,所以不需要对不同的泛型参数初始化不同的对象
        Map map=null;
        try {
            map=(Map) targetClass.newInstance();
            for (int j = 0; j < mapEntryProperties.size(); j++) {
                MapEntryProperty entryProperty=mapEntryProperties.get(j);
                MapEntryType entryKeyType=entryProperty.getKeyType();
                MapEntryType entryValueType=entryProperty.getValueType();
                Object key=getMapValueByType(entryKeyType, entryProperty, true, keyClazz);
                Object value=getMapValueByType(entryValueType, entryProperty, false, valueClazz);
                map.put(key, value);
            }
        } catch (InstantiationException | IllegalAccessException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        return map;
    }

这个方法的初步验证和上一个方法相同,不同的是这里我们要对Java类在声明map是做传入的泛型实参的类型和在xml中的类型,既key和value的类型分别进行校验。getGenericParamType方法获取的是泛型参数的类型,来看这个方法

public int getGenericParamType(Class<?> filedType){
        int type=-1;
        if (filedType.isAssignableFrom(Integer.class)) {
            type=Constant.Data.TYPE_INTEGER;
        }else if (filedType.isAssignableFrom(Double.class)) {
            type=Constant.Data.TYPE_DOUBLE;
        }else if (filedType.isAssignableFrom(Long.class)) {
            type=Constant.Data.TYPE_LONG;
        }else if (filedType.isAssignableFrom(Float.class)) {
            type=Constant.Data.TYPE_FLOAT;
        }else if (filedType.isAssignableFrom(Byte.class)) {
            type=Constant.Data.TYPE_BYTE;
        }else if (filedType.isAssignableFrom(Short.class)) {
            type=Constant.Data.TYPE_SHORT;
        }else if (filedType.isAssignableFrom(Boolean.class)) {
            type=Constant.Data.TYPE_BOOLEAN;
        }else if (filedType.isAssignableFrom(Character.class)) {
            type=Constant.Data.TYPE_CHAR;
        }else if (filedType.isAssignableFrom(String.class)) {
            type=Constant.Data.TYPE_STRING;
        }
        return type;
    }
我们这里之支持基本数据类型和引用类型,引用类型则返回-1。验证通过后开始进行注入,遍历entry集合,然后调用getMapValueByType方法获取key和value的值
//如何处理不同类型的注入
    //1.判断所有的基础类型,解析不同的类型
    //2.通过反射调用参数中对象的valueOf方法解析得到数据
    public Object getMapValueByType(MapEntryType mapEntryType,MapEntryProperty mapEntryProperty,boolean isKey,Class clazz) throws ReferenceException, FieldTypeException{
        System.out.println("注入bean"+mapEntryType.toString());
        Object resultObject=null;
        if(mapEntryType.equals(MapEntryType.value)){
            //基本类型的值
            String value=(String) (isKey?mapEntryProperty.getKey():mapEntryProperty.getValue());
            if (clazz.isAssignableFrom(String.class)) {
                resultObject=value;
            }else {
                Method method;
                try {
                    method = clazz.getDeclaredMethod("valueOf", String.class);
                    resultObject=method.invoke(null, value);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }else if (mapEntryType.equals(MapEntryType.ref)) {
            String value=(String) (isKey?mapEntryProperty.getKey():mapEntryProperty.getValue());
            resultObject=getRefObject(value);

        }else if (mapEntryType.equals(MapEntryType.bean)) {
            Bean bean=(Bean) (isKey?mapEntryProperty.getKey():mapEntryProperty.getValue());
            System.out.println("注入bean"+bean.toString());
            resultObject=loadObject(bean);
        }

        return resultObject;
    }
依旧是分类讨论,这里要注意的问题是对于基础数据类型,如何正确获取对应的类型的值,因为我们从注解或者xml中获取的值是字符串类型的,所有要把他们转化为8中对应的基础数据类型。刚开始的时候是对每个类型进行判断,然后调用对应类型的valueOf方法。其实我们可以再次进行反射,获取对应数据类型的valueOf方法的Method对象,因为所有的包装类型都有valueOf方法,因为他们都继承自Number类。
private Object pareseBasicValue(Class paramclazz,String value){
        Object resultObject=null;
        if (paramclazz.equals(String.class)) {
            resultObject=value;
        }else {
            Method method=null;
            try {
                method=paramclazz.getDeclaredMethod("valueOf", String.class);
                resultObject=method.invoke(null, value);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return resultObject;
    }
这提取基础类型值的方法,通过反射,大大简化了代码。
private void inject(Class<Object> clazz, Object object, String keyName,
            Class filedClass, Object value) {
        String methodName=MethodNameGenerator.getInstance()
                .generateName(MethodNameGenerator.PER_SETTER,
                        keyName);
        Method method;
        try {
            method = clazz.getMethod(methodName, filedClass);
            method.invoke(object, value);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
    }

这是最终注入的代码,通过MethodNameGenerator来和成对应的方法名称,到这里核心的代码就介绍完了。

Config config=new ConfigBuilder().setInjectMethod(Method.annotation)
                .setInjectParam("com.sunjinxi.spring.annotationinject").create();
        ObjectManager objectManager=ObjectManager.getInstance();
        objectManager.setConfig(config);
        User user=(User) objectManager.getObjectById("User");
        System.out.println(user.toString());

通过这样的代码,我们便可以轻松完成对JavaBean类进行各种信息的注入,是不是很方便呢。
四.反射的一些问题的总结
(1). 如何获取数据的类型

public static void getType(Type type){
                 if (type instanceof GenericArrayType) {
                    GenericArrayType genericArrayType=(GenericArrayType) type;
                    Type componentType=genericArrayType.getGenericComponentType();
                    System.out.println("componentType"+componentType);
                    getType(componentType);
                }else if (type instanceof ParameterizedType) {
                     ParameterizedType parameterizedType=(ParameterizedType) type;
                     Type[] arguments=parameterizedType.getActualTypeArguments();
                     for (int i = 0; i < arguments.length; i++) {
                        Type argumentsType=arguments[0];
                        System.out.println("ParameterizedType"+argumentsType);
                        getType(argumentsType);
                    }
                }else if (type instanceof WildcardType) {
                     WildcardType wildcardType=(WildcardType) type;
                    Type[] lowerTypes= wildcardType.getLowerBounds();
                     Type[] upperTypes=wildcardType.getUpperBounds();
                     if (lowerTypes.length!=0) {
                         System.out.println("WildcardTypeLower"+lowerTypes[0]);
                          getType(lowerTypes[0]);
                    }else if (upperTypes.length!=0) {
                         System.out.println("WildcardTypeUpper"+upperTypes[0]);
                        getType(upperTypes[0]);
                    }
                }else {
                    System.out.println("BasicType"+type);
                    System.out.println("我是基本数据类型");
                }
      }
      //测试代码
       Class<TestDom4j> clazz=TestDom4j.class;
          Field field=null;
          try {
            field=clazz.getDeclaredField("listParam");
            Type type=field.getGenericType();
             getType(type);
           } catch (NoSuchFieldException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

通过上面这段代码便可以获取各种对应的数据类型,在获取类型的时候一定要调用getGenericType()这个方法,否则无法获取的将是原始的数据类型,无法转换成其他数据类型。首先判断是不是GenericArrayType 类型,是的话则调用getGenericComponentType()方法获取数组元素的类型,然后递归调用该方法。第二步判断是不是ParameterizedType类型,是的话调用getActualTypeArguments方法获取每个泛型参数的类型,然后递归调用该方法。第三部判断是不是WildcardType通配符类型,是的话调用getLowerBounds和getUpperBounds获取通配符的上限和下限,然后递归调用该方法。
(2).通过反射调用类的静态方法时对象传递null值即可,比如上面代码中调用包装数据类型的Valueof方法时传递的也是null。
五.总结
通过这个案例的学习,我们学习到了反射技术的强大和方便,对我们的案例感兴趣的同学也可以下载代码来查看。在下一篇文章中,我们将总结反射和动态代理以及他们的应用。