spring-bean的生命周期

Posted 野生java研究僧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring-bean的生命周期相关的知识,希望对你有一定的参考价值。

前言

为什么要使用 spring?

1.简介

  • 目的:解决企业应用开发的复杂性
  • 功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
  • 范围:任何Java应用

简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

2.轻量

从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。

3.控制反转

Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。

4.面向切面

Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

5.容器

Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。

6.框架

Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。

所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。

使用spring和不使用springMVC的对比

spring最重要的就是:依赖注入,AOP,容器的概念。

以上的说明我们大概对spring有了个基本的了解。我们再来谈谈什么是依赖注入,以及容器的概念,最后在延伸出我们的主题spring中bean的生命周期。毫不夸张的来说,依赖注入,AOP,控制反转,甚至是事务,都跟bean的生命周期有关系。
总的来说我们的把创建对象的权利交给了spring去完成,我们只需要从spring中获取即可。

以前我们在web开发的时候我记得好像是这样用的,每次都有new,比较麻烦,反正我是记得每次都要去new的非常麻烦

public class UserServlet extends HttpServlet 

	private static UserDao userDao = new UserDao() ;
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
		
	

在spring中我们直接这样注入就行了,比较简单

@RestController
public class UserController 
	
	@Autowired
	private UserService userService;
	public String getUserInfo(String userId)
		 return UserInfo userInfo = userService.selectById(userId)
	
	

虽然这里面是有SpringMVC的东西,打不死springMVC只是小角色,最重要的还是spring,因为springMVC是基于spring的,以及后面的springBoot等等,正是因为spring有bean的生命周期,才会让他怎么强大和什么框架都可以组合,以及你可以自己在spring框架的基础上进行扩展。别着急我马上解释bean的生命周期,因为了解bean的生命周期之前,我想大家有个概念先。

由创建对象引出的思考

我们先思考一个问题? 创建对象怎么简单的事情,为什么明明简单的一个 new 就好了,为什么还需要整个spring来给我们管理呢?明明我们一行代码就可以的事情。

你看就一行代码的事情:

我们来看下spring的代码量:这只是其中一部分为什么要搞的怎么复杂?

我们之前常说的一句话:什么是高内聚,低耦合,扩展开放,修改关闭。
我们的spring就是这样的,他并不是简单地给我们创建对象而已,而是给了我们很多的回调接口,只是如果你对spring不太理解,那你就亏大了,正是这些预留回调接口,才让spring怎么强大,就行一个万能胶,什么都能粘到一起。

我们步入正题:来看看spring的简单图,就知道他们为什么那么强大了,这只是随意的简单图,复杂的再后面,我们由浅入深。这就是基本你的流程,在每个步骤都给你关键的接口,让你有机会插入,如果你不进行干预,他在进行自动处理


大概就是这样子,因为spring需要很多前置知识才能了解清楚,所以不理解没关系,后面我会发布spring的一个设计架构,已经容器初始化,以及AOP等系列文章。

记住一点:spring强大就强大在他的那些个回调接口,有了这些回调接口,你甚至可以在spring的基础上进行扩展你想完成的功能,比如说日志记录,事务,请求参数校验,完全可以你自己手写,但是前提得了解spring的运行流程,你知道了运行流程,你就能很清楚的在哪一步进行干预,嵌入你想要的功能。

这点跟vue有点像,vue也是留了很多回调函数给你进使用,所以说,一个好的框架,或者说应用,应该面向接口编程,在你实现功能的同时,给别留一些回调接口,让别人可以对你的功能进行扩展,而不是一味的将逻辑写死,接口都不写,全是搞些普通类。

我们需要先再次理解下:接口,抽象类,实现类的作用

解接口的作用: 接口的作用就是规定功能,有具体的类实现,反正我只告诉你要完成这个功能,具体你怎么完成那我不管,就好像你的老板让你给他买早餐,他只想吃到早餐,你走路过去买还是坐车过去买他是不关心的。

