zoukankan      html  css  js  c++  java
  • spring学习之依赖注入DI与控制反转IOC

    一 Ioc基础

    1.什么是Ioc?

      Ioc(Inversion of Control)既控制反转,Ioc不是一种技术,而是一种思想,在Java开发中意味着将设计好的对象交给容器来进行控制,并不是像传统的程序一样在对象内部进行创建。

    2.如何理解Ioc?

      在传统的程序中,当某个Java对象(调用者)需要调用另一个Java对象(被调用者,既被依赖对象)时,调用者通常会采用“new 调用者”的代码方式来创建对象。

      理解Ioc的关键在于要理解“谁控制谁,控制什么,为何是反转,哪些方面反转了”

      * 谁控制谁,控制什么:在传统的Java程序中,我们通常都是在一个类的内部直接创建一个对象(使用new),这样就是程序主动的去创建一个对象,控制权在程序,而在spring的Ioc中,是由一个专门的容器来创建这些对象,控制权不在程序了。谁控制谁?Ioc容器控制了对象。控制什么?Ioc容器主要控制了一个类对外部资源(对象,文件)的获取。

      *为何是反转,哪些方面反转了:

       有了反转,必定由正转:

       正转:在传统的程序中,是由自己在一个对象(一个类中)直接去创建一个1依赖对象,这就是正转。

       反转:反转就是由Ioc容器来创建对象并且给类注入此对象。

       为何是反转?因为是由容器来创建并且帮助注入依赖对象,对象并没有直接去创建(new)一个对象而是被动的接受依赖对象,所以是反转。

       哪些方面反转了?依赖对象的获取被反转了。

                           

                        传统应用程序示意图  

                         

                                      使用Ioc容器后的程序结构示意图

    3.Ioc的优点

      Ioc不是一种技术,而是一种思想,是一个重要的面向对象的编程法则,他能指导我们如何设计出松耦合,更优良的程序,传统的应用程序是我们在类的内部主动创建依赖对象,从而导致类与类之间的高耦合,难以测试,有了Ioc容器后,由容器来创建和查找依赖对象,并给对象注入依赖对象,所以对象与对象之间是松散耦合,方便测试,利于功能复用。

      Ioc对编程带来的最大改变不是代码上,而是思想上,应用程序原本是老大,要获取什么资源都是主动的去创建,但是在Ioc思想种,应用程序就变动被动了,被动地等待Ioc容器来创建并注入它所需的资源。

      Ioc容器很好的体现了面向对象的设计法则之一:好莱坞法则“别找我们,我们找你”,即由Ioc容器来创建并注入对象,而不是由对象来找。

         

    二 依赖注入

    1.什么是依赖注入(DI)?

      依赖注入(DI)是控制反转(Ioc)的含义相同,只不过是从不同的角度来看待。

    2.依赖注入的目的?

      依赖注入的目的并非是为系统带来更多的功能,而是为了提高组件的重用率,并为系统搭建一个灵活的可扩展的平台。

    3.理解DI的关键?

      理解DI的关键是“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么?”

      *谁依赖谁:应用程序依赖Ioc容器。

      *为什么需要依赖:应用程序需要Ioc容器来提供对象所需的资源。

      *谁注入谁:Ioc容器注入应用程序所需的依赖对象

      *注入了什么:注入了某个对象所需的外部资源。

    4.Ioc和DI的关系

      Ioc和DI相当于一回事,只不过是看待问题的角度不同:

      Ioc:spring反向控制应用程序所需的资源;

      DI:应用程序依赖spring为其提供资源

    5.依赖注入的方式

      依赖注入的作用是在使用spring框架时,动态地将其所依赖的对象注入到Bean组件中,其实现方法有两种:

      ☞ 属性setter方法注入:指的是spring容器使用setter方法注入被依赖的实例。通过调用无参构造器或者无参静态工厂方法实例化Bean后,调用该bean的setter方法,即可实现基于setter方法的依赖注入。

      ☞ 构造方法注入:指spring容器使用构造方法注入被依赖的实例。基于构造方法的依赖注入是通过调用带参数的构造方法来实现,每个参数代表着一个依赖。

      下面是使用setter方法来注入依赖对象

       (1)创建一个UserDao接口,该接口中有一个方法say方法

    package com.itheima.ioc;
    
    public interface  UserDao {
        public void say();
    }

      (2)创建一个UserDaoImpl的类,该类实现了接口UserDao

    package com.itheima.ioc;
    
    public class UserDaoImpl implements UserDao {
        @Override
        public void say() {
            System.out.println("UserDao say hello Word!");
    
        }
    }

      (3)创建一个UserService接口

    package com.itheima.ioc;
    
    public interface UserService {
        public void say();
    }

     (4)创建一个UserServiceImpl类,该类实现了UserService 接口,类中有一个属性UserDao,并且有一个方法setter,该方法是用于Ioc容器给UserServiceImpl注入UserDao对象。

    package com.itheima.ioc;
    
    public class UserServiceImpl implements UserService {
     
        //声明UserDao属性
        private UserDao UserDao;
        
        //添加UserDao属性的setter方法
        public void setUserDao(UserDao userDao) {
            UserDao = userDao;
        }
    
        //实现接口中的方法
        @Override
        public void say() {
            //调用userDao的方法
            this.UserDao.say();
            System.out.println("userService say hello World!");
        }
    }

       

      (5)配置applicationContext.xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> 
        
        <!-- 将指定的类配置给Spring,让Spring创建其对象的实例 -->
        <bean id="userDao" class="com.itheima.ioc.UserDaoImpl"/>
        
        <!-- 添加一个id为userService的bean -->
        <bean id="userService" class="com.itheima.ioc.UserServiceImpl">
            <!-- 将id为userDao的bean实例注入到user Service实例中 -->
            <property name="userDao" ref="userDao"/>
        </bean>
    </beans>

      <property>元素是<bean>元素的子元素,它用于调用Bean实例中的setUserDao()方法完成属性赋值,从而实现依赖注入。其name属性表示Bean实例中相应属性名,ref属性用于指定属性值。

      (6)Test测试类

    package com.itheima.ioc;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class DITest {
    public static void main(String[] args) {
    //1.初始化spring容器,加载配置文件
    ApplicationContext applicationContext=
    new ClassPathXmlApplicationContext("applicationContext.xml");
    //2.通过容器来获取UserService实例
    UserService userService=(UserService) applicationContext.getBean("userService");

    //3.调用实例中的方法
    userService.say();
    }
    }

      (7)程序结果

      

    三 Ioc容器

      容器中的两种表示形式:BeanFactoryApplicationContext

      springIoc把BeanFactory的实现当作低级容器,把ApplicationContext的实现当作高级容器

    1.两个容器之间的区别:

      BeanFactory:容器在启动的时候并不会实例化bean,只有当用户调用getBean时才会对配置好的bean进行实例化。

      ApplicationContext容器:当容器启动时,容器就已经实例化好了所有配置的bean。

    2.如何延迟实例化:

      对于在ApplicationContext容器启动便进行了实例化,可以通过两种方法来延迟实例化:

      ☞ 可以在bean元素配置lazy-init=true来让bean延迟实例化;

      ☞ 可以在beans元素里配置lazy-init=true来让这个beans里的所有bean都延迟实例化;

    3.如何选择延迟化和非延迟化

      ☞ 对于系统资源比较少的可以使用延迟实例化;

      ☞ 对于web应用,一般选择迫切实例化;

      ☞ 在web应用中,我们一般把比较耗时的事情放在系统启动的时候完成;

  • 相关阅读:
    grape入门
    半个小时写的一个二叉搜索树,实现了增,删,查功能
    Struts2 MVC 同 Spring MVC 的比较
    阿里巴巴 2016 java 实习岗位笔试题(昨天出炉)
    自己用20分钟java实现的单向链表(含有增删改查操作)
    关于 古人劝学 --写的真心是好 真的有收获
    JDK动态代理堆栈图详解--干货
    论闷声挣大钱与网红现象
    spring beanfactory --实现自己简单的 bean工厂类
    Spring IOC example one
  • 原文地址:https://www.cnblogs.com/zhilili/p/11383347.html
Copyright © 2011-2022 走看看