欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring:IoC-DI

程序员文章站 2022-04-18 11:25:02
Spring笔记(一) 什么是Spring? Spring是一个以IoC(Inversion of Control-控制反转)和AOP(Aspect Oriented Programming-面向切面编程)为内核的开源框架。 那么什么是框架呢?框架能做什么?为什么要使用框架?框架其实就是能完成一定功 ......

spring笔记(一)


什么是spring?

  spring是一个以ioc(inversion of control-控制反转)和aop(aspect oriented programming-面向切面编程)为内核的开源框架。

  那么什么是框架呢?框架能做什么?为什么要使用框架?框架其实就是能完成一定功能的半成品。框架能够帮助我们完成的是:项目的整体框架、一些基础功能、规定了类和对象如何创建,如何协作等,当我们开发一个项目时,框架帮助我们完成了一部分功能,我们自己再完成一部分,那这个项目就完成了。

spring框架包结构

  使用spring框架进行开发时,需要用到spring框架和第三方依赖包。

  框架包:

    以spring 4.3.16为例。下载之后,解压,最终的目录结构图如下:

       Spring:IoC-DI

    其中,libs目录下包含60个jar文件,这些jar文件分为3类:

      a、以release.jar结尾的是spring框架class文件的压缩包

      b、以release-javadoc.jar结尾的是spring框架的api文档的压缩包

      c、以release-sources.jar结尾的是spring框架源文件的压缩包

    整个spring由20个模块组成,该目录下为每个模块都提供了这三种压缩包。初次之外,在libs目录中,还有4个spring的基础包,分别对应spring核心容器的4个模块:

      spring-core-4.3.16.release.jar:包含spring框架的基本核心工具类,spring其他组件都要用到这个包里面的类。

      spring-beans-4.3.16.release.jar:所有基于spring框架的应用都要用到的jar包,包含访问配置文件、创建和管理bean以及进行ioc或者di操作相关的所有类。

      spring-context-4.3.16.release.jar:spring提供了在基础ioc功能上的扩展服务,还提供了许多企业级服务的支持,如任务调度、jndi定位、ejb集成、远程访问、缓存、邮件服务以及各种视图层框架的封装等。

      spring-expression-4.3.16.release.jar:定义了spring的表达式语言。

  第三方依赖包:

    在使用spring进行开发时,spring的核心容器还需要依赖commons-logging的jar包。  

什么是控制反转-ioc?

  学习ioc之前,要先懂什么是依赖?

    应用程序在没有引入ioc容器之前,对象a依赖对象b,那么a对象实例化或者运行到某一个点的时候,自己就必须去主动创建对象b或者使用已经创建好的对象b,如果没有对象b,对象a就无法使用,就是a has b的关系。此时,我们就可以理解为对象a对b对象产生了依赖。

  从上面的依赖关系可以看出,创建对象的过程是主动的:缺对象b马上new一个,也就是说我需要啥自己去创建一个;而将对象引入ioc容器之后呢?对象a和对象b就失去了直接联系,当a对象实例化或者运行到某个点需要对象b,ioc容器就是主动创建一个对象b给到a需要的地方。此时,对象a获取对象b的过程就是被动获取的,也就是把原来由自己创建对象的权力交给了ioc容器,此时对象的创建都由ioc容器来管理,这就是控制反转。你也可以这么理解:是的,你想抽烟!没结婚之前,想抽什么买什么,因为钱在自己手里。结婚之后呢?工资到哪里去了呢?很明显要上交给老婆大人,那你此时想抽烟就比较麻烦了,你该怎么做呢?是不是应该请求老婆大人给钱买烟呢?只有老婆大人给了你钱,你才能买到烟...这个权力的颠倒过程就是控制反转的过程。

  ioc在角色扮演上等价于一个第三方,我更习惯于理解成为一个代理商。为什么这么说呢?因为ioc实现了对具有依赖关系的对象之间的解耦!来,看图:

    Spring:IoC-DI

  从上面的图中可以看出,ioc做了什么事情呢?ioc它把各个对象类封装之后,再通过ioc容器来关联这些对象。这样一来,对象与对象之间的关系就通过ioc容器来进行联系,而对象与对象之间没有什么直接联系。怎么去理解呢?假如工厂支持diy笔记本电脑,你是消费者,你想diy笔记本电脑,就要直接联系工厂,那么此时你和工厂就产生了依赖关系,也就是你与工厂有了耦合。而ioc扮演的角色就是第三方的代理商,就是告诉你:你不用直接去联系工厂了,你告诉我需要什么,由我来把你的需求告诉工厂。然后代理商拿到按照你需求diy的笔记本电脑,然后注入给你。来看图:

    Spring:IoC-DI

