开发者学堂课程【高校精品课-厦门大学 -JavaEE 平台技术:Spring 对象生命周期示例】学习笔记,与课程紧密联系,让用户快速学习知识
课程地址:https://developer.aliyun.com/learning/course/80/detail/15901
Spring 对象生命周期示例
1、下面用一个例子代码来解释 Bean 的生命周期接口是怎样工作的,这个代码是基于 Maven 和 Spring Boot 来完成的,这两部分内容会在下一章节中讲到。
先看代码,代码有四个类,其中两个类是 spring 的 Bean 对象类,分别是 Car 和 Boss,Boss 这个类的内容相对比较多,让它实现了五个 Bean 级的生命周期接口;
Car 这个类比较简单,只是做了一个构造函数。
另外做了两个容器级的接口类,分别实现了两个容器级的接口。看这些类实现了 Bean 级的生命周期接口和容器类生命周期接口的方法是在这两个 Bean 实例化过程
中按照怎样的顺序被调用的?
2、它的代码在例子工程里面的 SpringFrameWork 这一章里,工程名叫 beanlifecycle,这个例子是用 Maven 和 Spring Boot 来写的,先不管 Maven 和 Spring Boot,先看两个 Bean 对象。第一个 Bean 对象相对简单,是 Car 对象,它只写了一个构造函数,
@Component
public class Car {
public Car() {
System.out.println("Car constructor invoke");
构造函数中间仅仅用system out打印出来它的构造函数被调用,这个对象通过配置信息让 Spring 容器知道它是 Bean 对象,办法是用注解的方式,用 @component
注解来告诉 Spring 容器这是一个 Bean对象。
3、另外一个 Bean 对象是 Boss,Boss 这个对象相对复杂一些,让它实现了五个 Bean 级的生命周期接口,三个 Aware,分别是 BeanNameAware、
BeanFactoryAware、 ApplicationContext
Aware,还有两个 InitializingBean、DisposableBean。这五个 Bean 级的生命周期接口有五个对应的方法,下面五个 Override 的方法就是五个 Bean 级生命周期接口对应的方法。
在 Bean对象里其它的方法写了一个属性,叫 bossName,bossName 对应的有一个 get 和 set 方法,在他 set 方法前面写了一个标签叫 @value,里面的名字是 Boss.bossName,这个标签的含义是告诉 Spring 容器这个方法的参数 bossName 要从配置文件中读,所以 Spring 容器读到它的 Bean 对象中间的某一个,可以写到属性前面,现在把它写到方法前面,就可以直接从配置文件当中读取信息,把它设置到方法的参数上。配置信息写在了 application.yaml 件里,文件是在 resources 目录下,resources 目录下放的都是一些配置文件,或者是静态文件。在 resources 下写了一个配置项叫 bossName,因为是用 yaml 写的,是用分级的方式写的,如
果用property 来写的话,是Boss.bossName,这个属性设定成为 Jack。
4、Spring容器在实例化一个boss对象的时候,会从配置文件中读取值赋给 set bossName 的参数上,代码会把它打印出来,这是 bossName 的属性,还有对应
的 get set 方法,另外它是在构造函数。
还有两个方法,分别是 myPostConstructure 和 myPreDestory。
这两个方法准备放在 @Bean 的定义中间来写,这个 Bean 对象在类前面是没有用注解来写的,怎样告诉 Spring 容器这是一个 Bean对象呢?在 spring 配置的 JAVA 代码中间说过可以用 JAVA 代码来写配置,这个过程中间配置的 JAVA代码是写在 BeanLifeCycle
Application 上面,因为他前面加了一个标签叫 @SpringBoot
Application,这个标签的具体含义在后面章节中会讲,这个标签中间包含了配置信
息,所以 Spring 会去读2配置的标签注解的类,然后读取里面的内容。
5、这个类中间写了一个方法,这个方法返回值是 boss 类型,方法名是 boss,方法里面的内容是创建了一个 boss 对象。这个方法起的作用是前面加了一个 @Bean 的标签,加了 @Bean 的标签 Spring 容器就知道需要创建一个 Bean 对象,这个 Bean 对象的类型是方法的返回类型,id 是方法的名称,就是小写的 boss,所以会创建一个 boss 类型的、id 是小写的 boss 这样一个 Bean 对象,通过 @Bean 的标签写在方法前面,这个 Bean 对象是在方法里用代码写出来的、构造出来的对象,这就是用JAVA 代码来告诉 Spring 容器配置怎样来做。在 @Bean 的注解里,定义了两个属性,一个是initMethod,是 myPostConstruct;destroyMethod 是
myPre
Destory,这是在 boss 类里的两个方法。用 java 代码写 Spring 的配置信息更加灵活,比如说在这个例子中间,Boss的 Spring 对象在方法中间用代码来写的,假如boss 有一些指类的话,可以根据配置的信息在方法中间实例化出 boss的某一个指类,返给 Spring 容器,所以它的灵活性大于注解的方式。如果不需要这样的灵活性,是没必要用 JAVA 代码来写的,因为用注解写比较简单,这是两种写 Spring 框架配置的方法。
6、一个 boss 里面定义了五个 Bean级生命周期,Car 里面其实什么都没定义。还定义了两个容器级的接口,容器级的接口其实不是针对特定的 Bean,需要独立的写一个类来实现容器级的接口,第一个 InstantiationAwareBeanPostProcessor 接口的类,这个类里面直接实现了这个接口要求的两个方法,这个方法里都是打印出来对应的信息;另外一个类也类似,也实现了 BeanPostProcessor 定义的两个方法去打印出它的内容。下面把整个工程跑起来,容器在启动的时候会把里面找到的 Bean 对象实例化出来,就可以看到定义的生命周期接口在整个 Bean 对象实例化过程中间,是按照怎样的一个顺序运行的?跑的时候要依赖于 SpringBoot,因为在 Maven 中间定义了一个 Pluyins,具体的会在下次课中讲解。在 Maven 中间找到对应的工程,找到 Pluyins,找到 spring-bootrun,因为起的是服务端的程序,是没有界面的,现在是通过命令行看到打印出来的信息,当看到下面 spring boot 的
提示的时候,
Spring Boot 已经正常的运行起来了,可以看 spring boot 运行起来,打印出了怎样的信息?这里定义了两个容器级的接口对象,因为容器级接口对象是对 spring 中间的所有的 Bean 对象都起作用,Spring 容器里不仅仅有我们定义的这两个对象,它内部的很多东西也是 Bean 对象,这里有很多提示是因为有很多容器及接口是对
它内部 Bean 对象都起了作用,所以有一堆提示。
只需要关注我们的两个 Bean 对象,car 比较简单,car 里面没有定义 Bean 级的生命周期接口。
可以看到它的顺序首先是 InstantiationAwareBeanPostProcessor
Adapter.postProcessBeforeInstantiation invoke, name=can
接口,然后是它的构造函数 Car constructor invoke,然后是 Instantiation
A
wareBeanPostProcessorAdapter.postprocess
AfterInstantiation invoke, name=car
接口,
最后是 BeanPostProcessor 两个接口,它的 BeforeInitialization 和 AfterInitialization 这两个接口,它所起作用的方法都是容器级的接口四个方法被调用。
7、另外一个是 Boss,Boss 定义了五个 Bean 级生命周期接口,能看到它的过程。
首先跟前面的 car 一样,是 InstantiationAwareBeanPost
ProcessorAdapter.postProcessBeforeInstantiation invoke,
na
m
e = boss
接口,然后是它的构造函数 Boss constructor invoke,然后是
InstantiationAwareBeanPostProcessorAdapter.post
ProcessAfterInstantiation invoke,name =boss
接口,在这个接口完成以后,可以看到 boss Bean 对象的属性是从配置文件中读进来的,所以这时候能看到 setBossName 被调用,因为前面配置了一个需要从配置文件中读取的属性方法,所以可以看到这个方法被调用。然后是三个 aware 的方法,BeanFactoryAware的方法、 ApplicationContextAware 的方法、BeanNameAware 的方法,这三个 aware 的接口被接连调用,然后就是容器级的 BeanPostProcessor 的 PostProcessorBeforeInstantiation 的方法被调用,最后是 InitializationBean 的 Bean 级接口 AfterPropertiesSet,然后是 @Bean 中间定义的 InitMethod 的方法 myPostConstruct,再然后是另外一个容器级的 BeanPostProcessor 另外一个方
法 PostProcessorAfter
Instantiation,这是一个容器级的接口被调用。这样的话 boss 对象就被创建完成了。下面看到的是他内部的一些 Bean 对象,因为定义了两个容器级的接口,
这些容器级的接口不仅仅对我们定义的 Bean 对象起效果,对于在 内部的一些自己
的 Bean 对象也会起效果,所以称之为容器级。
8、最后是 Bean 对象的销毁过程,Bean 对象销毁的时候,在Boss 里定义了一个 Bean 级的 Dispose Bean 的接口,它的 Destroy 方法被调用,然后是在 @Bean 中间定义的 Destroy 的 myPre Destroy 方法被调用,这样对象就被摧毁了。