飞道的博客

SSM框架超详细学习:Spring框架(一)

561人阅读  评论(0)

目录,更新ing,学习Java的点滴记录

  目录放在这里太长了,附目录链接大家可以自由选择查看--------Java学习目录

一丶Spring框架初识

  • 说明:
      第一部分前两节涉及到Spring的代码大家看看就可以,如果是初学者的话,在第一部分第4节HelloWorld会以一个项目引出,让大家先认识一下Spring的基本项目,详细内容在第二部分会超详细解释
      开发工具:IDEA
  • Spring框架是Java应用最广的框架.它的成功来源于理念,而不是技术本身.它的理念包括IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)

1 Spring Ioc简介

  • IoC是一个容器,在Spring中,它认为所有的Java资源都是Java Bean,容器的目标就是管理这些Bean和它们之间的关系.所以在SpringIoC里面装载的各种Bean,也可以理解为Java的各种资源,包括Java Bean的创建,事件,行为等,它们由IoC容器管理.除此之外,各个Java Bean之间会存在一定的依赖关系,比如学校依赖于学生和老师组成的,假设学生和老师都是Java Bean,那么显然二者之间形成了依赖关系,老师和学生有教育和被教育的关系.这些Spring IoC容器都可以对其管理.只是Spring IoC管理对象和其依赖关系,采用的不是人为主动的创建,而是由Spring IoC自己通过描述创建,也就是说Spring是依靠描述来完成对象的创建及其依赖关系的.
  • 比如汽车,将汽车类定义为一个接口,假设有两类汽车–电动汽车和燃油汽车,如下图
      
  • 使用者在使用汽车出行的时候,有两种汽车可以选择,具体该怎么选择呢?建设我们现在要使用电动汽车出行
      
  • 使用Car car = new ElectricVehicle();后,接口Car就和具体类ElectricVehicle绑定在一起了(多态的展现),但是弊端显而易见:如果要使用其他类型汽车出行,比如这里的燃油汽车,就需要修改代码了.这种情况Socket接口与其实现类ElectricVehicle耦合了,如果将来不用电动汽车了,而要使用燃油汽车,那么代码就要做如下修改:
      
  • 如果将来会产生一种更加高效的新能源汽车,岂不是还要进行修改吗?在互联网的大项目中,如果要对这样类似的代码进行不断修改,那么对于整个系统的可靠性可是非常危险的事情,Spring IoC可以解决这个问题.
  • 首先,我们不用new的方式创建对象,而是使用配置的方式,然后让Spring IoC容器自己通过配置去找对应的汽车类.用一段xml描述汽车和用户引用电动汽车,如下图:
      
  • 在该xml配置文件中,只需要把配置切换为:
      
  • 这样切换后,就可以实现往用户中注入燃油汽车,切换汽车的实现类非常方便,这个时候汽车Car接口就不依赖任何的汽车,而通过配置进行切换
      
  • 上图中配置信息是"我要电动汽车",就相当于xml文件中进行了用户和汽车的依赖关系配置,这时Spring IoC就只会拿到电动汽车,然后通过汽车接口注入给使用者,提供给使用者使用.换句话说,这时一种被动行为,而需要的资源(Bean)通过描述信息就可以得到,其中的控制权在Spring IoC容器中,它会根据描述找到使用者需要的资源,这就是控制反转的含义.
  • 好处是Car接口不再依赖于某个特定的实现类,需要使用某个实现类时我们通过书写配置信息就可以完成了.这样想修改或者加入其它资源就可以通过配置来完成,不再需要再用new关键字进行创建对象,依赖关系也可以通过配置完成,从而完全可以即插即拔地管理它们之间的关系.
  • 你不需要主动创建或者去寻找资源,只要向Spring IoC容器描述所需资源,Spring IoC自己会找到你所需要的资源,这就是Spring IoC的理念.这样做就将Bean之间的依赖关系解耦了,更容易写出结构清晰的程序.除此之外,Spring IoC还提供对Java Bean生命周期的管理,可以延迟加载,可以在其生命周期内定义一些行为等,更加方便有效的使用和管理Java资源,这就是Spring IoC的魅力.

