目錄
二,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方法也不會調用了(沒有安全管理器的話)。
(本文結束)