抽象类的功能就是: 将一些公共的方法或者属性进行一个抽离,让后由子类去继承,在父类的基础上再次进行扩展,先有个基本实现。

实现类就是继承了抽象类:对父类的功能进行扩展,实现自己需要的功能,在父类的功能上再次对自己的实现进行个性化。

就比如说我们的spring,都是接口+抽象类+实现类这样的一个实现进行解耦
最明显的就是那几个IoC容器

我们选两个最明显的:ClassPathXmlApplicationContext和AnnotationConfigApplicationContext
bean生命周期的基本流程

我说下spring生命周期的大概流程: 然后我在给张图,你在需要创建对象的地方进行打断点进行调试,看堆栈跟踪,看个一两次,让后你自己去实现那些个接口体验一下,源码这个事情,说再多也不如自己打断点调试,这样你才记忆深刻,别人为什么要这么干。

1.准备一个AnnotatedBeanDefinitionReader并且用于解析扫描到的class,并且注册一些基础的组件

2.将配置类的信息注册到BeanDefinition中去

3.准备一个BeanFactory工厂,注解模式是准备工厂,xml方式是解析配置文件得到BeanDefinition

4.根据扫描配置类中指定的扫描路径,扫描到符合注入条件的class,解析得到BeanDefinition,执行BeanFactoryProcessor的所有回调

5.初始化所有的单例bean 如果你实现了InstantiationAwareBeanPostProcessor接口并且返回对象,接下来的流程不在继续

6.如果没有,确定构造函数,实例化对象,你也可以手动返回,spring有留SmartInstantiationAwareBeanPostProcessor接口

7.实例化完后回调InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation()让你有手动赋值的机会,如果你返回的是false自动注入结束

8.开始进行属性注入,如果在注入的过程中,有依赖其余的bean会先去创建其他的bean

9.赋值完毕后开始回调Aware接口,例如BeanNameAware 属性自动注入完毕后,如果使用了AOP,这里的AOP会创建代理对象

10.初始化完毕后回调BeanPostProcessor的postProcessBeforeInitialization() ()方法你可以检查bean或者是重新返回一个bean

11.调用InitializingBean接口方法给你进行回调

12.如果你有配置init()方法,也会再此时进行回调

13.执行BeanPostProcessor的postProcessAfterInitialization()回调 回到完毕后会添加到单例池

14.所有的单实例bean创建完毕后,如果你实现了SmartInitializingSingleton就会执行所有bean的void afterSingletonsInstantiated();方法,前提是bean是单例的。至此ioc容器的所有组件创建完毕。可以开始进行使用, @Lazy标注的bean需要使用getBean()的时候才会创建。

15.当容器关闭时会调用DisposableBean()中的方法

结尾散花

最后这张图才是重点,过多的文字描述都是累赘的,如果你有不明白的地方百度慢慢看,有点耐心。

起始远远不止这15步,这只是个大概,有了后面这张完整的图,你可以慢慢打断点机芯调试,有了这个图至少你能清楚几分,在打个断点就差不多明白了,我就不贴源码了,这源码贴太多篇幅长,看起也头疼。写程序这个东西要自己多思考,我如果一步步贴出源码,在写上中文注释,那没有多大意义,如果给你个大概思路,你自己慢慢断点调试,你不明白都难,认真看完后,你甚至想自己写个轻量版本的spring。

最后奉献上完全的大图:别把你吓到了,可以进行点击图片进行方法看,因为这个确实流程有点复杂,使用的spring版本不同也行有点差别,不过差不多的,不会变化太大。

以上是关于spring-bean的生命周期的主要内容,如果未能解决你的问题,请参考以下文章

Spring-Bean的生命周期

spring-bean 生命周期

spring-bean 生命周期

引点科技私房菜专栏之Spring-Bean生命周期和作用域以及实现方式

spring-bean的生命周期

mybatis(万能Map生命周期和作用域)