public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.started();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();//逻辑是,判断是不是web环境,决定生成哪一种context,AnnotationConfigEmbeddedWebApplicationContext,
还是AnnotationConfigApplicationContext
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);//最关键的一个方法load()是把启动类给注册到工厂里
refreshContext(context);//在AnnotationConfigEmbeddedWebApplicationContext的构造函数中,new AnnotatedBeanDefinitionReader(this),而这个构造方法中
会向工厂注册(注意注册和实例化不同)ConfigurationClassPostProcessor(其他PostProcessor先不说),在本方法中,refresh工厂的时候,在invokeBeanFactoryPostProcessors这一步,
会调用所有实现BeanFactoryPostProcessor接口和BeanDefinitionRegistryPostProcessor接口的类的两个相应方法,
@Configuration注解的解析:
上面的两个方法都最终会执行processConfigBeanDefinitions方法,逻辑是判断所有已经注册的beanname,上面有没有注解@Configuration,如果有的话,用ConfigurationClassParser解析
parser = new ConfigurationClassParser,parser.parse(candidates);
解析的逻辑是:
对所有的内部类,重新进行parse方法(不严谨但是差不多啦)
然后看看自己的类上面有没有
@PropertySource注解,
@ComponentScan注解:逻辑是:有该注解的类,扫描下面的包,得到一批beanDefinition,然后这批bd出来之后直接用ConfigurationClassUtils.checkConfigurationClassCandidate方法判断,然后进入processConfigurationClass
方法,但是如果被扫描包里面,只有@Import注解的类,是不会扫描其中的@Import,@Bean等注解的,那说明得到这批beanDefinition的时候,已经过滤了,只扫描有@Component注解的(@Configuration也是包含@Component的)。
具体办法是:componentScanParser.parse方法中,scanner.doScan方法中findCandidateComponents中isCandidateComponent的excludeFilters和includeFilters,而默认的filter只会包含@Component或者其他的什么
@ManagedBean、JSR-330:@Named等等。上面说的scanner是ClassPathBeanDefinitionScanner,在构造方法中有registerDefaultFilters();
其实这样看起来,@[email protected]注解没啥用,完全可以用@component代替///@EnableAutoConfiguration其实是两个@Import注解的组合,一个导入AutoConfigurationImportSelector.class,一个通过
@AutoConfigurationPackage导入AutoConfigurationPackages.Registrar.class
@Import注解:先根据@Import注解里面的值,看该类上面有没有@Import注解,如果有,也加入进来,然后对于所有的候选类,如果是ImportSelector,或者ImportBeanDefinitionRegistrar,如果都不是,那么当作@Configuration
@ImportResource注解,
@Bean注解,
然后看它的父类,parse父类(也不严谨但是也差不多啦),直到父类以java开头?
所以这里可以看出,对类上面有没有@Configuration的判断,只在当前类上进行,而它的内部类和父类,都不做判断。那么一个@Configuration的类,它的内部类和父类,都要判断里面的注解类型
最后,会放到 工厂的 configurationClasses属性中
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
原文地址:https://www.cnblogs.com/chuliang/p/9081420.html