Spring4.1新しい特性SmartInitializingSingletonのRibbonへの応用
8076 ワード
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トリガとコールバックの理解には2つの意味があります.イベントがトリガーされ、ContextRefreshedEventイベントを介してAbstractApplicationContextが実際に実行する.refresh コールバックは、すべてのbeanがインスタンス化された後、SmartInitializingSingletonを呼び出して を初期化することを指す.
ソースを見て
Ribbonでの応用
Ribbon SmartInitializingSingletonを使用してカスタマイズされたRestTemplate
Ribbonについてまだよく知らない場合は、私のもう一つの章Spring Cloud Ribbonソースコード解析を参照してください.
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トリガとコールバックの理解には2つの意味があります.
ソースを見て
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ソースコード解析を参照してください.