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那么强大,基本的实现原理是一致的;

相关文章
相关标签/搜索