Springboot启动原理和自动配置原理

yizhihongxing

放本地文件夹都快吃土了,准备清理文件夹,关于Springboot的!

启动原理

@SpringBootApplication
public class Start {

    public static void main(String[] args) {
        SpringApplication.run(Start.class, args);
    }

}

SpringApplication

1、初始化

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }
 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.sources = new LinkedHashSet(); // 
        this.bannerMode = Mode.CONSOLE;// 控制banner
        this.logStartupInfo = true;// 是否启动日志
        this.addCommandLineProperties = true; // 读取命令行配置
        this.addConversionService = true; //添加转换器
        this.headless = true; // 
        this.registerShutdownHook = true; // 注册重启
        this.additionalProfiles = Collections.emptySet();// 读取配置环境
        this.isCustomEnvironment = false;// 是否是自定义环境
        this.lazyInitialization = false; // 是否懒加载
        this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
        this.applicationStartup = ApplicationStartup.DEFAULT; // ApplicationStartup DEFAULT = new DefaultApplicationStartup();
        this.resourceLoader = resourceLoader;// 资源加载器
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); // 主程序
        this.webApplicationType = WebApplicationType.deduceFromClasspath();//  SERVLET||REACTIVE; 是servlet还是reactive环境
        // BootstrapRegistryInitializer
	this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
        // ApplicationContextInitializer
	this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
	// ApplicationListener        
	this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

注册 BootstrapRegistryInitializer

this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));

// 
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = this.getClassLoader();
        // 1、从配置文件读取名称加载
        Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // 2、获取构造器实例
 	List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        // 3、排序
	 AnnotationAwareOrderComparator.sort(instances);
        return instances;
}

// 1、加载配置
 private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            HashMap result = new HashMap();

            try {
                 //核心 从这里知道读取配置文件位置 默认
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");
		// ... 这里省略迭代器遍历注册
                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
		// 添加到缓存中,下次读取。根据类名读取
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
            }
        }
    }

// 2、获取构造器实例
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
        List<T> instances = new ArrayList(names.size());
        Iterator var7 = names.iterator();

        while(var7.hasNext()) {
            String name = (String)var7.next();

            try {
                // 通过类名反射机制调用,读取Class<T> class
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, instanceClass);
                Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
                // 获取构造器实例
 		T instance = BeanUtils.instantiateClass(constructor, args);
                // 添加到构造器中
                instances.add(instance);
            } catch (Throwable var12) {
                throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);
            }
        }
	// 返回
        return instances;
    }


// 排序 通过debug这里调用的是Integer类型排序方法 List<Integer> list
  public static void sort(List<?> list) {
        if (list.size() > 1) {
            list.sort(INSTANCE);
        }

    }

配置文件

spring-boot:2.7.1.META-INF\spring.factorie

org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

Springboot启动原理和自动配置原理

像 BootstrapRegistryInitializer

另外几个配置是从其他配置文件中读取的

例如

Springboot启动原理和自动配置原理

注册 ApplicationContextInitializer 、ApplicationListener

BootstrapRegistryInitializer加载原理

2、调用run方法

核心

public ConfigurableApplicationContext run(String... args) {
        long startTime = System.nanoTime();
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        ConfigurableApplicationContext context = null;
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            // 加载所有注解使用的扫描的组件
	    this.refreshContext(context);
	    // 刷新
            this.afterRefresh(context, applicationArguments);
            Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
            }

            listeners.started(context, timeTakenToStartup);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var12) {
            this.handleRunFailure(context, var12, listeners);
            throw new IllegalStateException(var12);
        }

        try {
            Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
            listeners.ready(context, timeTakenToReady);
            return context;
        } catch (Throwable var11) {
            this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var11);
        }
    }

所有组件经过org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader方法加载注册组件

private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
        AnnotationMetadata metadata = configClass.getMetadata();
        AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
        ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
        configBeanDef.setScope(scopeMetadata.getScopeName());
        String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
        AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        // 在这里注册
	this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
        configClass.setBeanName(configBeanName);
        if (logger.isTraceEnabled()) {
            logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
        }

    }

