自定义IOC工厂

IOC概述
IOC(inversion of control)的中文解释是“控制反转”,对象的使用者不是创建者. 作用是将对象的创建 反转给spring框架来创建和管理。

控制反转怎么去理解呢。 其实它反转的是什么呢,是对象的创建工作。 举个例子:平常我们在servlet或者service里面创建对象,都是使用new 的方式来直接创建对象,现在有了spring之后,我们就再也不new对象了,而是把对象创建的工作交给spring容器去维护。我们只需要问spring容器要对象即可

ioc 的作用:削减计算机程序的耦合(解除我们代码中的依赖关系)。

分析和IOC的引入

上一小节我们通过使用工厂模式,实现了表现层——业务层以及业务层——持久层的解耦。

它的核心思想就是:

1、通过读取配置文件反射创建对象。

2、把创建出来的对象都存起来,当我们下次使用时可以直接从存储的位置获取。

这里面要解释两个问题:

第一个:存哪去?

分析:由于我们是很多对象,肯定要找个集合来存。这时候有 Map 和 List 供选择。

到底选 Map 还是 List 就看我们有没有查找需求。有查找需求,选 Map。

所以我们的答案就是:在应用加载时,创建一个 Map,用于存放三层对象。我们把这个 map 称之为容器。

第二个: 什么是工厂?

工厂就是负责给我们从容器中获取指定对象的类。这时候我们获取对象的方式发生了改变。

原来:我们在获取对象时,都是采用 new 的方式。 是主动的。

  • 老方式
    在这里插入图片描述
  • 现在 我们获取对象时,同时跟工厂要,有工厂为我们查找或者创建对象。 是被动的。
    在这里插入图片描述
    小结
  1. IOC概念: 控制反转. 说白了: 就是把对象交给Spring框架去创建和管理. 我们要用对象, 直接从Spring的IOC容器【集合】里面获得
  2. 好处: 解耦, 到时候我们只需要修改配置文件, 不需要修改源码

知识点-工厂模式解耦
在进行软件设计时,应力争做到高内聚,低耦合。
什么是高内聚,低耦合?
就好比如台上的杂技表演,表演者在台上相互配合,少了谁也完成不了表演,而表演者在台下是互不打扰的,比如张三少了李四不可能就活不下去把?
在这里插入图片描述
在代码中体现
早期我们的 JDBC 操作,注册驱动时,我们为什么不使用 DriverManager 的 register 方法,而是采
用 Class.forName 的方式?
原因就是: 我们的类依赖了数据库的具体驱动类(MySQL) ,如果这时候更换了数据库(比如 Oracle) ,
需要修改源码来重新数据库驱动。这显然不是我们想要的。

/**
* 程序的耦合
* 耦合:程序间的依赖关系
* 包括:
* 		类之间的依赖
* 		方法间的依赖
* 解耦:
* 		降低程序间的依赖关系
* 实际开发中:
* 		应该做到:编译期不依赖,运行时才依赖。
* 解耦的思路:
*		第一步:使用反射来创建对象,而避免使用 new 关键字。
*		第二步:通过读取配置文件来获取要创建的对象全限定类名
*/
public class JdbcDemo1 {
    public static void main(String[] args) throws Exception{
        //1.注册驱动 
         //DriverManager.registerDriver(new Driver());
        Class.forName("com.mysql.jdbc.Driver");
        //2.获取连接
        //3.获取操作数据库的预处理对象
        //4.执行 SQL,得到结果集
        //5.遍历结果集
        //6.释放资源
    }
}

解决程序耦合的思路
当是我们讲解 jdbc 时,是通过反射来注册驱动的,代码如下:
Class.forName(“com.mysql.jdbc.Driver”);//此处只是一个字符串
此时的好处是,我们的类中不再依赖具体的驱动类,此时就算删除 mysql 的驱动 jar 包,依然可以编译(运行就不要想了没有驱动不可能运行成功的) 。

同时,也产生了一个新的问题, mysql 驱动的全限定类名字符串是在 java 类中写死的,一旦要改还是要修改源码。解决这个问题也很简单,使用配置文件配置

工厂模式解耦
工厂模式解耦思路
在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候, 让一个类中的方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。那么,这个读取配置文件, 创建和获取三层对象的类就是工厂

实现

  • 添加坐标依赖

    <dependencies>
      <!-- 解析 xml 的 dom4j -->
      <dependency>
        <groupId>dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>1.6.1</version>
      </dependency>
      <!-- dom4j 的依赖包 jaxen -->
      <dependency>
        <groupId>jaxen</groupId>
        <artifactId>jaxen</artifactId>
        <version>1.1.6</version>
      </dependency>
      <!--单元测试-->
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.10</version>
        <scope>test</scope>
      </dependency>
    </dependencies>
    
  • AccountDao .java

      public interface AccountDao {
          /**
           * 保存账户
           */
          void save();
      }
    

AccountDaoImpl.java

public class AccountDaoImpl implements AccountDao {
    /**
     * 保存账户
     */
    @Override
    public void save() {
        System.out.println("AccountDaoImpl... save()");
    }
}
  • AccountService.java

      public interface AccountService {
          /**
           * 保存账户
           */
          void save();
      }
    

    AccountServiceImpl.java
    public class AccountServiceImpl implements AccountService {

      private AccountDao accountDao = (AccountDao) BeanFactory.getBean("accountDao");
      /**
       * 保存账户
       */
      @Override
      public void save() {
          System.out.println("AccountServiceImpl---saveAccount()");
          accountDao.save();
      }
    

    }

  • Client.java

      public class Client {
      
      public static void main(String[] args) {
          AccountService accountService = (AccountService) BeanFactory.getBean("accountService");
          accountService.save();
      }
    

    }

  • BeanFactory.java
    下面的通过 BeanFactory 中 getBean 方法获取对象就解决了我们代码中对具体实现类的依赖。

      public class BeanFactory {
      
      //定义map
      private static Map<String, Object> beans;
    
      static{
      	try {
      		beans = new HashMap<String, Object>();
      		//解析xml, 初始化beans集合
      		//1. 创建SaxReader对象
      		SAXReader saxReader = new SAXReader();
      		//2. 读取配置文件 获得document对象 
      		Document document = saxReader.read(BeanFactory.class.getClassLoader().getResourceAsStream("applicationContext.xml"));
      		//3. 获得所有的bean标签对象List
      		List<Element> beanList = document.selectNodes("//bean");
      		//4. 遍历
      		for (Element element : beanList) {
      			//获得id的属性值作为map的key
      			String id = element.attributeValue("id");
      			//获得class的属性值,反射得到对象作为map的value
      			String className = element.attributeValue("class");
      			beans.put(id, Class.forName(className).newInstance());
      		}
      		
      	} catch (Exception e) {
      		e.printStackTrace();
      	}
      }
    
      
      public static Object getBean(String id){
      	return beans.get(id);
      }
    

    }

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<!--id就是接口的名字, class实现类的全限定名  -->
	<bean id="userDao" class="com.lakes.dao.impl.UserDaoImpl"></bean>
	<bean id="userService" class="com.lakes.service.impl.UserServiceImpl"></bean>
</beans>

小结

  1. 先把配置文件的所有的bean标签解析出来
  2. 创建对象
  3. 把id作为key, 把对象作为value 存到容器(Map)

对象不需要我们创建了, 直接从容器里面取

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值