简单一点就是 : 扫描到spring.factories中的EnableAutoConfiguration,进行注入。比如RedisAutoConfiguration.class中的@bean注解,应该就明白,这里和spring中创建通过注解创建bean一样了。后面详细说明。 @Bean怎么注入ioc不明白可以去看一下spring ioc。
这里随便取一个spring.factories
那么现在问题就是spring是如何找到该类或者该注解,并且注入进容器的。
再简单说下。
就是在Spring ioc容器创建refresh()的时候,在执行beanFactoryPostProcessor链条的时候有类扫描到 springbootApplication主类上的注解@springBootApplication ,里的@EnableAutoConfiguration 里的@import(AutoConfIgurationImportSelector.class). AutoConfIgurationImportSelector类中会加载spring.factories中的EnableAutoConfiguration对应的类。后面会列出。将里面的bean统一转化为BeanDefinition等待后面初始化。
@EnableDiscoveryClient
@SpringBootApplication
public class SpringDemoApplication {
public static void main(String[] args) {
SpringApplication.run(UserCenterApplication.class, args);
}
}
springboot启动的入口,通过run进去就可以看到会初始化一个SpringApplication,然后执行run方法。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = deduceWebApplicationType();
//读取化加载器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//读取监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
getSpringFactoriesInstances(XXXXX.class) 这个方法在springboot初始化经常会看到。从名字也可以看出,其实就是从META-INF/spring.factories通过反射加载该类型的类。
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//加载监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
//触发starting事件(观察者模式,通知观察者listeners)
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//加载环境参数
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
//banner图,忽略
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备工作,将springbootApplication主类注册到beanfactory中的beanDefinitionMap中。
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//spring容器的refresh()方法。
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//触发监听器
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
4.spring中的refresh()方法,spring中的核心流程。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
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.
//执行BeanFactoryPostProcessors链条
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.
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();
}
}
}
5.在beanfactoryPostProcessor执行链条中,完成对自动装配类beanDefinition的加载。
6. ConfigurationClassPostProcessor (beanfactoryPostProcessor) 解析启动主类(DemoApplication),并且读取解析注解,也就是常说的核心注解(@SpringBootApplication ,@EnableAutoConfiguration ,@Import(AutoConfigurationImportSelector.class))。
ConfigurationClassPostProcessor.class
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
。。。
do {
//parse方法解析springApplication,解析自动装配的核心入口
parser.parse(candidates);
parser.validate();
//得到parse出来的自动装配(autoConfiguration)的类
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//将解析到configClasses元数据 读取到beanDefinitionMap中去
this.reader.loadBeanDefinitions(configClasses);
。。。
}
这一步可以看到ConfigurationClassPostProcessor类中parse方法解析启动类,将自动装配的类信息扫描到beanDefinitionMap中了。等后续的refresh()方法执行到finishBeanFactoryInitialization()完成初始化。
现在进入parse方法看一下:类信息是怎么扫描加载到beanDefinitionMap中的。
会执行AutoConfIgurationImportSelector类中的的方法。
AutoConfIgurationImportSelector.class
@Override
public void process(AnnotationMetadata annotationMetadata,
DeferredImportSelector deferredImportSelector) {
//导入
String[] imports = deferredImportSelector.selectImports(annotationMetadata);
for (String importClassName : imports) {
this.entries.put(importClassName, annotationMetadata);
}
}
selectImports的实现
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//
List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}