1. 程式人生 > >自己動手寫spring

自己動手寫spring

Java程式碼 複製程式碼
  1. publicstaticvoid main(String[] args) {   
  2.         ApplicationContext context = new FileSystemXmlApplicationContext(   
  3. "applicationContext.xml");   
  4.         Animal animal = (Animal) context.getBean("animal");   
  5.         animal.say();   
  6.     }  
public static void main(String[] args) {
		ApplicationContext context = new FileSystemXmlApplicationContext(
				"applicationContext.xml");
		Animal animal = (Animal) context.getBean("animal");
		animal.say();
	}


這段程式碼你一定很熟悉吧,不過還是讓我們分析一下它吧,首先是applicationContext.xml

Java程式碼 複製程式碼
  1. <bean id="animal"class="phz.springframework.test.Cat">   
  2.         <property name="name" value="kitty" />   
  3.     </bean>  
<bean id="animal" class="phz.springframework.test.Cat">
		<property name="name" value="kitty" />
	</bean>


他有一個類phz.springframework.test.Cat

Java程式碼 複製程式碼
  1. publicclass Cat implements Animal {   
  2. private String name;   
  3. publicvoid say() {   
  4.         System.out.println("I am " + name + "!");   
  5.     }   
  6. publicvoid setName(String name) {   
  7. this.name = name;   
  8.     }   
  9. }  
public class Cat implements Animal {
	private String name;
	public void say() {
		System.out.println("I am " + name + "!");
	}
	public void setName(String name) {
		this.name = name;
	}
}


實現了phz.springframework.test.Animal介面

Java程式碼 複製程式碼
  1. publicinterface Animal {   
  2. publicvoid say();   
  3. }  
public interface Animal {
	public void say();
}


很明顯上面的程式碼輸出I am kitty!

那麼到底Spring是如何做到的呢?
接下來就讓我們自己寫個Spring 來看看Spring 到底是怎麼執行的吧!

首先,我們定義一個Bean類,這個類用來存放一個Bean擁有的屬性

Java程式碼 複製程式碼
  1. /* Bean Id */
  2. private String id;   
  3. /* Bean Class */
  4. private String type;   
  5. /* Bean Property */
  6. private Map<String, Object> properties = new HashMap<String, Object>();  
/* Bean Id */
	private String id;
	/* Bean Class */
	private String type;
	/* Bean Property */
	private Map<String, Object> properties = new HashMap<String, Object>();


一個Bean包括id,type,和Properties。

接下來Spring 就開始載入我們的配置檔案了,將我們配置的資訊儲存在一個HashMap中,HashMap的key就是Bean 的 Id ,HasMap 的value是這個Bean,只有這樣我們才能通過context.getBean("animal")這個方法獲得Animal這個類。我們都知道Spirng可以注入基本型別,而且可以注入像List,Map這樣的型別,接下來就讓我們以Map為例看看Spring是怎麼儲存的吧

Map配置可以像下面的

Java程式碼 複製程式碼
  1. <bean id="test"class="Test">   
  2.         <property name="testMap">   
  3.             <map>   
  4.                 <entry key="a">   
  5.                     <value>1</value>   
  6.                 </entry>   
  7.                 <entry key="b">   
  8.                     <value>2</value>   
  9.                 </entry>   
  10.             </map>   
  11.         </property>   
  12.     </bean>  
<bean id="test" class="Test">
		<property name="testMap">
			<map>
				<entry key="a">
					<value>1</value>
				</entry>
				<entry key="b">
					<value>2</value>
				</entry>
			</map>
		</property>
	</bean>


Spring是怎樣儲存上面的配置呢?,程式碼如下:

Java程式碼 複製程式碼
  1. if (beanProperty.element("map") != null) {   
  2.                     Map<String, Object> propertiesMap = new HashMap<String, Object>();   
  3.                     Element propertiesListMap = (Element) beanProperty   
  4.                             .elements().get(0);   
  5.                     Iterator<?> propertiesIterator = propertiesListMap   
  6.                             .elements().iterator();   
  7. while (propertiesIterator.hasNext()) {   
  8.                         Element vet = (Element) propertiesIterator.next();   
  9. if (vet.getName().equals("entry")) {   
  10.                             String key = vet.attributeValue("key");   
  11.                             Iterator<?> valuesIterator = vet.elements()   
  12.                                     .iterator();   
  13. while (valuesIterator.hasNext()) {   
  14.                                 Element value = (Element) valuesIterator.next();   
  15. if (value.getName().equals("value")) {   
  16.                                     propertiesMap.put(key, value.getText());   
  17.                                 }   
  18. if (value.getName().equals("ref")) {   
  19.                                     propertiesMap.put(key, new String[] { value   
  20.                                             .attributeValue("bean") });   
  21.                                 }   
  22.                             }   
  23.                         }   
  24.                     }   
  25.                     bean.getProperties().put(name, propertiesMap);   
  26.                 }  
if (beanProperty.element("map") != null) {
					Map<String, Object> propertiesMap = new HashMap<String, Object>();
					Element propertiesListMap = (Element) beanProperty
							.elements().get(0);
					Iterator<?> propertiesIterator = propertiesListMap
							.elements().iterator();
					while (propertiesIterator.hasNext()) {
						Element vet = (Element) propertiesIterator.next();
						if (vet.getName().equals("entry")) {
							String key = vet.attributeValue("key");
							Iterator<?> valuesIterator = vet.elements()
									.iterator();
							while (valuesIterator.hasNext()) {
								Element value = (Element) valuesIterator.next();
								if (value.getName().equals("value")) {
									propertiesMap.put(key, value.getText());
								}
								if (value.getName().equals("ref")) {
									propertiesMap.put(key, new String[] { value
											.attributeValue("bean") });
								}
							}
						}
					}
					bean.getProperties().put(name, propertiesMap);
				}



