发布于2021-05-29 19:59 阅读(1337) 评论(0) 点赞(2) 收藏(1)
即指Bean从创建到初始化,使用,再到销毁的过程。 在spring中,bean的生命周期由spring容器来管理,即spring容器负责bean的初始化,使用,再到销毁。并且spring提供了可扩展的方法,我们可以自己指定bean的初始化和销毁方法,当bean进行到当前生命周期的阶段时,会自动调用我们自定义的初始化和销毁方法。
注意:spring对bean的生命周期进行管理仅限singleton。prototype的bean spring只负责创建,和初始化。但后续销毁就不管了。
目前有三种方式:
xml的bean中配置 init-method 和 destroy-method方法
此种模式适合使用XML配置bean,且init-method和destroy-method指定的方法必须是无参方法。目前项目主流都是无xml化,所以了解下就好,基本用不上。
在@Bean中配置属性initMethod和destroyMethod
此种模式适合使用JavaConfig配置Bean,是xml的变体版,功能实现上和xml的一致。指定的initMethod和destroyMethod要求跟xml的一样,即无参的public方法。
实现InitializingBean和DisposableBean
此种模式会依赖spring的接口,一般用在基础框架代码中,在spring中有大量的需要执行初始化的bean都采用此模式。
在bean的方法上加注@PostConstruct和@PreDestroy
这俩注解是JDK自带的,spring也做了实现,它们俩是JSR-250引入的注解,同一规范中的@Resource也做了支持。
以上几种方式如果同时使用,它们的执行顺序是:
@PostConstruct -> InitializingBean的afterPropertiesSet方法 -> init方法 -> 使用中 -> @PreDestroy -> DisposableBean的destroy方法 -> destroy。
上图为bean生命周期执行流程图,BeanPostProcessor相关部分暂时忽略,后面会讲。
先看@Bean的源码:
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
/**
* Alias for {@link #name}.
* <p>Intended to be used when no other attributes are needed, for example:
* {@code @Bean("customBeanName")}.
* @since 4.3.3
* @see #name
*/
@AliasFor("name")
String[] value() default {};
/**
* The name of this bean, or if several names, a primary bean name plus aliases.
* <p>If left unspecified, the name of the bean is the name of the annotated method.
* If specified, the method name is ignored.
* <p>The bean name and aliases may also be configured via the {@link #value}
* attribute if no other attributes are declared.
* @see #value
*/
@AliasFor("value")
String[] name() default {};
/**
* Are dependencies to be injected via convention-based autowiring by name or type?
* <p>Note that this autowire mode is just about externally driven autowiring based
* on bean property setter methods by convention, analogous to XML bean definitions.
* <p>The default mode does allow for annotation-driven autowiring. "no" refers to
* externally driven autowiring only, not affecting any autowiring demands that the
* bean class itself expresses through annotations.
* @see Autowire#BY_NAME
* @see Autowire#BY_TYPE
* @deprecated as of 5.1, since {@code @Bean} factory method argument resolution and
* {@code @Autowired} processing supersede name/type-based bean property injection
*/
@Deprecated
Autowire autowire() default Autowire.NO;
/**
* Is this bean a candidate for getting autowired into some other bean?
* <p>Default is {@code true}; set this to {@code false} for internal delegates
* that are not meant to get in the way of beans of the same type in other places.
* @since 5.1
*/
boolean autowireCandidate() default true;
/**
* The optional name of a method to call on the bean instance during initialization.
* Not commonly used, given that the method may be called programmatically directly
* within the body of a Bean-annotated method.
* <p>The default value is {@code ""}, indicating no init method to be called.
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.context.ConfigurableApplicationContext#refresh()
*/
String initMethod() default "";
/**
* The optional name of a method to call on the bean instance upon closing the
* application context, for example a {@code close()} method on a JDBC
* {@code DataSource} implementation, or a Hibernate {@code SessionFactory} object.
* The method must have no arguments but may throw any exception.
* <p>As a convenience to the user, the container will attempt to infer a destroy
* method against an object returned from the {@code @Bean} method. For example, given
* an {@code @Bean} method returning an Apache Commons DBCP {@code BasicDataSource},
* the container will notice the {@code close()} method available on that object and
* automatically register it as the {@code destroyMethod}. This 'destroy method
* inference' is currently limited to detecting only public, no-arg methods named
* 'close' or 'shutdown'. The method may be declared at any level of the inheritance
* hierarchy and will be detected regardless of the return type of the {@code @Bean}
* method (i.e., detection occurs reflectively against the bean instance itself at
* creation time).
* <p>To disable destroy method inference for a particular {@code @Bean}, specify an
* empty string as the value, e.g. {@code @Bean(destroyMethod="")}. Note that the
* {@link org.springframework.beans.factory.DisposableBean} callback interface will
* nevertheless get detected and the corresponding destroy method invoked: In other
* words, {@code destroyMethod=""} only affects custom close/shutdown methods and
* {@link java.io.Closeable}/{@link java.lang.AutoCloseable} declared close methods.
* <p>Note: Only invoked on beans whose lifecycle is under the full control of the
* factory, which is always the case for singletons but not guaranteed for any
* other scope.
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.context.ConfigurableApplicationContext#close()
*/
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
@Bean提供了两个属性,分别用来配置初始化方法和销毁方法。
initMethod 属性简单一些,默认是空串,即不执行任何初始化方法。
destroyMethod注释较长,分析下来如下:
以下为代码示例:
定义一个Bean类,包含两个无参方法:
package win.elegentjs.spring.ioc.lifecycle.initdestroy;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Data
@Slf4j
public class Group {
private String name;
public void init() {
log.info("==> in group init method.");
}
public void close() {
log.info("==> in group close method.");
}
}
定义java config类
package win.elegentjs.spring.ioc.lifecycle.initdestroy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GroupConfig {
@Bean(initMethod = "init")
public Group group() {
return new Group();
}
@Bean(initMethod = "init", destroyMethod = "close")
public Group group2() {
return new Group();
}
}
在该配置类中定义了两个方法,每个方法对应一个Bean定义,一个bean只指定initmethod, 另一既指定了initMethod,也指定了destroyMethod。看下测试效果:
package win.elegentjs.spring.ioc.lifecycle.initdestroy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import win.elegentjs.spring.ioc.imports.javabeans.OrgConfig;
import win.elegentjs.spring.util.ArraysUtil;
@Slf4j
public class GroupSample {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(GroupConfig.class);
context.close();
}
}
// result:
2021-05-27 17:39:14.140 [main] INFO w.elegentjs.spring.ioc.lifecycle.initdestroy.Group-==> in group init method.
2021-05-27 17:39:14.141 [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory-Creating shared instance of singleton bean 'group2'
2021-05-27 17:39:14.142 [main] INFO w.elegentjs.spring.ioc.lifecycle.initdestroy.Group-==> in group init method.
2021-05-27 17:39:14.173 [main] DEBUG o.s.c.a.AnnotationConfigApplicationContext-Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@36f6e879, started on Thu May 27 17:39:13 CST 2021
2021-05-27 17:39:14.176 [main] INFO w.elegentjs.spring.ioc.lifecycle.initdestroy.Group-==> in group close method.
2021-05-27 17:39:14.176 [main] INFO w.elegentjs.spring.ioc.lifecycle.initdestroy.Group-==> in group close method.
从结果可以分析出destroyMethod的确可以自动推断。
本节介绍InitializingBean和DisposableBean。先看InitializingBean的源码:
package org.springframework.beans.factory;
/**
* Interface to be implemented by beans that need to react once all their properties
* have been set by a {@link BeanFactory}: e.g. to perform custom initialization,
* or merely to check that all mandatory properties have been set.
*
* <p>An alternative to implementing {@code InitializingBean} is specifying a custom
* init method, for example in an XML bean definition. For a list of all bean
* lifecycle methods, see the {@link BeanFactory BeanFactory javadocs}.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see DisposableBean
* @see org.springframework.beans.factory.config.BeanDefinition#getPropertyValues()
* @see org.springframework.beans.factory.support.AbstractBeanDefinition#getInitMethodName()
*/
public interface InitializingBean {
/**
* Invoked by the containing {@code BeanFactory} after it has set all bean properties
* and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
* <p>This method allows the bean instance to perform validation of its overall
* configuration and final initialization when all bean properties have been set.
* @throws Exception in the event of misconfiguration (such as failure to set an
* essential property) or if initialization fails for any other reason
*/
void afterPropertiesSet() throws Exception;
}
afterPropertiesSet是在bean实例化后并且属性设置好值后调用。
同样看下DisposableBean源码:
/**
* Interface to be implemented by beans that want to release resources on destruction.
* A {@link BeanFactory} will invoke the destroy method on individual destruction of a
* scoped bean. An {@link org.springframework.context.ApplicationContext} is supposed
* to dispose all of its singletons on shutdown, driven by the application lifecycle.
*
* <p>A Spring-managed bean may also implement Java's {@link AutoCloseable} interface
* for the same purpose. An alternative to implementing an interface is specifying a
* custom destroy method, for example in an XML bean definition. For a list of all
* bean lifecycle methods, see the {@link BeanFactory BeanFactory javadocs}.
*
* @author Juergen Hoeller
* @since 12.08.2003
* @see InitializingBean
* @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName()
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons()
* @see org.springframework.context.ConfigurableApplicationContext#close()
*/
public interface DisposableBean {
/**
* Invoked by the containing {@code BeanFactory} on destruction of a bean.
* @throws Exception in case of shutdown errors. Exceptions will get logged
* but not rethrown to allow other beans to release their resources as well.
*/
void destroy() throws Exception;
}
跟InitializingBean的afterPropertiesSet方法类似,在容器销毁之前也会调用bean的销毁方法destroy。
示例:
定义bean,实现相关接口:
package win.elegentjs.spring.ioc.lifecycle.initializing;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* 一个简单的bean定义类,我们实现类三个接口,一个是会执行初始化方法,一个是bean销毁前执行,还有一个是注入容器类
*/
@Data
@Slf4j
public class Bird implements InitializingBean, DisposableBean, ApplicationContextAware {
private ApplicationContext applicationContext;
private String name;
@Override
public void destroy() throws Exception {
log.info("==> in destroy method.");
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("==> in afterPropertiesSet method.");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info("==> in setApplicationContext method.");
this.applicationContext = applicationContext;
}
}
定义java config类
package win.elegentjs.spring.ioc.lifecycle.initializing;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* java config类,初始化Bird bean实例。
*/
@Configuration
public class BirdConfig {
@Bean
public Bird bird() {
return new Bird();
}
}
执行示例,看看效果
package win.elegentjs.spring.ioc.lifecycle.initializing;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import win.elegentjs.spring.ioc.lifecycle.initdestroy.GroupConfig;
@Slf4j
public class BirdSample {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BirdConfig.class);
context.close();
}
}
// result
2021-05-27 19:17:02.969 [main] INFO w.elegentjs.spring.ioc.lifecycle.initializing.Bird-==> in setApplicationContext method.
2021-05-27 19:17:02.970 [main] INFO w.elegentjs.spring.ioc.lifecycle.initializing.Bird-==> in afterPropertiesSet method.
2021-05-27 19:17:02.999 [main] DEBUG o.s.c.a.AnnotationConfigApplicationContext-Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@36f6e879, started on Thu May 27 19:17:02 CST 2021
2021-05-27 19:17:03.002 [main] INFO w.elegentjs.spring.ioc.lifecycle.initializing.Bird-==> in destroy method.
可以看出执行的顺序是先注入容器类ApplicationContext, 再执行afterPropertiesSet方法,最后再容器销毁时执行destroy方法。
以上我们已经介绍了两种插入bean 初始化和销毁的方法,分别是通过@Bean的initMethod和destroyMethod实现以及spring接口InitializingBean和DisposableBean。
对比它们俩各自的优缺点总结如下:
JSR 250中定义了@PostConstruct 和 @PreDestroy注解,这两个注解是java的规范注解。spring也对它进行了实现。
注意注意的点:
以下举一个示例:
定义bean
package win.elegentjs.spring.ioc.lifecycle.postpre;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* 定义了一个Monkey类,此类比较特殊,我们将混合三种初始化和销毁方法,看看
* 执行的顺序到底是怎么样的
*/
@Data
@Slf4j
public class Monkey implements InitializingBean, DisposableBean {
private String name;
@Override
public void afterPropertiesSet() throws Exception {
log.info("==> in Monkey afterPropertiesSet method.");
}
@Override
public void destroy() throws Exception {
log.info("==> in Monkey destroy method.");
}
public void initMethod() {
log.info("==> in Monkey initMethod method.");
}
public void destroyMethod() {
log.info("==> in Monkey destroyMethod method.");
}
@PostConstruct
public void postConstructor() {
log.info("==> in Monkey postConstructor method.");
}
@PreDestroy
public void preDestroy() {
log.info("==> in Monkey preDestroy method.");
}
}
定义一个java config类
package win.elegentjs.spring.ioc.lifecycle.postpre;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* java config类,初始化Monkey bean实例。
*/
@Configuration
public class MonkeyConfig {
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
public Monkey monkey() {
return new Monkey();
}
}
测试执行结果
package win.elegentjs.spring.ioc.lifecycle.postpre;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@Slf4j
public class MonkeySample {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MonkeyConfig.class);
context.close();
}
}
// result:
2021-05-27 20:00:18.409 [main] INFO win.elegentjs.spring.ioc.lifecycle.postpre.Monkey-==> in Monkey postConstructor method.
2021-05-27 20:00:18.410 [main] INFO win.elegentjs.spring.ioc.lifecycle.postpre.Monkey-==> in Monkey afterPropertiesSet method.
2021-05-27 20:00:18.411 [main] INFO win.elegentjs.spring.ioc.lifecycle.postpre.Monkey-==> in Monkey initMethod method.
2021-05-27 20:00:18.443 [main] DEBUG o.s.c.a.AnnotationConfigApplicationContext-Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@36f6e879, started on Thu May 27 20:00:18 CST 2021
2021-05-27 20:00:18.446 [main] INFO win.elegentjs.spring.ioc.lifecycle.postpre.Monkey-==> in Monkey preDestroy method.
2021-05-27 20:00:18.447 [main] INFO win.elegentjs.spring.ioc.lifecycle.postpre.Monkey-==> in Monkey destroy method.
2021-05-27 20:00:18.447 [main] INFO win.elegentjs.spring.ioc.lifecycle.postpre.Monkey-==> in Monkey destroyMethod method.
本示例混合了三种初始化和销毁bean方法,可以看出执行的顺序确实如本章开头所讲的:
@PostConstruct -> InitializingBean的afterPropertiesSet方法 -> init方法 -> 使用中 -> @PreDestroy -> DisposableBean的destroy方法 -> destroy。
本章讲解了干预Bean生命周期中初始化和销毁的三种方式。虽然三种可以同时共存,但实际使用不可这么用,容易造成混乱。最佳实践:
本章只讲解了如何使用,并未深入源码看容器是如何执行这一系列步骤的。后面会专门开章节单独讲。敬请关注。
原文链接:https://blog.csdn.net/qq_25027457/article/details/117325241
作者:skdk
链接:http://www.javaheidong.com/blog/article/207222/8f2ff1732636793bd737/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!