SmartInitializingSingleton是spring 4.1中引入的新特效,与InitializingBean的功能类似,都是bean实例化后执行自定义初始化,都是属于spring bean生命周期的增强。但是,SmartInitializingSingleton的定义及触发方式方式上有些区别,它的定义不在当前的bean中(a bean's local construction phase),它是回调接口(针对非lazy单例Bean),回调的操作是由spring事件ContextRefreshedEvent触发。
SmartInitializingSingleton是spring bean上的另一个进步,实例化bean和bean自定义初始化可以不在一个类中或一个包中!
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.
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.
ContextRefreshedEvent触发以及回调的理解有两层意思:
看源码吧
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
...
//看这里吧
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
//其实执行的是:DefaultListableBeanFactory.preInstantiateSingletons
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
}
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isDebugEnabled()) {
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 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)
((SmartFactoryBean>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
//触发SmartInitializingSingleton的afterSingletonsInstantiated
// 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
Ribbon中应用
Ribbon使用SmartInitializingSingleton对定制个性化的RestTemplate
@Configuration
@ConditionalOnClass({RestTemplate.class})
@ConditionalOnBean({LoadBalancerClient.class})
@EnableConfigurationProperties({LoadBalancerRetryProperties.class})
public class LoadBalancerAutoConfiguration {
@LoadBalanced
@Autowired(
required = false
)
private List restTemplates = Collections.emptyList();
public LoadBalancerAutoConfiguration() {
}
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializer(final List customizers) {
return new SmartInitializingSingleton() {
public void afterSingletonsInstantiated() {
Iterator var1 = LoadBalancerAutoConfiguration.this.restTemplates.iterator();
while(var1.hasNext()) {
RestTemplate restTemplate = (RestTemplate)var1.next();
Iterator var3 = customizers.iterator();
while(var3.hasNext()) {
RestTemplateCustomizer customizer = (RestTemplateCustomizer)var3.next();
customizer.customize(restTemplate);
}
}
}
};
}
}
如果对Ribbon还不太了解,可参阅我的另一章Spring Cloud Ribbon源码解析。