持续创造,加速生长!这是我参加「日新方案 6 月更文挑战」的第9天,点击查看活动概况

解救一个人,便是解救全世界

概述

Spring Bean的生命周期是一个比较复杂的进程,从创立到毁掉,包含了一些列的进程,本章重点讲解下Spring Bean的afterPropertiesSet()

InitializingBean介绍

履行阶段

首要咱们来回顾下Spring Bean整个生命周期。

一文带你深入理解SpringBean生命周期之InitializingBean详解

履行阶段: 其间标记黄色部分的便是咱们本文的主角,它是在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办法的映射。

实战案例

  1. 界说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;
    }
}
  1. 查看履行成果

一文带你深入理解SpringBean生命周期之InitializingBean详解

履行成果验证了咱们的定论,履行afterPropertiesSet()时bean特点现已被初始化,一起它也是在init-method办法前履行。

代码地址:github.com/alvinlkk/sp…

源码解析

上面咱们现已了解了InitializingBean的作用和履行时机,现在咱们从源码的角度分析下。

一文带你深入理解SpringBean生命周期之InitializingBean详解

通过debug咱们看到,Bean的创立的进口AbstractAutowireCapableBeanFactorycreateBean办法,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…