zoukankan      html  css  js  c++  java
  • Spring IoC

    1.IoC是什么

    Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:

    ●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。

    ●为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

    用图例说明一下,传统程序设计如图2-1,都是主动去创建相关对象然后再组合起来:

     

    图2-1 传统应用程序示意图

    当有了IoC/DI的容器后,在客户端类中不再主动去创建这些对象了,如图2-2所示:

     

    图2-2有IoC/DI容器后程序结构示意图

    2. 1.1.2  IoC能做什么

    IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

    其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。

    IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。

    3. 2.1.3  IoCDI

    DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

    理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:

    ●谁依赖于谁:当然是应用程序依赖于IoC容器;

    ●为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;

    ●谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;

    ●注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。

     

    IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。

    注:如果想要更加深入的了解IoCDI,请参考大师级人物Martin Fowler的一篇经典文章《Inversion of Control Containers and the Dependency Injection pattern》,原文地址:http://www.martinfowler.com/articles/injection.html

     

     

    IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需在代码中new相关的对象,应用程序由IOC容器进行组装。

    spring IOC管理的对象,我们称为bean。bean就是spring容器初始化,装配,及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别。那IOC如何实例化bean、管理bean之间的依赖关系?这些就需要配置元数据。

    写个hello world(我用的是maven)

    pom.xml

    <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-context</artifactId>

            <version>4.3.4.RELEASE</version>

        </dependency>

        <dependency>

          <groupId>junit</groupId>

          <artifactId>junit</artifactId>

          <version>4.11</version>

          <scope>test</scope>

        </dependency>

        <dependency>

        <groupId>jdom</groupId>

        <artifactId>jdom</artifactId>

        <version>1.1</version>

    </dependency>

     

    helloInter.java

    public interface helloInter {

    public void sayHello(); 

    }

    helloImpl.java

    public class helloImpl implements helloInter{

     

        public void sayHello() {

            // TODO Auto-generated method stub

            System.out.println("Hello World!!!");

        }

     

    }

     

    <?xml version="1.0" encoding="UTF-8"?>

    <beans xmlns="http://www.springframework.org/schema/beans"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"

        xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 

        http://www.springframework.org/schema/context                http://www.springframework.org/schema/context/spring-context-4.0.xsd">

        <!-- id 表示你这个组件的名字,class表示组件类 -->

        <bean id="hello" class="com.lj.testspring.chapter.helloImpl"></bean>

    </beans> 

    import org.junit.Test;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class helloTest {

               @Test

               public void testHelloWorld() { 

                     //1、读取配置文件实例化一个IoC容器 

                     ApplicationContext context = new ClassPathXmlApplicationContext("hello.xml"); 

                     //2、从容器中获取Bean,注意此处完全“面向接口编程,而不是面向实现” 

                     helloInter helloApi = context.getBean("hello", helloInter.class); 

                      //3、执行业务逻辑 

                      helloApi.sayHello(); 

               } 

    }

     

    运行,可以看出输出一个hello World。

    在spring IOC容器的代表就是org.springframework.beans包中的BeanFactory接口,BeanFactory接口提供了IOC容器最基本功能,而org.springframework.context包下的ApplicationContext接口扩展了BeanFactory,还提供了与Spring AOP集成,国际化处理,事件传播及提供不同层次的context实现。简单说,BeanFactory提供了IOC容器最基本功能,而ApplicationContext则增加了更多支持企业级功能支持。ApplicationContext完全继承BeanFactory,因而BeanFactory所具有的语义也适用于ApplicationContext。

    容器实现一览:

    XmlBeanFactory:BeanFactory实现,提供基本的IoC容器功能,可以从classpath或文件系统等获取资源;
    (1) File file = new File("fileSystemConfig.xml");
    Resource resource = new FileSystemResource(file);
    BeanFactory beanFactory = new XmlBeanFactory(resource);
    (2)
    Resource resource = new ClassPathResource("classpath.xml");
    BeanFactory beanFactory = new XmlBeanFactory(resource);

    ClassPathXmlApplicationContext:ApplicationContext实现,从classpath获取配置文件;
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath.xml");

    FileSystemXmlApplicationContext:ApplicationContext实现,从文件系统获取配置文件。
    BeanFactory beanFactory = new FileSystemXmlApplicationContext("fileSystemConfig.xml");

     

    ApplicationContext接口获取Bean方法简介:
    • Object getBean(String name) 根据名称返回一个Bean,客户端需要自己进行类型转换;
    • T getBean(String name, Class<T> requiredType) 根据名称和指定的类型返回一个Bean,客户端无需自己进行类型转换,如果类型转换失败,容器抛出异常;

    • T getBean(Class<T> requiredType) 根据指定的类型返回一个Bean,客户端无需自己进行类型转换,如果没有或有
    多于一个Bean存在容器将抛出异常;
    • Map<String, T> getBeansOfType(Class<T> type) 根据指定的类型返回一个键值为名字和值为Bean对象的 Map,
    如果没有Bean对象存在则返回空的Map。

    让我们来看下IoC容器到底是如何工作。在此我们以xml配置方式来分析一下:

    一、准备配置文件:就像前边Hello World配置文件一样,在配置文件中声明Bean定义也就是为Bean配置元数据。

    二、由IoC容器进行解析元数据: IoC容器的Bean Reader读取并解析配置文件,根据定义生成BeanDefinition配置元数据对象,IoC容器根据BeanDefinition进行实例化、配置及组装Bean。

    三、实例化IoC容器:由客户端实例化容器,获取需要的Bean

     

  • 相关阅读:
    Java中存取权限和修饰符public、private、protected和default的区别和联系
    java集合之ArrayList,TreeSet和HashMap分析
    ResultSet,RowSet,OracleCachedRowSet和RowSetMetaData区别及联系
    实战篇
    kubernetes系列之 service代理模式ipvs
    Python Jinja2的简单使用
    Helm v3从入门到实战
    迷宫
    python多线程下载文件
    乱码,编码
  • 原文地址:https://www.cnblogs.com/Bluecom/p/12242647.html
Copyright © 2011-2022 走看看