Bean

Spring中的bean对象说到底也是一个java对象,只是spring赋予了这些java对象更加科学的特性。例如对象创建,对象池,作用域、延迟加载、生命周期方法、低耦合方式的依赖注入等。

Java对象的生命周期

首先是构建对象,然后还可以通过set方法给对象属性赋值,再之后就可以使用这个对象,使用完成之后被jvm的垃圾回收器回收掉。

Bean的生命周期

Spring中的bean也是java对象,所以和java对象一样,bean的生命周期也离不开实例化、使用、 最后销毁的过程,不过Spring作为一个功能全面、强大的框架,可以对bean的生命周期进行更细粒度的控制。除了实例化之外,还可以处理bean的依赖关系(依赖注入);可以对bean进行各种功能增强;也允许用户自定义一些初始化操作;对于单例bean来说,spring会将其保存在容器中(对象池),这样暂时使用完的bean不会被垃圾回收,下次使用的时候不需要再创建,而是直接获取。
总之,Spring对bean的创建、使用、销毁进行了全面的接管,这也是IoC(控制反转)的具体体现。

bean生命周期的几个阶段

1、扫描要由spring管理的bean,然后创建BeanDefinition对象,用于封装bean相关配置信息。例如类全名,作用域,延迟加载等。

2、创建bean对象(包括bean的实例化和依赖注入对象)。

3、增强bean(通过各种扩展点进行功能增强,比方说为bean创建代理对象)。

4、使用bean(结合业务进行应用)。

5、关闭Spring容器的时候销毁bean。

Bean的创建

创建BeanDefinition对象

BeanDefinition即对象的建模器,它保存了一个Bean的所有信息,这些信息包括bean的类型、属性、构造方法、作用域、延迟加载、生命周期方法等各种信息,Spring最终会根据BeanDefinition来创建对象。

BeanDefinition是什么时候创建

Spring容器在启动的时候会去扫描指定的包,识别出哪些类需要由spring接管,每扫描到一个类会生成一个MetadataReader对象,在这个对象中通过ASM框架(Java字节码操控框架,可以方便的解析出类中的所有元素:类名、方法、属性等,cglib动态代理底层也使用了ASM框架,其性能要远好于java反射)解析class文件,得到类的元数据信息和注解信息,通过这些信息就可以创建BeanDefinition对象了。

创建bean对象

获取到bean的BeanDefinition之后就可以根据BeanDefinition创建bean了,Spring容器会按照字典序来创建非懒加载的这些Bean。

如果通过debug调试过这个创建的步骤,最终会发现,Spring最终会调用到AbstractAutowireCapableBeanFactory类的createBean()方法,createBean()方法又会调用doCreateBean()方法,doCreateBean()还会调用initializeBean()方法,这三个方法执行结束,一个bean就真正意义的创建完成了,所以这三个方法非常重要,从这三个方法就可以了解创建bean和增强bean功能的整个过程。最重要的只有两步:第一是实例化,第二是属性赋值,这两步也是创建一个java对象的过程。

增强bean对象功能

在属性填充结束之后,从java的角度来说这个bean已经是一个完整的java对象,可以使用了。但是spring框架更进一步,通过各种扩展点来对bean的功能进行增强,这些扩展点都是用户可选的,并不是必须的。

初始化

Spring允许用户自定义一些操作,这些操作会在bean实例化完成之后执行,这些操作放在一个统一的方法中叫做初始化方法。

初始化方法有多种指定方式,这里列举最为常用的两种,第一种是实现InitializingBean接口,在这个接口的afterPropertiesSet()方法中定义初始化操作;第二种是在xml配置文件中通过init-method标签指定初始化方法,现在用xml配置文件的方式已经比较少了。这两种方式可以共存,会先执行在afterPropertiesSet()方法,然后执行init-method标签指定初始化方法,但是一般不会有人同时混用这两种方式。

初始化方法之后

初始化方法之后的扩展点就是bean后置处理器的后方法,这里典型的应用就是Spring AOP的功能实现,Spring AOP底层用的是动态代理,代理对象就是在Bean后置处理器的后方法中进行生成的。这一步执行完之后一个bean就真正意义的创建完成,如果是单例bean还会加入到单例池中,之后就可以真正使用了,直到最后在容器关闭的时候被销毁。

单例bean的销毁

容器销毁的时候会进行单例bean的销毁。可以想象一下,如果所有单例bean都没有定义销毁方法,那么容器只需要直接清空保存单例bean的缓存就可以了。但如果有一些单例bean定义了销毁方法,就需要找出这些单例bean,执行销毁方法,执行完之后再清空单例bean的缓存。所以先要找出那些定义了销毁方法的bean,然后执行这些销毁方法。

有多种方式来定义销毁方法,这里列举最为常用的三种方式:

1、使用@PreDestroy注解,在这个注解标注的方法中定义销毁操作。

2、实现DisposableBean接口,在destroy()方法中定义销毁操作。

3、在xml配置文件中使用destroy-method标签指定销毁方法。

Spring使用了适配器模式来统一这些销毁方法的处理方式,这个适配器就是DisposableBeanAdapter,最终会在这个适配器中的destroy方法中来执行具体的销毁方法。

上面提到的三种销毁方法可以同时存在,先执行@PreDestroy标注的方法,然后执行DisposableBean接口的destroy()方法,最后执行xml中destry-method标签指定的销毁方法。当然没有必要同时混用这几中方法。

总结

Spring对bean的创建、使用、销毁进行了全面的接管,这就是IOC,其过程包含如下几个阶段:

1、扫描要由spring管理的bean,然后创建BeanDefinition对象(用于封装bean相关配置信息。例如类全名,作用域,延迟加载等)。

2、创建bean对象(包括bean的实例化和依赖注入对象)。
#在依赖关系注入(DI)完成之后进行初始化,执行被@PostConstruct注解的任何方法。

  • 1.被注解的方法必须在类放入服务之前调用,即使类没有请求注入任何资源,也会被调用;
  • 2.被注解的方法有以下规则:
    a.不得有任何参数;
    b.返回类型为void;
    c.不得抛出已检查异常;
    d.可以是public、protected、package private 或 private;
    e.不能static,可以是final; f.抛出未检查异常,那么不得将类放入服务中。
    3、增强bean(通过各种Aware扩展点进行功能增强)。
    4、使用bean(结合业务进行应用)。
    5、关闭Spring容器的时候销毁bean。
    #@PreDestroy容器删除实例之前,回调被PreDestroy注解的任何方法,即:删除实例之前调用该方法
    1.注解的方法一般是释放所持有的资源
    2.Java EE5以后,容器管理对象都支持此注解;
    3.被注解的方法有以下规则:
    *a.不得有任何参数,除EJB外;
    *b.返回类型为void;
    *c.不得抛出已检查异常;
    *d.可以是 public、protected、package private 或 private;
    *e.不能static,可以是final;
    *f.抛出未检查异常,那么不得将类放入服务中,除EJB外。