Springソース(四)-beanのロード(上)
10681 ワード
前言
前にcontextの作成についてお話ししましたが、これからコアのbeanの作成過程に入ります.前期の準備が完了しました.多くの人が私と同じように、一度見たことがあるのは大体の印象しかありません.これから時間があれば、UMLと脳図を組み合わせてみんなと一緒に分かち合い、経験があるか、一緒に勉強したいと思っています.私に連絡してください.qq:616516146、本題に戻って、コードに戻ります.
1、prepareContext()
次に最初のコードSpringApplicationのrunメソッドに戻り、prepareContext()というメソッドを見てみましょう.この方法はcontextの準備をすることです.コードに入って彼の具体的な実装を見てみましょう.
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
/**
* context , ResourceLoader ClassLoader,
* bean beanNameGenerator
*/
postProcessApplicationContext(context);
/**
*
* applyInitializers(context)
* spring SpringApplication.setInitializers(xxx)
*
*/
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
Set
主にpostProcessApplicationContext(context)、applyInitializers(context)、load(context,sources.toArray(new Object[sourcess.size()]))の3つの方法についてのみ議論する.
/**
* Load beans into the application context.
* @param context the context to load beans into
* @param sources the sources to load
* beans context 。
* sources , BeanDefinitionLoader
* xxxReader xxxScanner 、 beans。
* BeanDefinitionLoader
*/
protected void load(ApplicationContext context, Object[] sources) {
logger.debug(" load ");
System.out.println("------------- load ");
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
以上はloadメソッドのロードです.上記の3つの方法が完了すると、prepareContext()関数はrefreshコンテキストの基礎的な準備ができています.次にrefreshに関する仕事を見ます.
2、refresh
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
/**
* context
*/
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
ここではrefreshに入って具体的な実装を見てみましょう.ここでrefreshはAbstractApplicationContextのrefreshメソッドを呼び出し、その後contextを呼び出します.registerShutdownHook();フックを閉じた.AbstractApplicationContextに入り、refreshの具体的な実装を見て、ここではコードの一部だけを切り取った.
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke( ) factory processors registered as beans in the context.
//DefaultListableBeanFactory, basepackage
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//DefaultListableBeanFactory
// beans
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
ここではfinishBeanFactoryInitialization(beanFactory)という方法に重点を置いている.
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) {
logger.info("----------weaverAwareName:"+weaverAwareName);
// bean
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();
// Instantiate all remaining (non-lazy-init) singletons.
// beanFactory DefaultListableBeanFactory, bean
beanFactory.preInstantiateSingletons();
}
最後にbeanFactoryのpreInstantiateSingletonsメソッドが呼び出され、ここでbeanFactoryはDefaultListableBeanFactoryです.では、これのポイントを見てみましょう.
List beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
this.logger.info("-----beanName:"+beanName);
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
final FactoryBean> factory = (FactoryBean>) getBean(FACTORY_BEAN_PREFIX + beanName);
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);
}
}
}
ここではおなじみのgetBean()メソッドを見ましたが、他に興味と時間があったら検討しましょう.まず他を無視してgetBean()メソッドをよく研究し、追跡してみるとAbstractoryFactoryのdoGetBean()メソッドを呼び出しました.ここは大きなコードです.この中には多くのコードが入っています.まず簡単に説明し、次の節に進みます.
// bean mbd
//
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
/**
* bean
*/
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
ここでは単例beanの実装,Springデフォルトのbeanはいずれも単例であるが,ここではcreateBean()メソッドを見たが,springソースコードは確かに優れており,メソッド名によってその役割を大まかに知ることができる.ここのcreateBean()メソッドはそのサブクラスのメソッドを使用しています.ここではコードクリップを少し取り出して見てください.
/**
* class, class classname class
*/
Class> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
ここでbeanのロードと作成の基本プロセスも終わり、次の記事では具体的な詳細を分析することに重点を置きます.
コードの構築はgithubを参照してください.このアドレスには対応するコードのコメントがあります.