SpringBoot原理分析

本文采用SpringBoot版本2.2.4.RELEASE

一、父项目

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.4.RELEASE</version>
        <relativePath/>
    </parent>

spring-boot-starter-parent的父项目:

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.2.4.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
  </parent>

spring-boot-dependencies来真正管理SpringBoot应用里面的所有依赖版本

二、探索SpringApplication启动Spring

@SpringBootApplication//标明是SpringBoot应用,可以开启自动配置的功能
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);//启动SpringBoot应用
    }

}
	public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
		return run(new Class<?>[] { primarySource }, args);
	}
	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	//创建SpringApplication对象,并执行运行
    return new SpringApplication(primarySources).run(args);
	}
	public ConfigurableApplicationContext run(String... args) {
    	//创建StopWatch对象,并启动。StopWatch主要用于简单统计run启动过程的时长
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
    	//获得SpringApplicationRunListener的数组,并启动监听
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
      		//创建ApplicationArguments对象
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      		//加载属性配置。执行完成后,所有的environment的属性都会加载进来,包括application.properties和外部的属性配置
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
      		//创建Spring容器
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
      		//调用所有初始化类的initialize方法
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
      		//初始化Spring容器
			refreshContext(context);
      		//执行Spring容器的初始化的后置逻辑。默认实现为空
			afterRefresh(context, applicationArguments);
      		//停止StopWatch统计时长
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
      		//通知SpringApplicationRunListener的数组,Spring容器启动完成
			listeners.started(context);
      		//调用ApplicationRunner或者CommandLineRunner的运行方法
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
      		//通知SpringApplicationRunListener的数组,Spring容器运行中
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

createApplicationContext()创建Spring容器:

	protected ConfigurableApplicationContext createApplicationContext() {
    	//根据webApplicationType类型,获得ApplicationContext类型
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
			}
		}
    	//创建ApplicationContext对象
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

prepareContext()调用所有初始化类的initialize方法:

	private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    	//设置context的environment属性
		context.setEnvironment(environment);
    	//设置context的一些属性
		postProcessApplicationContext(context);
    	//初始化ApplicationContextInitializer
		applyInitializers(context);
    	//通知SpringApplicationRunListener的数组,Spring容器准备完成
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		//设置beanFactory的属性
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		//加载BeanDefinition
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[0]));
    	//通知SpringApplicationRunListener的数组,Spring容器加载完成
		listeners.contextLoaded(context);
	}
	protected void load(ApplicationContext context, Object[] sources) {
		if (logger.isDebugEnabled()) {
			logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
		}
    	//执行BeanDefinition加载
		BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
    	//设置loader的属性
		if (this.beanNameGenerator != null) {
			loader.setBeanNameGenerator(this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			loader.setResourceLoader(this.resourceLoader);
		}
		if (this.environment != null) {
			loader.setEnvironment(this.environment);
		}
    	//执行BeanDefinition加载
		loader.load();
	}

三、Starter自动化配置原理

@SpringBootApplication注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited//使用@Inherite注解声明出来的自定义注解,在使用此自定义注解时,如果注解在类上面时,子类会自动继承此注解;否则的话,子类不会继承此注解
@SpringBootConfiguration//标记这是一个SpringBoot配置类
@EnableAutoConfiguration//开启自动配置功能
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

@EnableAutoConfiguration注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage//自动配置包,它会获取主程序类所在的包路径,并将包路径(包括子包)下的所有组件注册到IOC容器中
@Import(AutoConfigurationImportSelector.class)//导入自动配置相关的资源
public @interface EnableAutoConfiguration {

AutoConfigurationImportSelector类:

getCandidateConfigurations()获得符合条件的配置类的数组:

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    	//加载指定类型EnableAutoConfiguration对应的,在META-INF/spring.factories里的类名的数组
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

在这里插入图片描述

每一个*AutoConfiguration类加入到容器中,用他们来做自动配置

HttpEncodingAutoConfiguration(Http编码自动配置)为例:

@Configuration(proxyBeanMethods = false)//表明这是一个配置类
@EnableConfigurationProperties(HttpProperties.class)//启用指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把HttpEncodingProperties加入到IOC容器中
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)//Spring底层@ConditionalOn注解,根据不同的条件,如果满足指定的条件,整 个配置类里面的配置才会生效; 判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnClass(CharacterEncodingFilter.class)//判断当前项目有没有这个类 CharacterEncodingFilter:SpringMVC中进行乱码解决的过滤器
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)//判断配置文件中是否存在某个配置spring.http.encoding.enabled;如果不存在判断也是成立的
//matchIfMissing=true:即使配置文件中不配置spring.http.encoding.enabled=true,也是默认生效的
public class HttpEncodingAutoConfiguration {

