spring 原理1:java 模擬springIOC容器

本篇博客主要是使用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那麼強大,基本的實現原理是一致的;

相關文章
相關標籤/搜索