2021-05-03 09:46  阅读(158)
文章分类:Spring 入门教程 文章标签:SpringSpring 教程
©  原文作者:一点教程 原文地址:http://www.yiidian.com/spring/

IOC容器的底层实现其实就是利用工厂设计模式。接下来我们通过工厂设计模式模拟一个小型的IOC容器,让大家对IOC的底层原理更加清晰些。

一、搭建案例程序

1)CustomerDao接口:

    
    package com.yiidian.dao;
    
    public interface CustomerDao {
    
    	public void save();
    	
    }
    

2)CustomerDaoMySQLImpl:(模拟MySQL版本的Dao实现)

    
    package com.yiidian.dao.impl;
    
    import com.yiidian.dao.CustomerDao;
    /**
     * 
     * @author http://www.yiidian.com
     *
     */
    public class CustomerDaoMySQLImpl implements CustomerDao {
    
    	@Override
    	public void save() {
    		System.out.println("把客户数据保存到mysql数据");
    	}
    
    }

3)CustomerService接口:

    
    package com.yiidian.service;
    /**
     * 
     * @author http://www.yiidian.com
     *
     */
    public interface CustomerService {
    
    	public void save();
    }

4)CustomerServiceImpl实现类:

    
    package com.yiidian.service.impl;
    
    import com.yiidian.dao.CustomerDao;
    import com.yiidian.dao.impl.CustomerDaoImpl;
    import com.yiidian.service.CustomerService;
    /**
     * 
     * @author http://www.yiidian.com
     *
     */
    public class CustomerServiceImpl implements CustomerService {
    	//1.传统方法,直接new对象.
    	private CustomerDao customerDao = new CustomerDaoImpl();
    
    	@Override
    	public void save() {
    		customerDao.save();
    	}
    
    }

5)ActionDemo类(模拟Struts2的Action):

    
    package com.yiidian.web;
    
    import com.yiidian.service.CustomerService;
    import com.yiidian.service.impl.CustomerServiceImpl;
    /**
     * 
     * @author http://www.yiidian.com
     *
     */
    public class ActionDemo {
    
    	public static void main(String[] args) {
    		//传统方式调用业务,直接new对象
    		CustomerService customerService = new CustomerServiceImpl();
    		customerService.save();
    	}
    }
    

6)运行ActionDemo的main方法,执行结果为:

20210503094602402_1.png

二、扩展程序,发现问题

1)给CustomerDao接口添加多一个实现类,CustomerDaoOracleImpl(模拟Oracle的Dao实现):

    
    package com.yiidian.dao.impl;
    
    import com.yiidian.dao.CustomerDao;
    /**
     * 
     * @author http://www.yiidian.com
     *
     */
    public class CustomerDaoOracleImpl implements CustomerDao {
    
    	@Override
    	public void save() {
    		System.out.println("保存客户数据保存Oracle");
    	}
    
    }

2)这时我们需要在CustomerServiceImpl类中调用CustomerDaoOracleImpl的方法,需要手动修改代码实现:

    
    package com.yiidian.service.impl;
    
    import com.yiidian.dao.CustomerDao;
    import com.yiidian.dao.impl.CustomerDaoOracleImpl;
    import com.yiidian.service.CustomerService;
    /**
     * 
     * @author http://www.yiidian.com
     *
     */
    public class CustomerServiceImpl implements CustomerService {
    	//1.传统方法,直接new对象.
    	//private CustomerDao customerDao = new CustomerDaoMySQLImpl();
    	private CustomerDao customerDao = new CustomerDaoOracleImpl(); //(弊端:耦合性太高,修改源代码)
    
    	@Override
    	public void save() {
    		customerDao.save();
    	}
    
    }

3)运行ActionDemo,查看结果:
20210503094602402_2.png

**总结问题:**我们每次为CustomerDao接口扩展了实现类,业务层需要修改代码才可以实现切换具体的实现类,这种做法为“硬编码”方式,扩展性不好!接下来开始引用工厂设计模式改造程序。

三、利用工厂设计模式,改造程序

1)编写一个BeanFactory类,用于读取配置文件,创建程序需要的对象:

    
    package com.yiidian.ioc;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;
    
    /**
     * 创建对象的工厂(模拟简单IOC容器)
     * @author http://www.yiidian.com
     *
     */
    public class BeanFactory {
    	
    	/**
    	 * 初始化beans.properties文件
    	 */
    	private static Properties props = new Properties();
    	static{
    		InputStream in = BeanFactory.class.getResourceAsStream("/beans.properties");
    		try {
    			props.load(in);
    		} catch (IOException e) {
    			e.printStackTrace();
    			System.out.println("加载beans.properties文件失败");
    		}
    	}
    
    	/**
    	 * 从工厂获取一个对象
    	 * @return
    	 */
    	public static Object getBean(String name){
    		//根据name创建不同的对象
    		//1.通过name在properties文件找到类名称
    		String className = props.getProperty(name);
    		//2.通过反射构造类的对象
    		try {
    			return Class.forName(className).newInstance();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return null;
    	}
    }

2)在src目录编写beans.properties配置文件:

beans.properties:

    
    customerDao=com.yiidian.dao.impl.CustomerDaoMySQLImpl

3)改造CustomerServiceImpl类:

    
    /**
     * 
     * @author http://www.yiidian.com
     *
     */
    public class CustomerServiceImpl implements CustomerService {
    	//1.传统方法,直接new对象.
    	//private CustomerDao customerDao = new CustomerDaoMySQLImpl();
    	//private CustomerDao customerDao = new CustomerDaoOracleImpl(); //(弊端:耦合性太高,修改源代码)
    	
    	//2.IOC容器
    	private CustomerDao customerDao = (CustomerDao) BeanFactory.getBean("customerDao");
    
    	@Override
    	public void save() {
    		customerDao.save();
    	}
    
    }

4)运行ActionDemo,这时可以调用Dao程序,这时如果需求切换到CustomerDaoOracleImpl,只需要修改beans.properties,改为:

    
    customerDao=com.yiidian.dao.impl.CustomerDaoOracleImpl

再次运行ActionDemo,可以看到已经成功切换到Oracle的Dao实现啦!

到此为止,BeanFactory就是一个小型的IOC容器,可以创建我们程序中需要的一些对象。事实上,Spring的IOC容器的底层就是类似BeanFactory的原理

源码下载: http://pan.baidu.com/s/1geJrQCF

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> 工厂模式设计IOC容器
上一篇
SpringIOC的概念和作用
下一篇
SpringIOC的HelloWorld