Spring中InitializingBean和SmartInitializingSingleton的区别

目录

一,InitializingBean简介:

二,SmartInitializingSingleton简介

三,InitializingBean和SmartInitializingSingleton的区别

四,从源码观察InitializingBean和SmartInitializingSingleton调用时机的区别


一,InitializingBean简介:

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 BeanFactory: for example, to perform custom
 * initialization, or merely to check that all mandatory properties have been set.
 *
 * <p>An alternative to implementing 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
 * @see BeanNameAware
 * @see BeanFactoryAware
 * @see BeanFactory
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
 * @see org.springframework.context.ApplicationContextAware
 */
public interface InitializingBean {

	/**
	 * Invoked by a BeanFactory after it has set all bean properties supplied
	 * (and satisfied BeanFactoryAware and ApplicationContextAware).
	 * <p>This method allows the bean instance to perform initialization only
	 * possible when all bean properties have been set and to throw an
	 * exception in the event of misconfiguration.
	 * @throws Exception in the event of misconfiguration (such
	 * as failure to set an essential property) or if initialization fails.
	 */
	void afterPropertiesSet() throws Exception;

}

说明:

1,InitializingBean只有一个接口方法:afterPropertiesSet()

2,InitializingBean接口可以被bean实现,并重写afterPropertiesSet()方法。

3,功能:在BeanFactory初始化完这个bean,并且把bean的参数都注入成功后调用一次afterPropertiesSet()方法。

4,InitializingBean有个功能类似的替换方案:在XML配置文件中配置init-method。

 

二,SmartInitializingSingleton简介

SmartInitializingSingleton的代码:

package org.springframework.beans.factory;

/**
 * Callback interface triggered at the end of the singleton pre-instantiation phase
 * during {@link BeanFactory} bootstrap. This interface can be implemented by
 * singleton beans in order to perform some initialization after the regular
 * singleton instantiation algorithm, avoiding side effects with accidental early
 * initialization (e.g. from {@link ListableBeanFactory#getBeansOfType} calls).
 * In that sense, it is an alternative to {@link InitializingBean} which gets
 * triggered right at the end of a bean's local construction phase.
 *
 * <p>This callback variant is somewhat similar to
 * {@link org.springframework.context.event.ContextRefreshedEvent} but doesn't
 * require an implementation of {@link org.springframework.context.ApplicationListener},
 * with no need to filter context references across a context hierarchy etc.
 * It also implies a more minimal dependency on just the {@code beans} package
 * and is being honored by standalone {@link ListableBeanFactory} implementations,
 * not just in an {@link org.springframework.context.ApplicationContext} environment.
 *
 * <p><b>NOTE:</b> If you intend to start/manage asynchronous tasks, preferably
 * implement {@link org.springframework.context.Lifecycle} instead which offers
 * a richer model for runtime management and allows for phased startup/shutdown.
 *
 * @author Juergen Hoeller
 * @since 4.1
 * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons()
 */
public interface SmartInitializingSingleton {

	/**
	 * Invoked right at the end of the singleton pre-instantiation phase,
	 * with a guarantee that all regular singleton beans have been created
	 * already. {@link ListableBeanFactory#getBeansOfType} calls within
	 * this method won't trigger accidental side effects during bootstrap.
	 * <p><b>NOTE:</b> This callback won't be triggered for singleton beans
	 * lazily initialized on demand after {@link BeanFactory} bootstrap,
	 * and not for any other bean scope either. Carefully use it for beans
	 * with the intended bootstrap semantics only.
	 */
	void afterSingletonsInstantiated();

}

说明:

1,SmartInitializingSingleton中只有一个接口方法:afterSingletonsInstantiated()

2,从注释中可以看到,SmartInitializingSingleton接口可以被单例的bean实现,并重写afterSingletonsInstantiated()方法。

3,bean的afterSingletonsInstantiated()方法是在所有单例bean都初始化完成后才会调用的。

4,此接口可以解决一些因为bean初始化太早而出现的错误和问题。

5,此接口是从Spring4.1版本开始使用的。

6,此接口可以作为InitializingBean接口的一种替代方案。

 

三,InitializingBean和SmartInitializingSingleton的区别

1,SmartInitializingSingleton只作用於单例bean,InitializingBean无此要求。但他们都不能用于懒加载的bean。

2,SmartInitializingSingleton是在所有单例Bean都初始化完成后调用的,InitializingBean是每个bean初始化完成后就会调用。

 

四,从源码观察InitializingBean和SmartInitializingSingleton调用时机的区别

 

在Spring进行依赖注入的过程中,代码会来到DefaultListableBeanFactory类的preInstantiateSingletons()方法:

@Override
public void preInstantiateSingletons() throws BeansException {
	if (this.logger.isDebugEnabled()) {
		this.logger.debug("Pre-instantiating singletons in " + this);
	}

	// Iterate over a copy to allow for init methods which in turn register new bean definitions.
	// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// Trigger initialization of all non-lazy singleton beans...
	for (String beanName : beanNames) {
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				if (bean instanceof FactoryBean) {
					final FactoryBean<?> factory = (FactoryBean<?>) bean;
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
										((SmartFactoryBean<?>) factory)::isEagerInit,
								getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			}
			else {
				getBean(beanName);
			}
		}
	}

	// Trigger post-initialization callback for all applicable beans...
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		if (singletonInstance instanceof SmartInitializingSingleton) {
			final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
					smartSingleton.afterSingletonsInstantiated();
					return null;
				}, getAccessControlContext());
			}
			else {
				smartSingleton.afterSingletonsInstantiated();
			}
		}
	}
}

方法很明确的分成了两部分。

第一部分是从beanDefinitionNames列表中获得所有要注入的bean,然后调用getBean()方法完成对bean的注入,InitializingBean. afterPropertiesSet()就是在getBean()方法中调用的。

第二部分再一次从beanDefinitionNames列表中获得所有要注入的bean,并且调用他们的SmartInitializingSingleton. afterSingletonsInstantiated()方法。

以上就是这两个接口生效位置的不同。

 

下面还可以看一下具体调用InitializingBean. afterPropertiesSet()方法的代码,在上面第一部分调用getBean()方法的代码中,经过多层调用,代码会来到AbstractAutowireCapableBeanFactory的invokeInitMethods()方法:

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
		throws Throwable {

	boolean isInitializingBean = (bean instanceof InitializingBean);
	if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
		if (logger.isDebugEnabled()) {
			logger.debug("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 {
			((InitializingBean) bean).afterPropertiesSet();
		}
	}

	if (mbd != null && bean.getClass() != NullBean.class) {
		String initMethodName = mbd.getInitMethodName();
		if (StringUtils.hasLength(initMethodName) &&
				!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
				!mbd.isExternallyManagedInitMethod(initMethodName)) {
			invokeCustomInitMethod(beanName, bean, mbd);
		}
	}
}

这个方法的代码也是分成了明显的两部分,第一部分代码就是调用bean的afterPropertiesSet()方法,第二部分调用了bean的initMethod,这个initMethod是可以在配置文件中配置的。

通过这个方法可以看到,afterPropertiesSet()方法是在initMethod之前调用的,而且看起来如果afterPropertiesSet()方法如果抛出了异常,那么initMethod方法也不会调用了(没有安全管理器的话)。

 

(本文结束)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章