Spring 解析和注册 BeanDefinitions
有两种方式,一种XML,大部分的参考博客和文档都用自己作为解析的方法,另外一种是基于注解的扫描方法。SpringBoot 在初始化Context前,会先自己定义源,然后由 invokeBeanFactoryPostProcessors()
作为入口,进而协助解析和注册,即使是最简单的 Spring Boot 程序,这部分也比较耗时间。
/** * Run the Spring application, creating and refreshing a new * {@link ApplicationContext}. * @param args the application arguments (usually passed from a Java main method) * @return a running {@link ApplicationContext} */ public ConfigurableApplicationContext run(String... args) { ... 省略 try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); // prepareContext 会帮助保存source,bean的源 prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch ... 省略异常处理 return context; } 复制代码
SpringBoot 会以我们定义的主类作为 primarySources 去扫描 Beans。
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { ... 省略对context的初始化,和几个单例的注册 // Load the sources Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); // load load(context, sources.toArray(new Object[0])); listeners.contextLoaded(context); } 复制代码
// SpringApplication.java:677
/** * Load beans into the application context. * @param context the context to load beans into * @param sources the sources to load */ protected void load(ApplicationContext context, Object[] sources) { // BeanDefinitionLoader 把加载的逻辑代码独立委托给这个类(BeanDefinitions 加载器) 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(); } 复制代码
// BeanDefinitionLoader.java
/** * Load the sources into the reader. * @return the number of loaded beans */ int load() { int count = 0; for (Object source : this.sources) { // 加载每一个源 count += load(source); } return count; } private int load(Object source) { Assert.notNull(source, "Source must not be null"); if (source instanceof Class<?>) { // 一个Class对象都走这个 return load((Class<?>) source); } if (source instanceof Resource) { return load((Resource) source); } if (source instanceof Package) { return load((Package) source); } if (source instanceof CharSequence) { return load((CharSequence) source); } throw new IllegalArgumentException("Invalid source type " + source.getClass()); } private int load(Class<?> source) { if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) { // Any GroovyLoaders added in beans{} DSL can contribute beans here GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class); load(loader); } if (isComponent(source)) { // 把源放进 Reader this.annotatedReader.register(source); return 1; } return 0; } 复制代码
扫描加载的过程是由一个 BeanFactoryPostProcessor 接口的实现类进行的。
@ComponentScan
接口。
// 等待更新