	private final HttpProperties.Encoding properties;

	public HttpEncodingAutoConfiguration(HttpProperties properties) {
		this.properties = properties.getEncoding();
	}

	@Bean//给容器中添加一个组件,这个组件的某些值需要从properties中获取
	@ConditionalOnMissingBean
	public CharacterEncodingFilter characterEncodingFilter() {
		CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
		filter.setEncoding(this.properties.getCharset().name());
		filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
		filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
		return filter;
	}

一旦配置类生效,这个配置类就会给容器中添加各种组件,这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的

@ConfigurationProperties(prefix = "spring.http")//从配置文件中获取指定的值和bean的属性进行绑定
public class HttpProperties {

四、Conditional机制实现

@Conditional注解根据特定条件来控制bean的创建行为

@Conditional扩展注解作用(判断是否满足当前指定条件)
@ConditionalOnJava系统的java版本是否符合要求
@ConditionalOnBean容器中存在指定Bean
@ConditionalOnMissingBean容器中不存在指定Bean
@ConditionalOnExpression满足SpEL表达式指定
@ConditionalOnClass系统中有指定的类
@ConditionalOnMissingClass系统中没有指定的类
@ConditionalOnSingleCandidate容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty系统中指定的属性是否有指定的值
@ConditionalOnResource类路径下是否存在指定资源文件
@ConditionalOnWebApplication当前是web环境
@ConditionalOnNotWebApplication当前不是web环境
@ConditionalOnJndiJNDI存在指定项

@ConditionalOnProperty注解为例:

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {

OnPropertyCondition类:

getMatchOutcome()方法获得匹配结果:

	@Override
	public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
    	//获得@ConditionalOnProperty注解的属性
		List<AnnotationAttributes> allAnnotationAttributes = annotationAttributesFromMultiValueMap(
				metadata.getAllAnnotationAttributes(ConditionalOnProperty.class.getName()));
    	//存储匹配和不匹配的结果消息结果
		List<ConditionMessage> noMatch = new ArrayList<>();
		List<ConditionMessage> match = new ArrayList<>();
    	//遍历annotationAttributes属性数组,逐个判断是否匹配,并添加到结果
		for (AnnotationAttributes annotationAttributes : allAnnotationAttributes) {
			ConditionOutcome outcome = determineOutcome(annotationAttributes, context.getEnvironment());
			(outcome.isMatch() ? match : noMatch).add(outcome.getConditionMessage());
		}
    	//如果有不匹配的,则返回不匹配
		if (!noMatch.isEmpty()) {
			return ConditionOutcome.noMatch(ConditionMessage.of(noMatch));
		}
    	//如果都匹配,则返回匹配
		return ConditionOutcome.match(ConditionMessage.of(match));
	}
	private ConditionOutcome determineOutcome(AnnotationAttributes annotationAttributes, PropertyResolver resolver) {
    	//解析成Spec对象
		Spec spec = new Spec(annotationAttributes);
    	//创建结果数组
		List<String> missingProperties = new ArrayList<>();
		List<String> nonMatchingProperties = new ArrayList<>();
    	//收集是否不匹配的信息,到missingProperties、nonMatchingProperties中
		spec.collectProperties(resolver, missingProperties, nonMatchingProperties);
    	//如果有属性缺失,则返回不匹配
		if (!missingProperties.isEmpty()) {
			return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnProperty.class, spec)
					.didNotFind("property", "properties").items(Style.QUOTE, missingProperties));
		}
    	//如果有属性不匹配,则返回不匹配
		if (!nonMatchingProperties.isEmpty()) {
			return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnProperty.class, spec)
					.found("different value in property", "different value in properties")
					.items(Style.QUOTE, nonMatchingProperties));
		}
    	//返回匹配
		return ConditionOutcome
				.match(ConditionMessage.forCondition(ConditionalOnProperty.class, spec).because("matched"));
	}

参考:

《Spring源码深度解析》

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邋遢的流浪剑客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值