接下來就進入最核心部分了,讓我們看看Spring 到底是怎麼依賴注入的吧,其實依賴注入的思想也很簡單,它是通過反射機制實現的,在例項化一個類時,它通過反射呼叫類中set方法將事先儲存在HashMap中的類屬性注入到類中。讓我們看看具體它是怎麼做的吧。
首先例項化一個類,像這樣

Java程式碼 複製程式碼
  1. publicstatic Object newInstance(String className) {   
  2.         Class<?> cls = null;   
  3.         Object obj = null;   
  4. try {   
  5.             cls = Class.forName(className);   
  6.             obj = cls.newInstance();   
  7.         } catch (ClassNotFoundException e) {   
  8. thrownew RuntimeException(e);   
  9.         } catch (InstantiationException e) {   
  10. thrownew RuntimeException(e);   
  11.         } catch (IllegalAccessException e) {   
  12. thrownew RuntimeException(e);   
  13.         }   
  14. return obj;   
  15.     }  
public static Object newInstance(String className) {
		Class<?> cls = null;
		Object obj = null;
		try {
			cls = Class.forName(className);
			obj = cls.newInstance();
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		} catch (InstantiationException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		}
		return obj;
	}


接著它將這個類的依賴注入進去,像這樣

Java程式碼 複製程式碼
  1. publicstaticvoid setProperty(Object obj, String name, String value) {   
  2.         Class<? extends Object> clazz = obj.getClass();   
  3. try {   
  4.             String methodName = returnSetMthodName(name);   
  5.             Method[] ms = clazz.getMethods();   
  6. for (Method m : ms) {   
  7. if (m.getName().equals(methodName)) {   
  8. if (m.getParameterTypes().length == 1) {   
  9.                         Class<?> clazzParameterType = m.getParameterTypes()[0];   
  10.                         setFieldValue(clazzParameterType.getName(), value, m,   
  11.                                 obj);   
  12. break;   
  13.                     }   
  14.                 }   
  15.             }   
  16.         } catch (SecurityException e) {   
  17. thrownew RuntimeException(e);   
  18.         } catch (IllegalArgumentException e) {   
  19. thrownew RuntimeException(e);   
  20.         } catch (IllegalAccessException e) {   
  21. thrownew RuntimeException(e);   
  22.         } catch (InvocationTargetException e) {   
  23. thrownew RuntimeException(e);   
  24.         }   
  25. }  
public static void setProperty(Object obj, String name, String value) {
		Class<? extends Object> clazz = obj.getClass();
		try {
			String methodName = returnSetMthodName(name);
			Method[] ms = clazz.getMethods();
			for (Method m : ms) {
				if (m.getName().equals(methodName)) {
					if (m.getParameterTypes().length == 1) {
						Class<?> clazzParameterType = m.getParameterTypes()[0];
						setFieldValue(clazzParameterType.getName(), value, m,
								obj);
						break;
					}
				}
			}
		} catch (SecurityException e) {
			throw new RuntimeException(e);
		} catch (IllegalArgumentException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		} catch (InvocationTargetException e) {
			throw new RuntimeException(e);
		}
}


最後它將這個類的例項返回給我們,我們就可以用了。我們還是以Map為例看看它是怎麼做的,我寫的程式碼裡面是建立一個HashMap並把該HashMap注入到需要注入的類中,像這樣,

Java程式碼 複製程式碼
  1. if (value instanceof Map) {   
  2.                 Iterator<?> entryIterator = ((Map<?, ?>) value).entrySet()   
  3.                         .iterator();   
  4.                 Map<String, Object> map = new HashMap<String, Object>();   
  5. while (entryIterator.hasNext()) {   
  6.                     Entry<?, ?> entryMap = (Entry<?, ?>) entryIterator.next();   
  7. if (entryMap.getValue() instanceof String[]) {   
  8.                         map.put((String) entryMap.getKey(),   
  9.                                 getBean(((String[]) entryMap.getValue())[0]));   
  10.                     }   
  11.                 }   
  12.                 BeanProcesser.setProperty(obj, property, map);   
  13.             }  
if (value instanceof Map) {
				Iterator<?> entryIterator = ((Map<?, ?>) value).entrySet()
						.iterator();
				Map<String, Object> map = new HashMap<String, Object>();
				while (entryIterator.hasNext()) {
					Entry<?, ?> entryMap = (Entry<?, ?>) entryIterator.next();
					if (entryMap.getValue() instanceof String[]) {
						map.put((String) entryMap.getKey(),
								getBean(((String[]) entryMap.getValue())[0]));
					}
				}
				BeanProcesser.setProperty(obj, property, map);
			}


好了,這樣我們就可以用Spring 給我們建立的類了,是不是也不是很難啊?當然Spring能做到的遠不止這些,這個示例程式僅僅提供了Spring最核心的依賴注入功能中的一部分。
本文參考了大量文章無法一一感謝,在這一起感謝,如果侵犯了你的版權深表歉意,很希望對大家有幫助!

附件中包含該山寨Spring的原始碼,核心只有五個類,還有一個測試程式,phz.springframework.test.AnimalSayApp,可以直接執行。