SpringBoot启动流程源码分析( 六 )

复制
SpringApplication#applyInitializers方法protected void applyInitializers(ConfigurableApplicationContext context) {// 获取初始化器迭代器Iterator var2 = this.getInitializers().iterator();// 循环遍历初始化器迭代器while(var2.hasNext()) {ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next();// 根据解析器calss类型和应用上下文初始化器calss类型解析参数类型Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");initializer.initialize(context);}}复制
GenericTypeResolver#resolveTypeArgument方法@Nullablepublic static Class<?> resolveTypeArgument(Class<?> clazz, Class<?> genericIfc) {ResolvableType resolvableType = ResolvableType.forClass(clazz).as(genericIfc);return !resolvableType.hasGenerics() ? null : getSingleGeneric(resolvableType);}// 加载解析类public static ResolvableType forClass(@Nullable Class<?> clazz) {return new ResolvableType(clazz);}// 判断是否有解析类型数组public boolean hasGenerics() {return this.getGenerics().length > 0;}// 获取单个解析类型@Nullableprivate static Class<?> getSingleGeneric(ResolvableType resolvableType) {Assert.isTrue(resolvableType.getGenerics().length == 1, () -> {return "Expected 1 type argument on generic interface [" + resolvableType + "] but found " + resolvableType.getGenerics().length;});return resolvableType.getGeneric(new int[0]).resolve();}复制
加载Spring应用上下文中的beanSpringApplication#load方法protected void load(ApplicationContext context, Object[] sources) {if (logger.isDebugEnabled()) {// 如果开启了debug级别日志 , 则记录debug日志logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));}// 创建BeanDefinitionLoader类实例BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.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();}// 通过BeanDefinitionRegistry类实例参数和应用源数组构造BeanDefinitionLoader类实例protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {return new BeanDefinitionLoader(registry, sources); }复制
BeanDefinitionLoader类带两个参数的构造方法源码:
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {// 断言registry和sources两个参数不能为空Assert.notNull(registry, "Registry must not be null");Assert.notEmpty(sources, "Sources must not be empty");this.sources = sources;// 初始化基于注解的BeanDefinitionReaderthis.annotatedReader = new AnnotatedBeanDefinitionReader(registry);// 初始化基于xml的BeanDefinitionReaderthis.xmlReader = new XmlBeanDefinitionReader(registry);if (this.isGroovyPresent()) {// 如果存在groovy脚本则初始化基于Groovy的BeanDefinitionReaderthis.groovyReader = new GroovyBeanDefinitionReader(registry);}// 初始化类路径bean定义扫描器this.scanner = new ClassPathBeanDefinitionScanner(registry);// 扫描器添加排除过滤器,排除扫描启动类this.scanner.addExcludeFilter(new BeanDefinitionLoader.ClassExcludeFilter(sources));}复制
BeanDefinitionLoader#load方法然后我们回到BeanDefinitionLoader#load方法 , springboot项目中的bean具体是如何加载的我们在springboot项目的启动调试过程再来分析
int load() {int count = 0;Object[] var2 = this.sources;int var3 = var2.length;for(int var4 = 0; var4 < var3; ++var4) {Object source = var2[var4];// 每加载一个bean来源,记录加载数量的count会+1count += this.load(source);}return count;}// 这个加载bean的方法会根据不同的bean来源进行加载 , bean是如何加载的关键就在下面这几个load方法里面private int load(Object source) {Assert.notNull(source, "Source must not be null");if (source instanceof Class) {// 加载配置类中的beanreturn this.load((Class)source);} else if (source instanceof Resource) {// 加载类路径资源中的bean,包括groovy和xml文件中配置的beanreturn this.load((Resource)source);} else if (source instanceof Package) {// 加载包下面的不同配置类中的beanreturn this.load((Package)source);} else if (source instanceof CharSequence) {// 加载根据制定路径的xml文件中配置的beanreturn this.load((CharSequence)source);} else {throw new IllegalArgumentException("Invalid source type " + source.getClass());}}private int load(Class<?> source) {if (this.isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {BeanDefinitionLoader.GroovyBeanDefinitionSource loader = (BeanDefinitionLoader.GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);this.load(loader);}if (this.isComponent(source)) {this.annotatedReader.register(new Class[]{source});return 1;} else {return 0;}}private int load(Resource source) {if (source.getFilename().endsWith(".groovy")) {if (this.groovyReader == null) {throw new BeanDefinitionStoreException("Cannot load Groovy beans without Groovy on classpath");} else {return this.groovyReader.loadBeanDefinitions(source);}} else {return this.xmlReader.loadBeanDefinitions(source);}}private int load(Package source) {return this.scanner.scan(new String[]{source.getName()});}private int load(CharSequence source) {String resolvedSource = this.xmlReader.getEnvironment().resolvePlaceholders(source.toString());try {return this.load(ClassUtils.forName(resolvedSource, (ClassLoader)null));} catch (ClassNotFoundException | IllegalArgumentException var10) {Resource[] resources = this.findResources(resolvedSource);int loadCount = 0;boolean atLeastOneResourceExists = false;Resource[] var6 = resources;int var7 = resources.length;for(int var8 = 0; var8 < var7; ++var8) {Resource resource = var6[var8];if (this.isLoadCandidate(resource)) {atLeastOneResourceExists = true;loadCount += this.load(resource);}}if (atLeastOneResourceExists) {return loadCount;} else {Package packageResource = this.findPackage(resolvedSource);if (packageResource != null) {return this.load(packageResource);} else {throw new IllegalArgumentException("Invalid source '" + resolvedSource + "'");}}}}

推荐阅读