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 的主要特点:
- 独立运行:Spring Boot 应用程序可以作为独立的应用程序运行,不需要部署到 Web 服务器或应用服务器。
- 自动配置:Spring Boot 会根据项目中的依赖关系自动进行配置,减少了手动配置的工作量。
- 嵌入式 Web 服务器:Spring Boot 提供了内置的 Web 服务器,例如 Tomcat 和 Jetty,使得应用程序能够快速启动和运行。
- 提供生产就绪功能:Spring Boot 提供了许多用于监控和管理生产环境下的应用程序的功能,例如健康检查、指标收集和应用程序信息。
- 无代码生成和 XML 配置:Spring Boot 通过 Java 注解、属性文件和 YAML 文件支持配置,避免了繁琐的 XML 配置。
- 与 Spring 框架集成:Spring Boot 是基于 Spring 框架开发的,因此它可以与 Spring 框架的其他组件无缝集成。
- 丰富的插件支持:Spring Boot 提供了许多插件,方便与其他流行的框架和库集成,如 Hibernate、Thymeleaf、Spring Data 等。
- 国际化:Spring Boot 支持国际化和本地化,可以轻松地实现多语言支持。
- 轻量级和可扩展性: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类
-
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { // 会在所有@Configuration都解析完了之后才执行 if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } // 获取自动配置类(spring.factories中所导入的) AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }
-
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); }
-
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; }
-
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(); }
-
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); }
-
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; }
-
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); }
重点方法介绍:
- 方法一、方法二:完成对META-INF/spring.factories 中配置的自动配置类加载,经过排除、过滤、条件评估后返回符合条件的实体
- 方法三:通过 spi 技术,完成对类路径下 META-INF/spring.factories 文件中配置的众多自动配置类解析,并缓冲。
- 方法四:收集自动配置注解配置了 exclue 或是spring.autoconfigure.exclude方式配置的 key.
- 方法五:通过 spi 技术,完成读取 META-INF/spring.factories 文件中配置的AutoConfigurationImportFilter自动配置类,并实例
- 方法六:通过 spi 技术,加载读取META-INF/spring-autoconfigure-metadata.properties文件中配置的元信息,将前面处理的自动配置信息集合通过OnBeanCondition、OnClassCondition、OnWebApplicationCondition三个方法依次进行过滤。
- 方法七:将处理好的,符合条件的和要排除的,写入到自动配置事件监听器中。