什么是di-依赖注入?

  di(dependency inject)依赖注入:由ioc容器在运行期间动态的将某种依赖关系注入对象之中。也就是将对象b注入(赋值)给对象a的成员变量。

  怎么去理解di和ioc之间的联系呢?依赖注入( di) 和控制反转( ioc) 是对同一件事情的不同描述, 从某个方面讲, 就是它们描述的角度不同。 依赖注入是从应用程序的角度描述, 即应用程序依赖容器创建并注入它所需要的外部资源; 而控制反转是从容器的角度描述, 即容器控制应用程序, 由容器反向地向应用程序注入应用程序所需要的外部资源。 这里所说的外部资源可以是外部实例对象, 也可以是外部文件、对象等。

ioc和di带来的益处?

  1.可维护性比较号,便于单元测试、调试程序和争端故障。代码中的每一个class都可以单独测试,彼此之间互不影响,只要保证自身的功能无误即可,这就是组件之间低耦合或者无耦合带来的好处。

  2.每个开发团队的成员都只需要关注自己要实现的业务逻辑,完全不用关心其他人的工作进展,因为你的任务跟别人没有任何关系,你的任务可以单独测试,不用依赖于别人的组件,再也不会扯不清责任了。所以,在一个大中型项目中,团队成员分工明确、责任明晰,很容易将一个大的任务划分为细小的任务,开发效率和产品质量必将得到大幅度的提高。

  3.可复用性好,我们可以把具有普遍性的常用组件独立出来,反复应用到项目中的其他部分,或者是其他项目,当然这也是面向对象的基本特征。显然,ioc更好地贯彻了这个原则,提高了模块的可复用性。符合接口标准的实现都可以插接到支持此标准的模块中。

  4.生成对象的方式转为外置方式,就是把对象生成放在配置文件中进行定义。这样,当我们更换一个实现子类将会变得很简单,只要修改配置文件就可以了,完全具有热插拔的特性。