2 Spring AOP

  • IoC的目标就是为了管理Bean,而Bean是Java面向对象(OOP)的基础设计,比如声明一个用户类,汽车类都是基于面向对象的概念.
  • 有些情况下面向对象是没有办法处理的.比如,生产部门的订单,生产部门,财务部门三者符合OOP的设计理念.订单发出,提交给生产部门去审批,生产部门审批通过,然后通知财务部门准备付款,但是财务部门发现订单的价格超支了,需要取消订单.显然取消订单这件事已经不只是影响财务部门了,还会影响生产部门之前所做的审批,需要将它们作废.我们把预算超支这个条件称为切面,它影响了订单,生产部门和财务部门3个OOP对象.在现实中,这样的切面条件跨越了3个甚至更多的对象,并且影响了它们的协作.所以只用OOP并不完善,还需要面向切面的编程,通过它去管理在切面上的某些对象之间的协作.
      
  • 上图中,实线是订单提交流程,虚线是订单驳回流程,影响它们的条件是预算超支,这是一个切面条件
  • Spring AOP常用于数据库事务的编程,很多情况如同上面的例子,做完第一步数据库更新后,不知道下一步是否会成功,如果下一步失败,会使用数据库事务的回滚功能去回滚事务,使得第一步的数据库更新也作废.在Spring AOP实现的数据库事务管理中,是以异常作为消息的.在默认情况下(可以通过Spring配置修改),只要Spring接收到了异常信息,它就会将数据库事务回滚,从而保证数据的一致性.这样我们就知道在Spring的事务管理中只要让它接收到异常信息,它就会回滚事务,而不需要通过代码来实现这个过程.下面用一段伪代码来进行说明,如下:
      
  • 在上述代码中,我们完全看不到操作数据库的代码,也没有复杂的try-catch-finally语句.在实际中,Spring AOP编程也是如此,这些东西都被Spring屏蔽了,不需要关注它,只需要关注业务代码,知道只要发生了异常,Spring回滚事务就足够了.事务当然是很复杂的,但是Spring提供了隔离级别和传播行为去控制它们,有了Spring的这些封装,开发人员就可以减少很多的代码和不必要的麻烦.

3 一些准备资源

  • Spring官网:https://spring.io/projects/spring-framework
  • 官方各版本jar包下载地址:https://repo.spring.io/libs-release-local/org/springframework/spring/,关于jar包中的目录结构解释会在第二部分开头说明
  • 官方源码各版本源码包下载地址:https://github.com/spring-projects/spring-framework/tags
  • 后续案例中使用到的包,如果有其他添加会进行说明,
     下载方式:网盘链接(版本为4.1.6,包含日志包)-----链接:链接:https://pan.baidu.com/s/1BB1XSylXzZ8_9pj_zyG9hA 提取码:bvby
     如果感觉网盘下载太慢时,可以使用上面提供的jar包和源码包的网址下载,下面给出下载jar包的示例,源码包类似,但是需要自己额外下载一个Spring依赖的日志包commons-logging,再提供一个网盘链接,这个只包含这个jar包,内容很小,下载很快–链接:https://pan.baidu.com/s/1ZRFrMs4XhzLggngU71lX6w 提取码:5vjj
      
      

4 HelloWorld项目

  • 创建项目–这里我创建一个空的Project,然后以此为基础对每一个Spring的介绍创建一个新的Module来写代码
      
      
      
      
      
      
      
  • 添加jar包到项目环境中—按常规惯例,创建一个lib文件夹,放置jar包然后添加为library
      
      
      在下载的jar包的文件目录下,找到下面五个jar包已经Spring依赖的commons-logging.jar包
      
      
      复制这5个jar包到lib目录下,然后右键选中lib,选择add as library
      
  • 在src下创建一个Spring的全局配置文件:
      
      
      
      如果你创建的配置文件出现了这样的提示信息,就说明该配置文件并没有关联到项目中,需要进行处理,操作不再赘述,详情见新建Spring全局配置文件出错
  • 创建HelloWorld类
      
  • 在全局配置文件中配置bean
      
  • 创建测试类,进行测试
      
      特别的,如果在最后运行代码时出现了:Error:java: 无效的源发行版: 12的错误,解决方案—>Error.java:12解决
  • 通过这样一个简单的项目,你可能对Spring的最基本的配置有了一点点认识,下一部分我们将进入超级详细的各部分总结

二丶深入SpringIoC

1 Spring IoC概念

