持续创造,加速生长!这是我参加「日新方案 6 月更文挑战」的第9天,点击查看活动概况
解救一个人,便是解救全世界
概述
Spring Bean的生命周期是一个比较复杂的进程,从创立到毁掉,包含了一些列的进程,本章重点讲解下Spring Bean的afterPropertiesSet()
。
InitializingBean介绍
履行阶段
首要咱们来回顾下Spring Bean整个生命周期。
履行阶段: 其间标记黄色部分的便是咱们本文的主角,它是在bean的特点被设置值之后,调用bean init-method特点指定的办法之前履行的。
作用
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;
}
InitializingBean
只要一个办法afterPropertiesSet
,见名知意,这个办法是在bean的特点值被设置今后履行。 Spring给咱们提供了这么一个扩展点,能够用来做许多的事情, 比方能够修正默认设置的特点,添加弥补额定的特点值或许针对要害特点做一个校验。
Spring自身也有许多的Bean完成了InitializingBean
接口, 比方Spring MVC中的RequestMappingHandlerMapping
就完成了InitializingBean
接口,在afterPropertiesSet
中完成了一些初始化工作,比方url和controller办法的映射。
实战案例
- 界说bean
@Data
@Slf4j
@ToString
@Accessors(chain = true)
public class BeanLifeCycle implements InitializingBean {
@Value("${prop:hello}")
private String prop ;
public BeanLifeCycle() {
log.info("#################BeanLifeCycle 实例化");
}
public void init() {
log.info("#################BeanLifeCycle 调用init-mthod 初始化");
}
public void destroy() {
log.info("#################BeanLifeCycle 毁掉");
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("#################BeanLifeCycle 调用afterPropertiesSet办法, 查看特点值prop:[{}],现已被赋值", prop);
log.info("#################BeanLifeCycle 调用afterPropertiesSet 初始化");
}
}
@Configuration
public class LifeCycleConfig {
@Bean(name = "beanLifeCycle", initMethod = "init", destroyMethod = "destroy")
public BeanLifeCycle createBeanLifeCycle() {
BeanLifeCycle beanLifeCycle = new BeanLifeCycle();
return beanLifeCycle;
}
}
- 查看履行成果
履行成果验证了咱们的定论,履行afterPropertiesSet()
时bean特点现已被初始化,一起它也是在init-method办法前履行。
代码地址:github.com/alvinlkk/sp…
源码解析
上面咱们现已了解了InitializingBean
的作用和履行时机,现在咱们从源码的角度分析下。
通过debug咱们看到,Bean的创立的进口AbstractAutowireCapableBeanFactory
的createBean
办法,createBean
最终调用的是doCreateBean
办法。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
........
try {
// 为bean设置特点值
populateBean(beanName, mbd, instanceWrapper);
// 初始化bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
........
}
doCreateBean
办法中相关的便是populateBean
办法和initializeBean
办法,populateBean
办法主要为bean设置特点值,咱们重点重视初始化Bean办法initializeBean
。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
........
try {
// 履行初始化办法
invokeInitMethods(beanName, wrappedBean, mbd);
}
......
return wrappedBean;
}
initializeBean
中要害的是履行invokeInitMethods
办法,在这里边调用afterPropertiesSet
办法。
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
// 判别当前bean是否完成了InitializingBean接口
boolean isInitializingBean = (bean instanceof InitializingBean);
// 假如当前bean是一个InitializingBean
if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 真正调用当前bean的afterPropertiesSet办法
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
// 最后通过反射的办法履行init-method特点对应的办法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
以上便是从源码层面了解InitializingBean
的调用时机。
总结
InitializingBean
是Spring中很要害的一个扩展接口,其实它和bean中init-method
特点对应的办法功用是一致的,都是初始化bean,咱们能够二选一完成即可,当然一起使用也没有问题。init-method
是通过反射完成的,性能相对差一点点。另外,假如调用afterPropertiesSet办法时犯错,则不会调用init-method指定的办法。
参阅
www.cnblogs.com/zrtqsk/p/37…
/post/696460…