ioc和di的实现

  spring框架的主要功能是通过器核心容器来实现的。spring框架提供的两种核心容器分别是:beanfactory(来源与org.springframework.beans.factory的主要接口)和applicationcontext(来源于org.springframework.context的主要接口)。

  spring ioc框架的主要组件由beans、配置文件applicationcontext.xml、beanfactory接口及其相关类、applicationcontext接口及其相关类。

  1.beans是指项目中提供业务功能的bean,即容器要管理的bean。bean就是一个常见的javabean、java类。

  2.在spring中对bean的管理是在配置文件中进行的。在spring容器内编辑配置文件管理bean又被称为bean的装配,实际上装配就是告诉容器需要哪些bean,以及容器是如何使用ioc来将他们配合起来的。

    其中,配置文件包含bean的id、类、属性及其值,包含一个<beans>元素和数个<bean>子元素。spring ioc框架可以根据bean的id从bean配置文件中取得该bean类,并生成该类的一个实例对象,继而从配置文件中获得该对象的属性和值。

    <!--将指定类配置给spring,让spring创建其对象的实例-->
    <bean id="chinese" class="com.soai.model.chinese">
        <!--property元素用来指定需要容器注入的属性,name指定其属性值为 language,ref指向需要向language属性注入的id,即注入对象“english”,该对象由english实体类生成
        -->
        <property name="language" ref="english" />
    </bean>       
     
    <--配置另外一个bean-->
    <bean id="english" class="com.soai.model.english">

  3.beanfactory采用了工厂设计模式,即bean容器模式,负责读取bean的配置文件,管理对象的生成、加载,维护bean对象与bean对象之间的依赖关系,负责bean的生命周期。对于简单的应用程序来说,使用beanfactory就已经足够管理bean了,在对象的管理上可以获得许多便利性。

    常用的方法:

      getbean(string name):根据bean的id生成该bean的对象。

      getbean(string name,class requiredtype):根据bean的id和相应类生成该bean的对象。

  4.applicationcontext接口提供高级功能的容器,基本功能与beanfactory很相似,

    但它还有以下功能:

      a.提供访问资源文件更方便的方法。

      b.支持国际化消息。

      c.提供文字消息解析的方法。

      d.可以发布事件,对事件感兴趣的bean可以接收到这些事件。

    applicationcontext常用的实现类:

      1.classpathxmlapplicationcontext:读取classpath中的资源(从类路径中的xml文件中加载上下文定义的信息)      

    applicationcontext context= new filesystemxmlapplicationcontext(" d:/ applicationcontext. xml ");

      2.filesystemxmlapplicationcontext:读取指定路径的资源(从文件系统中的xml文件中加载上下文中定义的信息)     

    applicationcontext context= new classpathxmlapplicationcontext(" applicationcontext. xml ");

      3.xmlwebapplicationcontext:需要在web环境下才能运行(从web系统中的xml文件中加载上下文中定义的信息)      

    xmlwebapplicationcontext ac = new xmlwebapplicationcontext(); // 这时并没有初始化容器
    ac.setservletcontext(servletcontext); // 需要指定servletcontext对象
    ac.setconfiglocation("/web-inf/applicationcontext.xml"); // 指定配置文件路径,开头的斜线表示web应用的根目录
    ac.refresh(); // 初始化容器    
 

beanfactory和applicationcontext

  spring ioc容器的设计主要基于以下两个接口:beanfactory和applicationcontext,其中applicationcontext是beanfactory的子接口之一,换句话说:beanfactory是spring ioc容器所定义的最底层接口,只提供了最简单的ioc功能,负责配置,创建和管理bean.而applicationcontext是其*的接口之一,并对beanfactory功能做了许多的扩展,所以在绝大多数情况下,都会使用applicationcontext作为spring ioc容器.

di(依赖注入)的实现方式

  注入:bean实例默认在调用类的无参构造器创建对象后,就要对bean实例的属性进行初始化。这个初始化过程是由容器自动完成的,称为注入。

  di注入的实现方式通常有2种:

    1.设置注入:spring调用类的setter方法,通过set方法完成属性赋值

      a.简单类型   

<bean id="bean别名" class="类全限定名称">
    <property name="类属性名" ref="引用类型属性值"/>
</bean>

      b.引用类型

<--ref作为属性-->
<bean id="bean别名" class="类全限定名称">
    <property name="类属性名" ref="引用类型属性值"/>
</bean>

<--ref作为子标签-->
<bean id="bean别名" class="类全限定名称">
    <property name="类属性名">
        <ref="引用类型属性值"/>
    </property>
</bean>

      c.其他类型

    2.构造注入:spring调用类的有参构造器,通过构造方法给属性赋值,每个参数代表着一个依赖

      a.使用name完成构造注入

<constructor-age name="myage" value="22"/>

      b.使用index构造器,参数位置从0开始

<constructor-age index="0" value="..."/>

      c.省略index属性,必须按照构造器的参数位置(顺序)来复制

<constructor-age value="...">