本篇博客主要是使用java代碼模擬spring的IOC容器,實現依賴注入;固然只是模擬spring容器中簡單的一點實現原理而已,加深一些本身對spring框架的底層原理的理解;java
使用的技術:dom4j xml解析技術 工廠模式 java反射技術spring
關於工廠模式:主要做用是對象的的解耦,經過容器中的方法獲取對象,而不是在須要的類中去 new 對象;針對接口編程,不須要關注具體的實現方式;編程
如:一個對象:Car 依賴的對象有 Engine Wheel Door框架
不用工廠模式此時若是須要建立Car,則須要在Car 對象中 建立 Engine Wheel Door 三個對象,這樣的弊端是在代碼中耦合了太多其餘的對象:此時若是Engine 對象和 Wheel對象改變了屬性,那麼調用者在調用時也須要作修改;若是依賴的對象不少的話,對於調用者是一件很麻煩的事情;dom
public class Car implements ICar{ private Engine engine; private Wheel wheel; private Door door; public Car(Engine engine, Wheel wheel, Door door) { super(); this.engine = engine; this.wheel = wheel; this.door = door; } public static void main(String[] args) { Engine engine=new Engine(); Wheel wheel=new Wheel(); Door door=new Door(); Car car=new Car(new Engine(), new Wheel(), new Door()); } }
此時就引入了工廠模式:ide
Car的工廠類以下所示:this
public class Factory implements Ifactory{ @Override public Car createCar() { Engine engine=new Engine(); Wheel wheel=new Wheel(); Door door=new Door(); return new Car(engine, wheel, door); } }
調用者須要Car的對象的時候只須要調用工廠類的 createCar() 方法便可:這是就算有依賴的類更改了屬性或者方法,對於調用方而言能夠不作任何更改;url
public static void main(String[] args) { Factory f=new Factory(); ICar car=f.createCar(); }
固然,這樣並不完美:試想一個場景:Engine 有 大衆的 豐田的 Wheel 也有大衆和豐田的 Door 也分爲大衆和豐田的,如今調用方須要的是大衆的Carspa
那麼在工廠類中就須要更改成大衆類,若是有上千個品牌,那麼工廠類的維護也是一件很痛苦的事,這是引入統一接口,接口的引用指向具體的實現類,具體的實現由調用方指定,這樣就減小了代碼的耦合;code
可是,基於接口的工廠模式仍是不完美,這種方式:我須要在工廠類中 new 對象 而且須要經過構造器或者是set方法把須要注入的對象注入進來,此時,試想一個場景:若是你有100個對象須要被其餘對象注入,那麼這個工廠類則須要維護100 個方法來返回對象;工廠類的維護一件很複雜的任務;
這是能夠想到用配置文件來管理這些類的名稱,而後在工廠類中經過在配置文件中的類的名稱實現類的建立和注入;這樣須要增刪改工廠類的建立對象則能夠經過更改配置文件來實現,這樣就方便了不少;
這就是一種比較完美的實現方式:IOC模式;
下面經過java代碼來實現ioc模式:
mydoc.xml的配置以下:
<beans> <bean id="userController" class="bz.beppe.controller.UserController"> <property name="userService" ref="userService"></property> </bean> <bean id="userService" class="bz.beppe.serviceImpl.UserServiceImpl"></bean> </beans>
userService的接口代碼:
public interface UserService { public void getUser(); }
實現代碼以下:
public class UserServiceImpl implements UserService{ @Override public void getUser() { System.out.println("i am beppe!!"); } }
UserController的代碼以下
public class UserController { private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } public void getUser(){ userService.getUser(); // System.out.println(user.getName()); } public void say(){ System.out.println("say something"); } }
下面模擬spring 的Ioc來實現最基本的依賴注入:
工廠接口以下:BeanFactory 這個接口不作任何的實現,只有一個getBean(String id) 的方法 具體的具體的工廠類須要實現這個接口,而且覆蓋相應的方法:
public interface BeanFactory { public Object getBean(String id); }
如下爲BeanFatory的具體實現類;IOC容器的關鍵,實現依賴注入;這裏用一個Map容器來存儲對象,而且能夠經過key來獲取對象
public class ClassPathXmlApplicationContext implements BeanFactory{ private Map<String,Object> beans=new HashMap<String,Object>(); //建立容器,用來存儲須要被IOC容器管理的對象 // 構造該容器時就初始化beans的值 public ClassPathXmlApplicationContext(String filePath){ //在建立工廠對象的時候就將須要被管理的對存放到map中 Document doc = getDocument(filePath); //解析 xml 文件 Element rootElement = doc.getRootElement(); List<Element> beanElements = rootElement.elements(); for (Element beanElement : beanElements) { //獲取bean 標籤 而且實例化對象 String idStr = beanElement.attributeValue("id"); String classStr=beanElement.attributeValue("class"); System.out.println(idStr+":"+classStr); try { Class<?> clazz = Class.forName(classStr); Object obj = clazz.newInstance(); beans.put(idStr, obj); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } for (Element beanElement1 : beanElements) { List<Element> propertyElements = beanElement1.elements(); for (Element propertyElement : propertyElements) { //獲取<bean> 標籤下的全部property標籤 而且 經過調用set方法來進行注入:關鍵的方法 Element parentElement=propertyElement.getParent(); Object contoller=getBean(parentElement.attributeValue("id")); String nameStr = propertyElement.attributeValue("name"); String refStr=propertyElement.attributeValue("ref"); Object service = getBean(refStr); String methodStr="set"+nameStr.substring(0, 1).toUpperCase()+nameStr.substring(1); try { Method method=contoller.getClass().getMethod(methodStr, service.getClass().getInterfaces()[0]); method.invoke(contoller, service); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } @Override public Object getBean(String id) { // TODO Auto-generated method stub return beans.get(id); } private Document getDocument(String filePath){ try { // URL url=new URL(filePath); SAXReader redaer=new SAXReader(); Document doc = redaer.read(filePath); return doc; } catch (DocumentException e) { // TODO Auto-generated catch block System.out.println("路徑不存在"); e.printStackTrace(); } return null; } }
這就是一個簡單的spring IOC容器,固然,功能遠沒有spring IOC那麼強大,基本的實現原理是一致的;