1.1 Spring概述

  • Spring框架是Java应用最广的框架.它的成功来源于理念,而不是技术本身.它的理念包括IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程).其中IoC是Spring的基础,而AOP则是其重要功能,最为典型的当属数据库事务的使用.应该说Spring框架已经融入到了JavaEE开发的各个领域.

1.1.1 Spring历史

  • Spring从2004年第一个版本至今已经过去15年多了.Spring的出现是因为当时SUN公司EJB的失败,尤其是在EJB2的时代,EJB2需要许多配置文件,还需要配合很多抽象概念才能运用.虽然EJB3克服了配置方面的冗余,但是对于JavaEE开发而言,更为致命的是对EJB容器的依赖,也就是EJB只能运行在EJB容器中,EJB容器的笨重,给一些企业应用带来了困难,企业更喜欢轻便,容易开发和测试的环境.而在EJB开发中,需要选择EJB容器,然后通过EJB容器发布Bean,应用则可以通过EJB容器获得对应的Bean
  • 这一方式存在两方面问题.首先,它比较缓慢,从容器中得到Bean需要大量的远程调用,反射,代理,序列化和反序列化等复杂步骤,对开发者来说是很大的挑战.其次,对EJB容器依赖比较重,难以达到快速开发和测试的目的,对于测试人员而言需要部署和跟踪EJB容器,所以EJB2和EJB3都在短暂繁荣之后迅速走向没落.
  • EJB的没落造就了Spring的兴起.在Spring中,它会认为一切Java类都是资源,而资源都是Bean,容纳这些Bean的是Spring所提供的IoC容器,所以Spring是一种基于Bean的编程.Spring就在EJB2失败的缝隙中出现了,它是由一位澳大利亚的工程师--Rod Johnson(学历上是一位音乐博士学位)所提倡的,它深刻的改变了Java开发世界,迅速地使得Spring取代了EJB成为了实际的开发标准.
      
  • Rod Johnson指出了Spring的一些优势.首先它是一个程序员乐于使用的框架.其次,它不依赖于Spring所提供的API,也就是无侵入性或者低侵入性,即使Java应用离开了Spring依旧可以运行,这使得Spring更加灵活,拥有即插即拔的功能.最后,Spring不是要去取代当时存在的EJB,Hibernate等技术,而是将这些框架和技术整合到Spring中去,这意味着Spring提供的是一个支持它们开发的模板,比如支持MyBatis开发的SQLSessionTemplate,支持Redis开发的RedisTemplate等.

1.1.2 Spring特点

  • 轻量级:Spring是非侵入性的,基于Spring开发的应用中的对象可以不依赖与Spring的API
  • 控制反转----实现了低耦合,应用了IoC,一个对象依赖的其他对象会通过被动的方式传递进来,而不是这个对象自己创建或查找对象
  • 依赖注入—DI(Dependency injection)
  • 面向切面编程–AOP(Aspect Oriented Programming),将业务逻辑和具体服务分开
  • 容器–Spring是一个容器,因为它包含并且管理应用对象的生命周期
  • 框架:Spring实现了使用简单的组件配置组合成一个复杂的应用,在Spring中可以使用xml和Java注解组合这些对象
  • 一站式:在IoC和AOP的基础上可以整合各种应用的开源框架和优秀的第三方类库(实际上,Spring也提供了非常优秀的表现层的SpringMvc和持久层的Spring Jdbc)

