为网站开发uwp应用,国外 做励志视频的网站,网站备案可以国际域名,建筑招聘最好的网站所谓万物皆对象#xff0c;对于一个 bean 而言#xff0c;从出生到死亡#xff0c;他要经历哪些阶段呢#xff1f; 生命周期
理解对象的生命周期#xff0c;可以帮助我们更好的做一些扩展。 一个对象从被创建到被垃圾回收#xff0c;可以大致分为这 5 个阶段#xff1a… 所谓万物皆对象对于一个 bean 而言从出生到死亡他要经历哪些阶段呢 生命周期
理解对象的生命周期可以帮助我们更好的做一些扩展。 一个对象从被创建到被垃圾回收可以大致分为这 5 个阶段
创建/实例化阶段调用类的构造方法产生一个新对象初始化阶段此时对象已经被创建了但还未被正常使用可以在这里做一些初始化的操作运行使用期此时对象已经完全初始化好程序正常运行对象被使用销毁阶段此时对象准备被销毁需要预先的把自身占用的资源等处理好如关闭、释放数据库连接回收阶段此时对象已经完全没有被引用了被垃圾回收器回收。
理解了一个 Bean 的生命周期后下面我们看下SpringFramework怎么对Bean 的生命周期做干预的。
单实例 Bean 的生命周期
init-method destroy-method
1创建 Bean
package com.study.spring.a_initmethod;public class Cat {private String name;public Cat() {System.out.println(Cat 构造方法执行了。。。);}public void setName(String name) {System.out.println(setName方法执行了。。。);this.name name;}public void init() {System.out.println(name 被初始化了。。。);}public void destroy() {System.out.println(name 被销毁了。。。);}
}public class Dog {private String name;public Dog() {System.out.println(Dog 构造方法执行了。。。);}public void setName(String name) {System.out.println(setName方法执行了。。。);this.name name;}public void init() {System.out.println(name 被初始化了。。。);}public void destroy() {System.out.println(name 被销毁了。。。);}
}2分别创建 XML 文件 和 注解配置类
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdbean classcom.study.spring.a_initmethod.Cat init-methodinit destroy-methoddestroyproperty namename value小米米//bean
/beansConfiguration
public class Config {Bean(initMethod init,destroyMethod destroy)public Dog dog(){Dog dog new Dog();dog.setName(小勾勾);return dog;}
}3分别测试xml 和注解驱动
private static void testXml() {System.out.println(准备初始化IOC容器。。。);ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext(bean-initmethod.xml);System.out.println(IOC容器初始化完成。。。);System.out.println();System.out.println(准备销毁IOC容器。。。);context.close();System.out.println(IOC容器销毁完成。。。);}private static void testAnnotationConfig() {System.out.println(准备初始化IOC容器。。。);AnnotationConfigApplicationContext applicationContext new AnnotationConfigApplicationContext(Config.class);System.out.println(IOC容器初始化完成。。。);System.out.println();System.out.println(准备销毁IOC容器。。。);applicationContext.close();System.out.println(IOC容器销毁完成。。。);}输出如下
准备初始化IOC容器。。。
Cat 构造方法执行了。。。
setName方法执行了。。。
小米米 被初始化了。。。
IOC容器初始化完成。。。准备销毁IOC容器。。。
小米米 被销毁了。。。
IOC容器销毁完成。。。-----------------------------准备初始化IOC容器。。。
Dog 构造方法执行了。。。
setName方法执行了。。。
小勾勾被初始化了。。。
IOC容器初始化完成。。。准备销毁IOC容器。。。
小勾勾被销毁了。。。
IOC容器销毁完成。。。由此可以得出结论在 IOC 容器初始化之前默认情况下 Bean 已经创建好了而且完成了初始化动作容器调用销毁动作时先销毁所有 Bean 最后 IOC 容器全部销毁完成。
同时也可以看出来在 Bean 的生命周期中是先对属性赋值后执行 init-method 标记的方法。
PostConstruct PreDestroy
上面的 Cat 和 Dog 都是我们手动声明注册的但是对于那些使用模式注解的 Bean 这种方式就不好使了因为没有可以声明 init-method 和 destroy-method 的地方了。
此时可以使用JSR250 规范提供的 PostConstruct 和 PreDestroy 这两个注解分别对应 init-method 和 destroy-method 。 比如Spring中常用的模式注解Component、Service、Repository、Controller使用这些注解Spring容器可以在启动时自动扫描并注册这些Bean而不需要显式地在XML配置文件中声明或在Java配置类中手动注册。 1创建Bean
Component
public class Pen {private Integer ink;public Pen(){System.out.println(钢笔的构造方法);}PostConstructpublic void addInk() {System.out.println(钢笔中已加满墨水。。。);this.ink 100;}PreDestroypublic void outWellInk() {System.out.println(钢笔中的墨水都放干净了。。。);this.ink 0;}Overridepublic String toString() {return Pen{ ink ink };}
}2测试
public class Client {public static void main(String[] args) {System.out.println(准备初始化IOC容器。。。);AnnotationConfigApplicationContext ctx new AnnotationConfigApplicationContext(com.study.spring.b_jsr250);System.out.println(IOC容器初始化完成。。。);System.out.println();System.out.println(准备销毁IOC容器。。。);ctx.close();System.out.println(IOC容器销毁完成。。。);}
}输出如下
准备初始化IOC容器。。。
钢笔的构造方法
钢笔中已加满墨水。。。
IOC容器初始化完成。。。准备销毁IOC容器。。。
钢笔中的墨水都放干净了。。。
IOC容器销毁完成。。。可以得出结论这两个注解实现的效果和 init-method 、 destroy-method 是一样的。
JSR250规范 与 init-method 共存
如果 PostConstruct 和 PreDestroy 和 init-method 和 destroy-method 共存执行顺序是怎样的呢
1创建 Bean
public class Pen {private Integer ink;public Pen(){System.out.println(钢笔的构造方法);}public void open() {System.out.println(init method ...打开钢笔);}public void close() {System.out.println(destroy-method - 合上钢笔。。。);}PostConstructpublic void addInk() {System.out.println(PostConstruct...钢笔中已加满墨水。。。);this.ink 100;}PreDestroypublic void outWellInk() {System.out.println(PreDestroy...钢笔中的墨水都放干净了。。。);this.ink 0;}Overridepublic String toString() {return Pen{ ink ink };}
}2创建配置类
Configuration
public class JSR250Configuration {Bean(initMethod open,destroyMethod close)public Pen pen() {return new Pen();}
}3测试执行
public class Client {public static void main(String[] args) {System.out.println(准备初始化IOC容器。。。);AnnotationConfigApplicationContext applicationContext new AnnotationConfigApplicationContext(JSR250Configuration.class);System.out.println(IOC容器初始化完成。。。);System.out.println();System.out.println(准备销毁IOC容器。。。);applicationContext.close();System.out.println(IOC容器销毁完成。。。);}
}输出结果
准备初始化IOC容器。。。
钢笔的构造方法
PostConstruct...钢笔中已加满墨水。。。
init method ...打开钢笔
IOC容器初始化完成。。。准备销毁IOC容器。。。
PreDestroy...钢笔中的墨水都放干净了。。。
destroy-method - 合上钢笔。。。
IOC容器销毁完成。。。可以得出结论JSR250 规范的执行优先级高于 init / destroy。
InitializingBean DisposableBean
是 SpringFramework 内部预先定义好的两个关于生命周期的接口他们的触发时机与 init-method destroy-method 、 PostConstruct PreDestroy一样都是在 Bean 的初始化和销毁阶段要回调的。
1创建 Bean
Component
public class Pen implements InitializingBean, DisposableBean {private Integer ink;Overridepublic void destroy() throws Exception {System.out.println(钢笔中的墨水都放干净了。。。);this.ink 0;}Overridepublic void afterPropertiesSet() throws Exception {System.out.println(钢笔中已加满墨水。。。);this.ink 100;}Overridepublic String toString() {return Pen{ ink ink };}
}2测试执行
public class InitializingDisposableAnnoApplication {public static void main(String[] args) throws Exception {System.out.println(准备初始化IOC容器。。。);AnnotationConfigApplicationContext ctx new AnnotationConfigApplicationContext(com.study.spring.c_initializingbean);System.out.println(IOC容器初始化完成。。。);System.out.println();System.out.println(准备销毁IOC容器。。。);ctx.close();System.out.println(IOC容器销毁完成。。。);}
}输出结果
准备初始化IOC容器。。。
钢笔中已加满墨水。。。
IOC容器初始化完成。。。准备销毁IOC容器。。。
钢笔中的墨水都放干净了。。。
IOC容器销毁完成。。。三种生命周期并存
当一个 Bean 同时用这三种生命周期控制时执行顺序又是怎么样的呢
1创建 Bean
Component
public class Pen implements InitializingBean, DisposableBean {private Integer ink;public Pen(){System.out.println(构造方法);}public void open() {System.out.println(init-method - 打开钢笔。。。);}public void close() {System.out.println(destroy-method - 合上钢笔。。。);}PostConstructpublic void addInk() {System.out.println(PostConstruct 钢笔中已加满墨水。。。);this.ink 100;}PreDestroypublic void outwellInk() {System.out.println(PreDestroy 钢笔中的墨水都放干净了。。。);this.ink 0;}Overridepublic void destroy() throws Exception {System.out.println(DisposableBean - 写完字了。。。);}Overridepublic void afterPropertiesSet() throws Exception {System.out.println(InitializingBean - 准备写字。。。);}Overridepublic String toString() {return Pen{ ink ink };}}2创建配置类
Configuration
public class Config {Bean(initMethod open,destroyMethod close)public Pen pen(){return new Pen();}
}3测试执行
public class Client {public static void main(String[] args) {System.out.println(准备初始化IOC容器。。。);AnnotationConfigApplicationContext ctx new AnnotationConfigApplicationContext(Config.class);System.out.println(IOC容器初始化完成。。。);System.out.println();System.out.println(准备销毁IOC容器。。。);ctx.close();System.out.println(IOC容器销毁完成。。。);}
}输出结果
准备初始化IOC容器。。。
构造方法
PostConstruct 钢笔中已加满墨水。。。
InitializingBean - 准备写字。。。
init-method - 打开钢笔。。。
IOC容器初始化完成。。。准备销毁IOC容器。。。
PreDestroy 钢笔中的墨水都放干净了。。。
DisposableBean - 写完字了。。。
destroy-method - 合上钢笔。。。
IOC容器销毁完成。。。可以看到执行顺序是PostConstruct → InitializingBean → init-method 。
原型Bean的生命周期
当面介绍的都是单实例 Bean 的生命周期而对于原型 Bean它与单实例 Bean 的生命周期是不一样的。 单实例 Bean 的生命周期是陪着 IOC 容器一起的容器初始化单实例 Bean 也跟着初始化延迟 Bean 例外 容器销毁单实例 Bean 也跟着销毁。 原型 Bean 由于每次都是取的时候才产生一个所以它的生命周期与 IOC 容器无关。 1创建 Bean
Component
public class Pen implements InitializingBean, DisposableBean {private Integer ink;public Pen(){System.out.println(构造方法);}public void open() {System.out.println(init-method - 打开钢笔。。。);}public void close() {System.out.println(destroy-method - 合上钢笔。。。);}PostConstructpublic void addInk() {System.out.println(PostConstruct 钢笔中已加满墨水。。。);this.ink 100;}PreDestroypublic void outWellInk() {System.out.println(PreDestroy 钢笔中的墨水都放干净了。。。);this.ink 0;}Overridepublic void afterPropertiesSet() throws Exception {System.out.println(InitializingBean - 准备写字。。。);}Overridepublic void destroy() throws Exception {System.out.println(DisposableBean - 写完字了。。。);}Overridepublic String toString() {return Pen{ ink ink };}
}2创建配置类
Configuration
public class Config {Bean(initMethod open,destroyMethod close)Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) //原型Beanpublic Pen pen(){return new Pen();}
}3测试执行
public class Client {public static void main(String[] args) {System.out.println(准备初始化IOC容器。。。);AnnotationConfigApplicationContext ctx new AnnotationConfigApplicationContext(Config.class);System.out.println(IOC容器初始化完成。。。);}
}输出结果
准备初始化IOC容器。。。
IOC容器初始化完成。。。由此得出结论原型 Bean 的创建不随 IOC 的初始化而创建。
然后在main 方法中去获取该 Bean再次执行
public class Client {public static void main(String[] args) {System.out.println(准备初始化IOC容器。。。);AnnotationConfigApplicationContext ctx new AnnotationConfigApplicationContext(Config.class);System.out.println(IOC容器初始化完成。。。);System.out.println(准备获取pen);Pen pen ctx.getBean(Pen.class);System.out.println(获取到pen);}
}输出结果
准备初始化IOC容器。。。
IOC容器初始化完成。。。
准备获取pen
构造方法
PostConstruct 钢笔中已加满墨水。。。
InitializingBean - 准备写字。。。
init-method - 打开钢笔。。。
获取到pen由此得出结论原型Bean的初始化动作与单实例Bean完全一致。
接着我们把销毁 Bean 的代码也加上
public class Client {public static void main(String[] args) {System.out.println(准备初始化IOC容器。。。);AnnotationConfigApplicationContext ctx new AnnotationConfigApplicationContext(Config.class);System.out.println(IOC容器初始化完成。。。);System.out.println(准备获取pen);Pen pen ctx.getBean(Pen.class);System.out.println(获取到pen);System.out.println(用完Pen了准备销毁。。。);ctx.getBeanFactory().destroyBean(pen);System.out.println(Pen销毁完成。。。);}
}输出结果
准备初始化IOC容器。。。
IOC容器初始化完成。。。
准备获取pen
构造方法
PostConstruct 钢笔中已加满墨水。。。
InitializingBean - 准备写字。。。
init-method - 打开钢笔。。。
获取到pen
用完Pen了准备销毁。。。
PreDestroy 钢笔中的墨水都放干净了。。。
DisposableBean - 写完字了。。。
Pen销毁完成。。。由此得出结论原型 Bean 在销毁时不处理 destroyMethod 标注的方法。 后置处理器 BeanPostProcessor BeanPostProcessor 是一个容器的扩展点它可以在 bean 的生命周期过程中初始化阶段前后添加自定义处理逻辑并且不同 IOC 容器间的 BeanPostProcessor 不会相互干预。 也可以配置多个BeanPostProcessor实例通过设置order属性来控制BeanPostProcessor实例的执行顺序。 1创建 bean
public class Dog implements InitializingBean {public void initMethod() {System.out.println(initMethod ...);}PostConstructpublic void postConstruct() {System.out.println(PostConstruct ...);}Overridepublic void afterPropertiesSet() throws Exception {System.out.println(InitializingBean ...);}
}2创建配置类
Configuration
public class Config {Bean(initMethod initMethod)public Dog dog() {return new Dog();}
}3创建两个后置处理器
Component
public class InstantiationTracingBeanPostProcessor1 implements BeanPostProcessor, Ordered {Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof Dog) {System.out.println(【第一个后置处理器】拦截到Bean的初始化之前 bean);}return bean;}Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof Dog) {System.out.println(【第一个后置处理器】拦截到Bean的初始化之后 bean);}return bean;}Overridepublic int getOrder() {return 1;}
}Component
public class InstantiationTracingBeanPostProcessor2 implements BeanPostProcessor, Ordered {Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof Dog) {System.out.println(【第二个后置处理器】拦截到Bean的初始化之前 bean);}return bean;}Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof Dog) {System.out.println(【第二个后置处理器】拦截到Bean的初始化之后 bean);}return bean;}Overridepublic int getOrder() {return 2;}
}4测试执行
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext ctx new AnnotationConfigApplicationContext(com.study.spring.postprocessor);}
}输出结果
【第一个后置处理器】拦截到Bean的初始化之前com.study.spring.postprocessor.Dog7f9fcf7f
【第二个后置处理器】拦截到Bean的初始化之前com.study.spring.postprocessor.Dog7f9fcf7f
PostConstruct ...
InitializingBean ...
initMethod ...
【第一个后置处理器】拦截到Bean的初始化之后com.study.spring.postprocessor.Dog7f9fcf7f
【第二个后置处理器】拦截到Bean的初始化之后com.study.spring.postprocessor.Dog7f9fcf7f由此得出 bean 的初始化阶段的全流程BeanPostProcessor#postProcessBeforeInitialization → PostConstruct → InitializingBean → init-method → BeanPostProcessor#postProcessAfterInitialization。
参考资料《从 0 开始深入学习Spring小册》