org.springframework.beans.factory.support.DefaultListableBeanFactory

  • registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition())
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(existingDefinition)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			// 注册
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					removeManualSingletonName(beanName);
				}
			}
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
		else if (isConfigurationFrozen()) {
			clearByTypeCache();
		}
	}

自动配置原理

该部分暂时找不到了,之前备份找不到了,先TODO下吧!

原文链接:https://www.cnblogs.com/wuxin001/p/17351482.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Springboot启动原理和自动配置原理 - Python技术站

(0)
上一篇 2023年4月24日
下一篇 2023年4月25日

相关文章

  • Java实现读取及生成Excel文件的方法

    生成Excel文件可以使用Apache POI库,读取Excel文件可以使用JXL或者Apache POI库。 使用Apache POI进行Excel文件读取及生成 要使用Apache POI进行Excel文件处理,需要添加以下maven依赖: <dependency> <groupId>org.apache.poi</grou…

    Java 2023年5月20日
    00
  • 解决mybatis-plus使用jdk8的LocalDateTime 查询时报错的方法

    下面我来详细讲解“解决mybatis-plus使用jdk8的LocalDateTime查询时报错的方法”的完整攻略。 问题描述 在使用mybatis-plus时,如果使用了jdk8的LocalDateTime类型进行查询操作,可能会出现以下的错误: There is no TypeHandler found for property xxxx 这是由于myb…

    Java 2023年5月20日
    00
  • Java实现Excel导入导出数据库的方法示例

    下面是Java实现Excel导入导出数据库的方法示例的完整攻略: 一、Excel导入数据库: 首先,需要添加相关的依赖包,如以下示例代码所示: <!– poi组件 –> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi&…

    Java 2023年5月20日
    00
  • java8新特性教程之time包使用总结

    Java8新特性教程之time包使用总结 Java8引入了java.time包,为Java的日期和时间处理提供了全新的API。新的API包括了很多改进和新增的功能,例如: 新的日期和时间API更加安全; 新的日期和时间API更加简单,提升了开发效率; 新的日期和时间API实现了时区处理,并且更加清晰易懂; 新的日期和时间API提供了可读性更强的代码。 Jav…

    Java 2023年5月20日
    00
  • Java实现经典拳皇误闯冒险岛游戏的示例代码

    让我来详细给你讲解Java实现经典拳皇误闯冒险岛游戏的示例代码的完整攻略。 核心思路 经典拳皇误闯冒险岛游戏的核心思路是将两个游戏融合在一起,使得玩家能够在游戏中既能享受打拳皇的快感,又能够领略冒险岛的神奇之旅。在实现这个目标的过程中,需要分别实现拳皇游戏和冒险岛游戏的核心逻辑,并将它们合并在一起。 实现步骤 首先,我们需要将拳皇游戏的代码和冒险岛游戏的代码…

    Java 2023年5月23日
    00
  • Java编程中最基础的文件和目录操作方法详解

    Java编程中最基础的文件和目录操作方法详解 在 Java 编程中,文件和目录操作是最基础的操作之一。Java 提供了丰富的类库,可以方便地完成文件和目录的读写、创建、修改、删除等操作。在本文中,我们将详细介绍 Java 编程中最基础的文件和目录操作方法,包括文件的读写、文件夹的创建、遍历、复制和删除等操作。 文件读写 读取文件内容 Java 中读取文件的方…

    Java 2023年6月1日
    00
  • 详解SpringBoot配置连接池

    Spring Boot是一个快速创建Web应用程序的框架,它提供了许多便捷的功能和工具,其中包括连接池。连接池是一种管理数据库连接的技术,它可以提高应用程序的性能和可伸缩性。下面是详解Spring Boot配置连接池的完整攻略: 添加依赖项 首先,我们需要在pom.xml文件中添加连接池依赖项。Spring Boot支持多种连接池,包括HikariCP、To…

    Java 2023年5月14日
    00
  • 从零开始在Centos7上部署SpringBoot项目

    从零开始在CentOS7上部署Spring Boot项目,大致分为以下几个步骤: 安装Java环境 在CentOS7上部署Spring Boot项目,首先需要安装Java环境。可以通过以下命令安装: yum install java-1.8.0-openjdk-devel 安装完成后,可以通过以下命令查看Java版本: java -version 安装Mav…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部