1.1.3 Spring模块

  • 模块图
      
  • 核心容器(Core Container)------Spring的核心容器是其他模块建立的基础,有Spring-core,Spring-beans,Spring-context,Spring-context-support和Spring-expression(Spring表达式语言)等模块组成
     1) spring-core模块:提供了框架的基本组成部分,包括控制反转和依赖注入功能
     2) spring-beans模块:提供了BeanFactory,是工厂模式的一个经典实现,spring将其管理的对象称为Bean
     3) spring-context模块:Spring上下文,向spring框架提供上下文信息,建立在spring-core和spring-beans模块的基础上,提供一个框架式的对象访问方式,是访问定义和配置的任何对象的媒介,ApplicationContext接口是context模块的焦点
     4) spring-context-support模块:支持整合第三方库到spring应用程序上下文,特别是用于高速缓存和任务调度的支持
     5) spring-expression模块:提供了强大的表达式语言去支持运行时查询和操作对象.
  • AOP和Instrumentation
     1) spring-aop模块:提供了一个符合AOP要求的面向切面的编程实现,允许定义方法拦截器和切入点,将代码按照功能进行分离,以便干净地解耦
     2) spring-aspects模块:提供了与AspectJ的集成功能,AspectJ是一个功能强大且成熟的AOP框架
     3) spring-instrument模块:提供了类植入(Instrumentation)支持和类加载器的实现,可以在特定的应用服务器中使用
  • 消息
     1) Spring4.0以后新增了消息(Spring-messaging)模块,该模块提供了对消息传递体系结构和协议的支持
  • 数据访问/集成----由Jdbc,ORM,JMS,OXM和Transactions事务模块组成
     1) spring-jdbc模块:提供了一个Jdbc的抽象层,消除了繁琐的Jdbc编码和数据库厂商特有的错误代码解析
     2) spring-orm模块:为流行的对象关系映射(Object-Relational Mapping)API提供了集成,包括JPA和Hibernate.使用spring-orm模块可以将这些ORM映射框架与Spring提供的所有其他功能结合使用,例如声明式事务管理
     3) Spring-oxm模块:提供了一个支持对象/xml映射的抽象层实现
     4) spring-jms模块(Java Messaging Service):指Java消息传递服务,包含用于生产和使用消息的功能.
     5) spring-tx模块(事务模块):支持用于特殊接口和所有POJO(普通Java对象)类的编程和声明式事务管理
  • Web----由spring-web,spring-webmvc,spring-websocket,portlet模块组成
     1) spring-web模块:提供了基本的web开发集成功能,例如多文件上传,使用Servlet监听器初始化一个IOC容器以及web应用上下文
     2) spring-webmvc模块:也称为web-servlet模块,包含用于web应用程序的springMvc和REST Web Service实现.SpringMvc框架提供了领域模型代码和web表单之间的清晰分离,并与Spring Framework的所有其他功能集成
     3) spring-websocket模块:spring4.0后新增模块,提供了websocket和socket JS的实现
     4) portlet模块:类似于Servlet模块的功能,提供了portlet环境下的mvc的实现
  • 测试
     Spring-test模块支持使用JUnit或TestNG对Spring组件进行单元测试和集成测试。

1.1.4 Spring主要jar包及其作用

1.1.5 Spring常见注解(提前总结,看不懂没关系,看完SSM回头就明白了)

1.1.6 Spring第三方整合(提前总结,看不懂没关系)

1.2 Spring IoC概述

1.2.1 案例引入

  • 控制反转是一个比较抽象的概念,下面通过一个例子进行说明.实际生活中,当你要用一个东西,基本的想法是找到东西,比如想喝杯橙汁,在没有饮品店的情况下,最直观的做法是,买果汁机,橙子,热水.请注意这是你自己主动创造的过程,也就是一杯橙汁需要主动创造.到了今天,饮品店很多,已经没必要自己去榨橙汁的.想喝橙汁的想法一出现,第一个想法就是通过联系饮品店,将自己的需求,地址,联系方式告知,下单等待即可.这里你并没有主动创造橙汁,橙汁是由饮品店创造的,而不是你,但也达到了你的要求.这个例子中就包含了控制反转的思想.

1.2.2 代码模拟–主动创建对象

  • 如果需要橙汁,那么就等于需要橙子,开水,糖等原谅,果汁机是工具.如果需要主动创造果汁,就需要创建对应的对象—JuiceMaker(果汁生成器)和Blender(搅拌器).如下图
      
      
  • 主动创造橙汁,需要我们实现自己可能不太熟悉的工作–如何搅拌橙汁,这里的mix方法显然不是一个好方法,果汁对象依赖于水,水果,糖和搅拌机等,这些关系都需要我们自己去维护
  • 现实中比这麻烦且关系复杂的系统多得是,如果都采用这样的维护方式,那么将会非常复杂.更多时候我们并不希望了解具体的过程,只需要得到最终结果,正如果汁例子一样,现实生活中,我们更加希望是通过对饮品店的描述得到果汁,只对结果进行描述,得到我们想要的东西,这就是被动创建对象.

