Java反射、泛型和註解實戰之Spring核心注入IOC的實現
一.前言
通過前兩篇文章的學習,我們已經對Java中這三個模組的知識有了初步的瞭解。為了將鞏固之前的知識,今天我們將綜合運用這三個模組的知識,來實現一個類似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=listProper