zoukankan      html  css  js  c++  java
  • spring 原理1:java 模拟springIOC容器

    本篇博客主要是使用java代码模拟spring的IOC容器,实现依赖注入;当然只是模拟spring容器中简单的一点实现原理而已,加深一些自己对spring框架的底层原理的理解;

    使用的技术:dom4j xml解析技术   工厂模式    java反射技术

    关于工厂模式:主要作用是对象的的解耦,通过容器中的方法获取对象,而不是在需要的类中去 new 对象;针对接口编程,不需要关注具体的实现方式;

    如:一个对象:Car 依赖的对象有 Engine   Wheel  Door

    不用工厂模式此时如果需要创建Car,则需要在Car 对象中 创建 Engine   Wheel  Door 三个对象,这样的弊端是在代码中耦合了太多其他的对象:此时如果Engine 对象和 Wheel对象改变了属性,那么调用者在调用时也需要做修改;如果依赖的对象很多的话,对于调用者是一件很麻烦的事情;

    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());
    	}
    }
    

    此时就引入了工厂模式:

    Car的工厂类如下所示:

    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() 方法即可:这是就算有依赖的类更改了属性或者方法,对于调用方而言可以不做任何更改;

    public static void main(String[] args) {
            Factory f=new Factory();
            ICar car=f.createCar();
        }

    当然,这样并不完美:试想一个场景:Engine 有 大众的 丰田的   Wheel 也有大众和丰田的  Door 也分为大众和丰田的,现在调用方需要的是大众的Car

    那么在工厂类中就需要更改为大众类,如果有上千个品牌,那么工厂类的维护也是一件很痛苦的事,这是引入统一接口,接口的引用指向具体的实现类,具体的实现由调用方指定,这样就减少了代码的耦合;

    但是,基于接口的工厂模式还是不完美,这种方式:我需要在工厂类中 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那么强大,基本的实现原理是一致的;

  • 相关阅读:
    开源mvcpager分页控件分页实例
    「YNOI2016」自己的发明
    「SNOI2017」一个简单的询问
    势能分析(splay分析)
    「Ynoi2018」未来日记
    「JOISC 2016 Day 1」棋盘游戏
    「ZJOI2014」璀灿光华
    「ZJOI2019」线段树
    「科技」区间众数
    「ZJOI2017」树状数组
  • 原文地址:https://www.cnblogs.com/beppezhang/p/6601092.html
Copyright © 2011-2022 走看看