1.2.3 代码模拟–被动创建对象

  • 饮品店提供了制作果汁的方式,并且为我们提供一份原料清单供我们选择,将具体需求配置好传递给饮品店即可
      
      
  • 显然我们并不需要去关注果汁如何被创建,只需要采用xml文件对自己的需求进行描述
      
  • 描述完自己的需求后,就可以选择饮品店,假设选择贡茶
      
  • 上面将饮品店设置为贡茶,这样就可以指定贡茶为我们服务,通过下面的代码就可以得到我们需求中的果汁了
      
  • 在这个过程中,`果汁是由贡茶制造的,我们并不关心制造的过程,只关心对果汁如何描述,选择哪个店去制作,这才是我们如今的习惯,这个理念也可以应用于程序代码.

1.2.4 控制反转阐述

  • 控制反转概念:控制反转是一种通过描述(在Java中可以是xml或注解)并通过第三方去产生或获取特定对象的方式
  • 其思想是反转资源获取的方向. 传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应, 容器适时的返回资源. 而应用了 IOC 之后, 则是容器主动地将资源推送给它所管理的组件, 组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式
  • Spring中实现控制反转的是IoC容器,实现方法是依赖注入(Dependency Injection,DI)----即组件以一些预先定义好的方式(例如: setter 方法)接受来自如容器的资源注入.

1.3 Spring IoC容器

1.3.1 简要介绍

  • Spring IOC容器可以容纳我们所开发的各种Bean,并且我们可以从中获取各种发布在SpringIOC容器里的Bean,并且通过描述可以得到它.
  • Spring通过一个配置文件描述Bean及Bean之间的依赖关系,利用Java语言的反射功能实例化Bean并建立Bean之间的依赖关系.SpringIOC容器在完整这些底层工作的基础上,还提供了Bean实例缓存,生命周期管理,Bean实例代理,资源装载等高级功能

1.3.2 容器设计及继承结构图

  • SpringIOC容器的设计主要是基于BeanFactory和ApplicationContext两个接口,其中ApplicationContext是BeanFactory的子接口之一,BeanFactory是SpringIOC容器所定义的最底层接口,而ApplicationContext是其高级接口之一,并且对BeanFactory功能做了很多扩展,绝大部分情况下,都会使用ApplicationContext作为SpringIOC容器.
  • BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的开发者.
  • 这边网上找了一张超详细的继承结构的图(右键可以查看图像会清楚一些)
      

1.3.3 BeanFactory说明

  • 在上面的继承结构图中,可以清楚看到BeanFactory位于设计的最底层,它提供了SpringIOC容器的最底层的设计,下面我们看一下源码
      
  • 下面对该接口中一些重要方法进行解释
      1) getBean的多个方法用于获取配置给SpringIOC容器的Bean.从参数类型看可以是字符串,也可以是class类型,由于Class类型可以扩展接口也可以继承父类,所以在一定程度上会存在使用父类类型无法准确获得实例的异常,比如学生类,它有男学生和女学生两个子类,如果通过学生类的Class就无法得到具体的实例,因为容器无法判断到底要选用哪个实现类
      2) isSingleton用于判断是否为单例,如果判断为真,表示该Bean在容器中作为一个唯一单例存在.默认情况下,Spring会为Bean创建一个单例,isSingleton返回true
      3) isPrototype则相反,如果判断为真,意思是当你从容器中获取Bean,容器就为你生成了一个新的实例.默认情况下,isPrototype返回false
      4) 关于type的匹配,这是一个按Java类型匹配的方式
      5) getAliases方法是获取别名的方法

1.3.4 ApplicationContext说明

  • 为了扩展更多的功能,ApplicationContext接口扩展了许许多多的接口,它的功能非常强大.它有两个重要的实现类:ClassPathXmlApplicationContext:从 类路径下加载配置文件,FileSystemXmlApplicationContext: 从文件系统中加载配置文件
  • ClassPathXMLApplicationContext实现类之前已经用到很多次了,创建该实现类对象,并将全局配置文件作为参数进行传递,这样就能得到一个SpringIOC容器,再通过SpringIOC容器提供的方法拿到对应的bean对象执行相关操作就可以了
      

1.3.5 WebApplicationContext说明

  • 扩展于ApplicationContext,是专门为 WEB 应用而准备的,它允许从相对于 WEB 根目录的路径中装载配置文件完成初始化工作.从WebApplicationContext中可以获得ServletContext的引用,整个Web应用上下文对象作为属性放在ServletContext中,以便于Web应用环境可以访问Spring应用上下文

1.3.6 ConfigurableApplicationContext说明

  • 扩展于 ApplicationContext,新增加两个主要方法:refresh() 和 close(), 让 ApplicationContext 具有启动、刷新和关闭上下文的能力

1.4 SpringIOC容器的初始化和依赖注入

  • SpringIOC容器的生成很复杂,但是了解SpringIOC容器的初始化过程还是不难理解的.Spring中Bean的初始化和依赖注入在SpringIOC容器中是两大步骤,先初始化才会进行依赖注入.
  • Spring启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配好Bean之间的依赖关系,为上层应用提供准备就绪的运行环境,其中Bean缓存池使用HashMap实现
      
  • Bean初始化的详细3步:
     1) Resource定位,这一步是SpringIOC容器根据开发者的配置,进行资源定位,在Spring开发中,通过xml或者注解都是十分常见的方式,定位的内容是由开发者提供的
     2) BeanDefinition的载入,这个过程就是Spring根据开发者的配置获取对应的POJO,用以生成对应实例的过程
     3) BeanDefinition的注册,将之间载入的POJO往SpringIOC容器中注册,这样,开发人员就可以通过描述从中得到SpringIOC容器的Bean了.
  • 完成了上面的步骤,Bean就在SpringIOC容器中得到了初始化,但是没有完成依赖注入.也就是说没有注入其配置的资源给Bean,它现在还不能使用.对于依赖注入,SpringBean还有一个配置选项—lazy-init,其含义就是是否初始化SpringBean.在没有任何配置的情况下,它默认值为default,实际值为false,也就是SpringIOC默认会自动初始化Bean.如果将其设置为true,那么只有当我们使用SpringIOC容器的getBean方法获取Bean实例的时候,它才会进行初始化,完成依赖注入.
      
  • 关于依赖注入的详细内容放在第二部分中说明

1.5 SpringBean的生命周期

  1. SpringIOC容器的本质目的是为了管理Bean.对于Bean而言,在容器中存在其生命周期,它的初始化和销毁也需要一个过程,在一些需要自定义的过程中,我们可以插入代码去改变他们的一些行为,以满足特定的需求,这就需要了解SpringBean的生命周期的知识了
  2. 生命周期主要是为了了解SpringIOC容器初始化和销毁Bean的过程,熟悉整个生命周期可以方便我们在初始化和销毁的特定流程中加入自定义方法,满足特定需求
  3. 详细过程图
      
  4. 生命周期步骤文字说明
      1) 初始化:创建了一个SpringIOC容器的对象,默认作用域为单例
      2) 依赖注入(下一章节详细讲):按照Spring上下文对实例化的Bean进行配置,这里使用setter进行注入
      3) 如果Bean实现了接口BeanNameAware的setBeanName方法,那么此时就会调用这个方法
      4) 如果Bean实现了接口BeanFactoryAware的setBeanFactory方法,那么此时就会调用这个方法
      5) 如果Bean实现了接口ApplicationContextAware的setApplicationContext方法,并且SpringIOC容器对象也必须是一个ApplicationContext接口的实现类,那么才会调用这个方法,否则不调用
      6) 如果Bean实现了接口BeanPostProcessor接口的postProcessBeforeInitialization方法,那么此时会调用
      7) 如果Bean实现了接口InitializingBean的afterPropertiesSet方法,那么此时会调用
      8) 如果Bean自定义初始化方法,并且在Bean的配置文件中使用init-method进行了指定,那么会被调用
      9) 如果Bean实现了接口BeanPostProcessor接口的postProcessAfterInitialization方法,完成了到此的调用,这时候Bean就完成了初始化,那么Bean就生存在SpringIOC容器中了,我们就可以容器中获取对象了
      10) 如果服务器正常关闭,或者遇到其他关闭SpringIOC容器的调用,就会调用对应方法完成Bean的销毁,步骤为11,12
      11) 如果Bean实现了接口DisposableBean的destroy方法,那就会调用
      12) 如果Bean自定义了销毁方法,并且在Bean配置文件中使用destroy-method进行了指定,那么就会被调用
  5. 示例代码,了解生命周期过程
      特别说明:请仔细看上面的生命周期图,大部分接口是针对单个Bean而言的,而BeanPostProcessor接口是针对所有Bean而言,接口DisposableBean是针对SpringIOC容器本身,因此在后面代码中,我将这两个接口单独创建了实现类,我们只需要在SpringIOC容器中(配置文件)以bean的形式进行配置,SpringIOC容器就会自动识别.
      1) BeanPostProcessor实现类\
package com.spring.two;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class BeanPostProcessorImpl implements BeanPostProcessor {

    // BeanPostProcessor接口中的方法
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【" + bean.getClass().getSimpleName() + "】调用BeanPostProcessor接口中的postProcessBeforeInitialization方法,对象" + beanName + "开始实例化");
        return bean;
    }

    // BeanPostProcessor接口中的方法
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【" + bean.getClass().getSimpleName() + "】调用BeanPostProcessor接口中的postProcessAfterInitialization方法,对象" + beanName + "实例化完成");
        return bean;
    }

}

  2) DisposableBean实现类

package com.spring.two;

import org.springframework.beans.factory.DisposableBean;

public class DisposableBeanImpl implements DisposableBean {

	//DisposableBean接口的destroy方法
	@Override
	public void destroy() throws Exception {
		System.out.println("调用接口DisposableBean的destroy方法");
	}

}

  3) Person–一个Bean类

package com.spring.two;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class Person implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean{
	private String name = null;
	private int id;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		System.out.println("【Setter】为Person类的name属性赋值");
		this.name = name;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		System.out.println("【Setter】为Person类的id属性赋值");
		this.id = id;
	}

	@Override
	public String toString() {
		return "Person{" +
				"name='" + name + '\'' +
				", id=" + id +
				'}';
	}
	//自定义初始化方法
	public void myinit() {
		System.out.println("【" + this.getClass().getSimpleName() + "】执行自定义初始化方法");
	}

	//自定义销毁方法
	public void mydestroy() {
		System.out.println("【" + this.getClass().getSimpleName() + "】执行自定义销毁方法");
	}

	//BeanNameAware接口中方法
	@Override
	public void setBeanName(String arg0) {
		System.out.println("【" + this.getClass().getSimpleName() + "】调用BeanNameAware接口的setBeanName方法");

	}

	//BeanFactoryAware接口中方法
	@Override
	public void setBeanFactory(BeanFactory arg0) throws BeansException {
		System.out.println("【" + this.getClass().getSimpleName() + "】调用BeanFactoryAware接口的setBeanFactory方法");
	}

	//ApplicationContextAware接口中方法
	//特别强调,必须使用ApplicationContext及其实现类来创建SpringIOC容器,否则即便实现了该方法也不会调用
	@Override
	public void setApplicationContext(ApplicationContext arg0) throws BeansException {
		System.out.println(
				"【" + this.getClass().getSimpleName() + "】调用ApplicationContextAware接口的setApplicationContext方法");
	}

	//InitializingBean接口中方法
	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("【" + this.getClass().getSimpleName() + "】调用InitializingBean接口的afterPropertiesSet方法");
	}
}

  4) 全局配置文件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.0.xsd">

    <!--BeanPostProcessor定义 该接口是针对所有Bean而言的 -->
    <bean id="beanPostProcessor" class="com.spring.two.BeanPostProcessorImpl"/>
    <!--DisposableBean定义 该接口是针对SpringIOC容器本身的-->
    <bean id="disposableBean" class="com.spring.two.DisposableBeanImpl"/>

    <!--  自定义bean类,通过init-method,destroy-method指定自定义初始化方法和自定义销毁方法  -->
    <bean id="person" class="com.spring.two.Person"
          destroy-method="mydestroy" init-method="myinit">
        <property name="name" value="root"/>
        <property name="id" value="1"/>
    </bean>
</beans>


  5) 测试类

package com.spring.two;

import com.spring.one.JuiceMaker;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class Test {
    public static void main(String[] args) {
        // 1. 获取SpringIOC容器,这里使用ClassPathXmlApplicationContext来接收
        // 原因是该实现类中含有close方法,在手动关闭时,可以调用生命周期中的销毁方法
        ClassPathXmlApplicationContext ctx =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        // 2. 获取Bean实例
        Person person =ctx.getBean(Person.class);
        // 3. 输出Bean对象
        System.out.println("【生命周期内】"+person);
        // 4. 关闭IOC容器,调用销毁方法
        ctx.close();
    }
}

  6) 测试结果

下一篇–>三丶Spring装配Bean,近期更新


转载:https://blog.csdn.net/qq_41649001/article/details/106936915
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场