SpringBoot 源码解析 (一)----- Spring Boot 注解分析

本文介绍了SpringBoot,一个用于简化Spring应用程序开发的框架,强调其自动配置、嵌入式Web服务器、轻量级特性及Maven集成。通过实例展示了如何使用SpringBoot快速搭建一个简单的Web应用。
摘要由CSDN通过智能技术生成

Spring Boot 概述:

Build Anything with Spring Boot:Spring Boot is the starting point for building all Spring-based applications. Spring Boot is designed to get you up and running as quickly as possible, with minimal upfront configuration of Spring

用 Spring Boot 构建任何东西:Spring Boot 是构建所有基于 Spring 的应用程序的起点。Spring Boot 旨在使您尽快启动并运行,同时对 Spring 进行最小的前期配置

Spring Boot 优点:

Spring Boot 是一个基于 Java 的开源框架,它旨在简化 Spring 应用程序的创建和部署。Spring Boot 通过提供自动配置、内置的依赖解析和管理、以及对各种生产环境下的应用程序监控和管理的支持,使得开发者能够更快速、更轻松地开发基于 Spring 的应用程序。

以下是 Spring Boot 的主要特点:

  1. 独立运行:Spring Boot 应用程序可以作为独立的应用程序运行,不需要部署到 Web 服务器或应用服务器。
  2. 自动配置:Spring Boot 会根据项目中的依赖关系自动进行配置,减少了手动配置的工作量。
  3. 嵌入式 Web 服务器:Spring Boot 提供了内置的 Web 服务器,例如 Tomcat 和 Jetty,使得应用程序能够快速启动和运行。
  4. 提供生产就绪功能:Spring Boot 提供了许多用于监控和管理生产环境下的应用程序的功能,例如健康检查、指标收集和应用程序信息。
  5. 无代码生成和 XML 配置:Spring Boot 通过 Java 注解、属性文件和 YAML 文件支持配置,避免了繁琐的 XML 配置。
  6. 与 Spring 框架集成:Spring Boot 是基于 Spring 框架开发的,因此它可以与 Spring 框架的其他组件无缝集成。
  7. 丰富的插件支持:Spring Boot 提供了许多插件,方便与其他流行的框架和库集成,如 Hibernate、Thymeleaf、Spring Data 等。
  8. 国际化:Spring Boot 支持国际化和本地化,可以轻松地实现多语言支持。
  9. 轻量级和可扩展性:Spring Boot 是轻量级的,易于学习和使用,同时它也是可扩展的,可以根据需求添加或替换组件。

话不多说,开搞,了解语言先来一个 helloword,祭出三板斧,然后在打断点一步一步看

pom 加依赖用于依赖集成整合第三方依赖
启动类加注解根据需求自定义添加即可
application.properties 写配置全局配置文件,配置均在此文件中配置

先来简单的一个 helloword

第一步: pom 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.chenhao</groupId>
    <artifactId>springboot</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springboot</name>
    <description>Demo project for Spring Boot</description>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath/>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

第二步,启动类加注解

/**
 * @SpringBootApplication来标注一个主程序类,说明这是一个SpringBoot应用
 */
@SpringBootApplication
public class HelloWorldMainApplication {

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

第三步,写配置

server.port=8081

然后写一个控制类: 输出 helloword

    @RestController
    public class HelloController {
    
        @RequestMapping("/hello")
        public String hello(){
            return "Hello world";
        }
    }

我们看依赖:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

这个依赖帮助我们完成了 前端请求到服务端处理然后返回给前端的所有工作

我们点进去看下,都一些啥:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
    </dependency>

tomcat web mvc 我们熟悉的 mvc 三件套。

然后我们再看 springboot主类注解

@SpringBootApplication
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication 

我们可以看到他是一个复合注解,

@SpringBootConfiguration
  • Spring Boot 的配置类
  • 标注在某个类上,表示这是一个 Spring Boot 的配置类

注解定义如下:

     @Configuration
     public @interface SpringBootConfiguration {}
@EnableAutoConfiguration
  • 开启自动配置功能,Spring Boot 帮助自动配置;
  • 通知 SpringBoot 开启自动配置功能,这样自动配置才能生效。

注解定义如下:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

@AutoConfigurationPackage

  • 开启自动配置包功能,自动扫描主类包下的所有 bean 并注入到spring 容器
  • 主要实现是使用AutoConfigurationPackages.Registrar类

注解定义如下:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({AutoConfigurationPackages.Registrar.class})
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
}

@Import(AutoConfigurationPackages.Registrar.class) 

  • 默认将主配置类 ( @SpringBootApplication ) 所在的包及其子包里面的所有组件扫描到 Spring 容器中。如下

    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }

        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new PackageImports(metadata));
        }
    }

@Import(EnableAutoConfigurationImportSelector. class)

  • 导入哪些组件的选择器,将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中。
AutoConfigurationImportSelector类
  1. 	@Override
    	public String[] selectImports(AnnotationMetadata annotationMetadata) {
    		// 会在所有@Configuration都解析完了之后才执行
    
    		if (!isEnabled(annotationMetadata)) {
    			return NO_IMPORTS;
    		}
    
    		// 获取自动配置类(spring.factories中所导入的)
    		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
    		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    	}
    
  2. 	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    		if (!isEnabled(annotationMetadata)) {
    			return EMPTY_ENTRY;
    		}
    		// 获取@EnableAutoConfiguration的属性
    		AnnotationAttributes attributes = getAttributes(annotationMetadata);
    		// 获取spring.factories中所有的AutoConfiguration
    		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    		// 去重(也就是按类名去重)
    		configurations = removeDuplicates(configurations);
    		// 获取需要排除的AutoConfiguration,可以通过@EnableAutoConfiguration注解的exclude属性,或者spring.autoconfigure.exclude来配置
    		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    
    		// 排除
    		checkExcludedClasses(configurations, exclusions);
    		configurations.removeAll(exclusions);
    
    		// 获取spring.factories中的AutoConfigurationImportFilter对AutoConfiguration进行过滤
    		// 默认会拿到OnBeanCondition、OnClassCondition、OnWebApplicationCondition
    		// 这三个会去判断上面的AutoConfiguration是否符合它们自身所要求的条件,不符合的会过滤掉,表示不会进行解析了
    		// 会利用spring-autoconfigure-metadata.properties中的配置来进行过滤
    		// spring-autoconfigure-metadata.properties文件中的内容是利用Java中的AbstractProcessor技术在编译时生成出来的
    		configurations = getConfigurationClassFilter().filter(configurations);
    		// configurations表示合格的,exclusions表示被排除的,把它们记录在ConditionEvaluationReportAutoConfigurationImportListener中
    		fireAutoConfigurationImportEvents(configurations, exclusions);
    
    		// 最后返回的AutoConfiguration都是符合条件的
    		return new AutoConfigurationEntry(configurations, exclusions);
    	}
  3. 	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    		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;
    	}
    	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    		ClassLoader classLoaderToUse = classLoader;
    		if (classLoaderToUse == null) {
    			classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
    		}
    		String factoryTypeName = factoryType.getName();
    		return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    	}
    
    	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
    		Map<String, List<String>> result = cache.get(classLoader);
    		if (result != null) {
    			return result;
    		}
    
    		result = new HashMap<>();
    		try {
    			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
    			while (urls.hasMoreElements()) {
    				URL url = urls.nextElement();
    				UrlResource resource = new UrlResource(url);
    				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
    				for (Map.Entry<?, ?> entry : properties.entrySet()) {
    					String factoryTypeName = ((String) entry.getKey()).trim();
    					String[] factoryImplementationNames =
    							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
    					for (String factoryImplementationName : factoryImplementationNames) {
    						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
    								.add(factoryImplementationName.trim());
    					}
    				}
    			}
    
    			// Replace all lists with unmodifiable lists containing unique elements
    			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
    					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
    			cache.put(classLoader, result);
    		}
    		catch (IOException ex) {
    			throw new IllegalArgumentException("Unable to load factories from location [" +
    					FACTORIES_RESOURCE_LOCATION + "]", ex);
    		}
    		return result;
    	}
  4. 	protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    		Set<String> excluded = new LinkedHashSet<>();
    		excluded.addAll(asList(attributes, "exclude"));
    		excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
    		excluded.addAll(getExcludeAutoConfigurationsProperty());
    		return excluded;
    	}
    
    	protected List<String> getExcludeAutoConfigurationsProperty() {
    		Environment environment = getEnvironment();
    		if (environment == null) {
    			return Collections.emptyList();
    		}
    		if (environment instanceof ConfigurableEnvironment) {
    			Binder binder = Binder.get(environment);
    			return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList)
    					.orElse(Collections.emptyList());
    		}
    		String[] excludes = environment.getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
    		return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
    	}
  5. 	private ConfigurationClassFilter getConfigurationClassFilter() {
    		if (this.configurationClassFilter == null) {
    			List<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters();
    			for (AutoConfigurationImportFilter filter : filters) {
    				invokeAwareMethods(filter);
    			}
    			this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);
    		}
    		return this.configurationClassFilter;
    	}
    
    	protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
    		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
    	}
  6. List<String> filter(List<String> configurations) {
    			long startTime = System.nanoTime();
    			String[] candidates = StringUtils.toStringArray(configurations);
    			boolean skipped = false;
    
    			// 逐个利用AutoConfigurationImportFilter来判断所有的自动配置类的条件是否匹配,匹配结果存在match数组中
    			// 先利用OnBeanCondition进行过滤
    			// 再利用OnClassCondition进行过滤
    			// 再利用OnWebApplicationCondition进行过滤
    			for (AutoConfigurationImportFilter filter : this.filters) {
    				boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
    
    				for (int i = 0; i < match.length; i++) {
    					if (!match[i]) {
    						candidates[i] = null;
    						skipped = true;
    					}
    				}
    			}
    
    			// 全部都匹配
    			if (!skipped) {
    				return configurations;
    			}
    
    			// 把匹配的记录在result集合中,最后返回
    			List<String> result = new ArrayList<>(candidates.length);
    			for (String candidate : candidates) {
    				if (candidate != null) {
    					result.add(candidate);
    				}
    			}
    			if (logger.isTraceEnabled()) {
    				int numberFiltered = configurations.size() - result.size();
    				logger.trace("Filtered " + numberFiltered + " auto configuration class in "
    						+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
    			}
    			return result;
    		}
  7. 	private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
    
    		// ConditionEvaluationReportAutoConfigurationImportListener
    		// 条件评估报告
    		List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
    		if (!listeners.isEmpty()) {
    			AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
    			for (AutoConfigurationImportListener listener : listeners) {
    				invokeAwareMethods(listener);
    				listener.onAutoConfigurationImportEvent(event);
    			}
    		}
    	}
    
    
    	protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
    		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
    	}

重点方法介绍:

  1. 方法一、方法二:完成对META-INF/spring.factories 中配置的自动配置类加载,经过排除、过滤、条件评估后返回符合条件的实体
  2. 方法三:通过 spi 技术,完成对类路径下 META-INF/spring.factories 文件中配置的众多自动配置类解析,并缓冲。
  3. 方法四:收集自动配置注解配置了 exclue 或是spring.autoconfigure.exclude方式配置的 key.
  4. 方法五:通过 spi 技术,完成读取 META-INF/spring.factories 文件中配置的AutoConfigurationImportFilter自动配置类,并实例
  5. 方法六:通过 spi 技术,加载读取META-INF/spring-autoconfigure-metadata.properties文件中配置的元信息,将前面处理的自动配置信息集合通过OnBeanCondition、OnClassCondition、OnWebApplicationCondition三个方法依次进行过滤。
  6. 方法七:将处理好的,符合条件的和要排除的,写入到自动配置事件监听器中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值