SpringBoot-基础入门

布鸽不鸽 Lv4

视频地址

https://www.bilibili.com/video/BV19K4y1L7MT

文档地址

https://www.yuque.com/atguigu/springboot/oovrhy

一.基础入门

hello-world

编写项目

  • Maven依赖
1
2
3
4
5
6
7
8
9
10
11
12
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
  • 编写主类
1
2
3
4
5
6
7
8
9
package com.xuedongyun;

@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
  • 编写控制器
1
2
3
4
5
6
7
8
9
10
package com.xuedongyun.controller;

@RestController
public class HelloController {

@RequestMapping("/hello")
public String hello() {
return "hello world!";
}
}
  • 简化配置
1
2
# application.properties
server.port=8888
  • 运行main方法即可

打包

  • 打包为”fat jar”
  • 插件
1
2
3
4
5
6
7
8
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
  • mvn clear, mvn package

  • java -jar ./xxx.jar

(源码)父项目

  • 父项目
1
2
3
4
5
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
</parent>
  • 父项目的父项目
1
2
3
4
5
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.5</version>
</parent>
  • 点进去,声明了几乎所有依赖的版本号
1
2
3
4
5
6
7
<properties>
<activemq.version>5.16.5</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<appengine-sdk.version>1.9.98</appengine-sdk.version>
<artemis.version>2.19.1</artemis.version>
...
</properties>

版本仲裁:

  • 父项目声明了常用依赖的版本号,其他依赖无需写版本号(自动版本仲裁)
  • 自定义版本号
1
2
3
<properties>
<mysql.version>8.0.21</mysql.version>
</properties>
  • starter
    • 引入某种场景的依赖
    • 官方:spring-boot-starter-*
    • 第三方:*-spring-boot-starter

所有spring-boot-starter-*最基本的依赖都是spring-boot-starter

自动配置

graph LR
    web(spring-boot-starter-web)
    mvc(spring-webmvc)
    springWeb(spring-web)
    boot(spring-boot-starter)
    tomcat(spring-boot-starter-tomcat)
    web --> mvc
    web --> springWeb
    web --> boot
    web --> tomcat

自动配好Tomcat

  • 引入Tomcat依赖
  • 配置Tomcat

自动配好SpringMVC

  • 引入SpringMVC开发全套依赖
  • 配置SpringMVC常用功能
  1. 返回IOC容器
1
ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class, args);
  1. 查看IOC容器中的组件
1
String[] names = context.getBeanDefinitionNames();
  1. 发现有相关的组件
1
2
3
4
5
dispatcherServlet
characterEncodingFilter
viewResolver
multipartResolver
...

SpringBoot已经配置好了web开发常见场景

默认包扫描规则

  • 主程序所在包,及其子包,都会被自动扫描

  • 也可以指定基本包

1
2
3
4
5
6
7
@SpringBootApplication(scanBasePackages = "com.xuedongyun")

// 或者把这个合成注解直接拆开

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.xuedongyun")

各种properties配置

  • 默认配置会映射到MultipartProperties类上
  • 配置文件的值最终会绑定到每个类上,类在容器中创建对象

按需加载自动配置项

  • 存在非常多starter
  • 只会开启引入的starter的自动配置
  • 所有的自动配置功能都在spring-boot-autoconfigure
graph LR
    web(spring-boot-starter-web)
    boot(spring-boot-starter)
    config(spring-boot-autoconfigure)
    web-->boot-->config
  • 可以在项目依赖中看看
1
2
3
4
5
6
7
8
Maven: org.springframework.boot:spring-boot-autoconfigure:2.7.5
spring-boot-autoconfigure-2.7.5.jar
org.springframework.boot.autoconfigure
aop
AopAutoConfiguration
netty
NettyAutoConfiguration
...

有了什么场景,对应AutoConfig才能生效

容器功能

组件添加

@Configuration
1
2
3
4
5
6
7
8
9
10
11
package com.xuedongyun.config;

@Configuration
public class MyConfig {

@Bean
// @Bean("user01")
public User user() {
return new User("xdy", 12);
}
}

组件是单实例的

配置类本身也是组件

  • proxyBeanMethods:默认true,是否代理Bean的方法
    • 代理的话,重复调用方法从容器中拿,无论多少次都是同一个对象
1
@Configuration(proxyBeanMethods = true)
1
2
MyConfig config = context.getBean(MyConfig.class);
User user = config.user();
  • 组件依赖
    • proxyBeanMethods为true的情况下
1
2
3
4
5
@Bean
public User user() {
Pet pet = pet()
return new User("xdy", 12, pet);
}

Full模式与Lite模式:

  • Full(proxyBeanMethods=true)

    • 组件始终是单实例的
    • 组件依赖必须使用Full模式
  • Lite(proxyBeanMethods=false)

    • 返回的组件是新创建的
@Bean
  • @Bean
  • @Component
  • @Controller
  • @Service
  • @Repository
@Import
  • @ComponentScan
  • @Import
1
2
3
4
5
@Import({User.class, Pet.class})
@Configuration
public class MyConfig {

}

@Import:向容器中注入对应类型组件,默认组件名是全类名

“com.xuedongyun.User”: User{}

“com.xuedongyun.Pet”: Pet{}

@Conditional
  • 满足条件,才进行组件注入

  • 存在派生注解

1
2
3
4
5
6
7
8
9
10
11
12
@Conditional
@ConditionalOnBean // 容器存在指定Bean
@ConditionalOnMissingBean // 容器不存在指定Bean
@ConditionalOnClassBean // 容器存在指定类型的对象
@ConditionalOnMissingClassBean // 容器不存在指类型的对象
@ConditionalOnResource // 容器类路径存在指定资源
@ConditionalOnJava // 指定Java版本号
@ConditionalOnWebApplication // 应用是Web应用
@ConditionalOnNotWebApplication // 应用不是Web应用
@ConditionOnSingleCandidate // 指定组件只有一个实例(或只有一个主实例)
@ConditionOnProperty // 配置文件配置了某属性
...
1
2
3
4
5
6
7
8
9
10
@Bean
public Pet pet() {
return new Pet("tiny");
}

@Bean
@ConditionalOnBean(name = "pet")
public User user() {
return new User("xdy", 12);
}
1
2
3
4
5
6
// 也可以用在类上
@Configuration
@ConditionalOnBean({Test.class})
public class MyConfig {

}

注意Bean注册有顺序,有兴趣可以深入了解

引入xml配置

  • 适配之前写过的xml文件
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="user" class="com.atguigu.boot.bean.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
</beans>
1
2
@ImportResource("classpath:beans.xml")
public class MyConfig {}

配置绑定

  • 引入property配置文件,两种方法
@ConfigurationProperties
1
2
mycar.name=BYD
mycar.price=100000
1
2
3
4
5
6
7
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {

private String name;
private String price;
}
1
2
3
4
5
6
7
8
9
10
11
@RestController
public class HelloController {

@Autowired // 现在其实推荐使用构造器注入
Car car;

@RequestMapping("/car")
public Car car() {
return car;
}
}
@EnableConfigurationProperties
1
2
3
4
5
6
7
@Configuration
@EnableConfigurationProperties(Car.class)
// 1. 开启Car的属性配置功能
// 2. 把组件自动导入容器中
public class MyConfig {

}
1
2
3
4
5
6
@ConfigurationProperties(prefix = "mycar")
public class Car {

private String name;
private String price;
}

这样Car就不用加@Component

实际场景:比如Car是一个第三方包中的类

(源码)自动配置原理

  • @SpringBootApplication的核心
1
2
3
4
5
6
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})

1. @SpringBootConfiguration

  • Main程序也是SpringBoot中的配置类,只不过是核心配置类
1
2
// 核心
@Configuration

2. @ComponentScan

  • 指定扫描哪些,Spring注解,可以看看具体用法
  • 意义不算很大

3. @EnableAutoConfiguration

1
2
3
// 核心
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)

@AutoConfigurationPackage

  • 翻译:自动配置包
1
2
// 核心
@Import(AutoConfigurationPackages.Registrar.class)
  • 为容器导入Registrar组件(@Import的高级用法 )
  • 利用Registrar为容器中导入一系列组件
    • AnnotationMetadata:注解元信息,当前注解(@AutoConfigurationPackage)的一些信息,标在哪里,属性值是多少等等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// ↓ 批量注册,断点打在这
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}

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

}
  • 利用注解元信息,获取包名,封装到数组中
1
new PackageImports(metadata).getPackageNames().toArray(new String[0])
  • 第一个参数是BeanDefinitionRegistry对象,用于向IOC容器中注册组件
  • 第二个参数是一个字符串数组,存包的全限定名
  • 该方法扫描指定的包,将其中组件注册到IOC容器中
1
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0])); 

@Import(…)

  • 导入AutoConfigurationImportSelector类型的Bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
...

@Override
返回值:给容器中导入哪些组件
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 结果都是由它返回的
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

...
}
  • 查看getAutoConfigurationEntry()方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 给容器中批量导入组件
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// ↓ 断点,
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 加载所有候选的配置
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 后面对configurations进行一系列操作,最后返回
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
  • getCandidateConfigurations获取所有候选的配置(目前144个)
1
2
// ↓步入
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
1
2
3
4
5
"org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration"
"org.springframework.boot.autoconfigure.aop.AopAutoConfiguration"
"org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration"
"org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration"
...
  • 步入后可以看到,通过SpringFactoriesLoader工厂加载器,加载一些内容
1
2
3
4
5
6
7
8
9
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// loadFactoryNames()点进去看看
List<String> configurations = new ArrayList<>(
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader())
);
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations, "...");
return configurations;
}
  • 点进去可以看到,通过loadSpringFactories,继续点进去
1
2
3
4
5
6
7
8
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());
}
  • 利用loadSpringFactories加载得到一个Map<String, List<String>>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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 {
// 从“META-INF/spring.factories”加载文件
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;
}
  • META-INF/spring.factories加载文件,默认扫描系统所有位置包含META-INF/spring.factories的文件
1
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
  • 引入的所有jar包中,凡是有META-INF/spring.factories的包都将被扫到

  • spring-boot-autoconfigure-2.7.5.jar包也有这个文件

  • 可以看到,配置写死在这里。不同注解,所需要的包,都在其中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.autoconfigure.integration.IntegrationPropertiesEnvironmentPostProcessor

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.data.redis.RedisUrlSyntaxFailureAnalyzer,\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jooq.NoDslContextBeanFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.MissingR2dbcPoolDependencyFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.MultipleConnectionPoolConfigurationsFailureAnalzyer,\
org.springframework.boot.autoconfigure.r2dbc.NoConnectionFactoryBeanFailureAnalyzer,\
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer

# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider

# DataSource initializer detectors
org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializerDatabaseInitializerDetector

# Depends on database initialization detectors
org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\
org.springframework.boot.autoconfigure.batch.JobRepositoryDependsOnDatabaseInitializationDetector,\
org.springframework.boot.autoconfigure.quartz.SchedulerDependsOnDatabaseInitializationDetector,\
org.springframework.boot.autoconfigure.session.JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector

2.7.0以后,不推荐将配置写入工程中了,写在包下的Imports里

按需开启自动配置项

  • 虽然上述场景中,所有自动配置启动时默认加载全部(xxxAutoConfiguration
  • 按照每个类的装配规则(@Conditional),最终会按需配置

例1.AopAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@AutoConfiguration
// spring.aop.auto = true开启aop
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

// 存在Advice类,
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration { }

// 没有Advice类
// 开启的简单的aop功能
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
// spring.aop.proxy-target-class = true
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
static class ClassProxyingConfiguration { }
}

例2.CacheAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
@AutoConfiguration(after = { CouchbaseDataAutoConfiguration.class, HazelcastAutoConfiguration.class,
HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
// CacheManager类存在才加载,Spring核心包是包含的
@ConditionalOnClass(CacheManager.class)
// CacheAspectSupport类型的组件存在才加载,没配置则下面都不生效了
@ConditionalOnBean(CacheAspectSupport.class)
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class)
@Import({ CacheConfigurationImportSelector.class, CacheManagerEntityManagerFactoryDependsOnPostProcessor.class })
public class CacheAutoConfiguration {
}

例3.DispatcherServletAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 配置类的配置顺序,指定优先级
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
// 在ServletWebServerFactoryAutoConfiguration(web服务器)之后生效
@AutoConfiguration(after = ServletWebServerFactoryAutoConfiguration.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
// SpringMVC中肯定有,这里配置生效了
@ConditionalOnClass(DispatcherServlet.class)
public class DispatcherServletAutoConfiguration {

...

@Configuration(proxyBeanMethods = false)
@Conditional(DefaultDispatcherServletCondition.class)
// 导入Tomcat组件就有,此处生效
@ConditionalOnClass(ServletRegistration.class)
// 开启WebMvcProperties类的配置绑定,加入容器中
@EnableConfigurationProperties(WebMvcProperties.class)
protected static class DispatcherServletConfiguration {

// 帮我们配置DispatcherServlet
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
return dispatcherServlet;
}

// 帮我们配置文件上传解析器
// 条件是:有这个类型的Bean,但是名字不叫multipartResolver(以免用户把变量名写错了)
@Bean
@ConditionalOnBean(MultipartResolver.class)
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
// @Bean传入对象参数,从容器中找
public MultipartResolver multipartResolver(MultipartResolver resolver) {
return resolver;
}

}

...

}

例4.HttpEncodingAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@AutoConfiguration
@EnableConfigurationProperties(ServerProperties.class)
// 判断是不是Web应用
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
// 判断容器中有没有CharacterEncodingFilter(导了SpringMVC肯定有)
@ConditionalOnClass(CharacterEncodingFilter.class)
// server.servlet.encoding = enabled
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

private final Encoding properties;

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

// CharacterEncodingFilter
// 用户没配就帮我们配
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
return filter;
}

...

}

总结

  1. SpringBoot加载所有自动配置类
  2. 每个自动配置类按照条件生效
    • 很多配置类开启了配置绑定(@EnableConfigurationProperties
    • 可以看看HttpEncodingAutoConfiguration中的this.properties->ServerProperties
    • 可以自己在application.properties中更改
  3. 生效的配置类,会给容器中装配很多组件
    • 若用户自己配置组件,以用户的优先(@ConditionalOnMissingBean

最佳实践

SpringBoot应用开发

  1. 引入场景依赖
  2. 查看自动配置了哪些(选做)
    • 自己分析,引入场景对应的自动配置一般生效
    • application.properties中写debug=true,开启自动配置报告,来查看
  3. 是否需要修改

Lombok

  • 添加依赖(版本号自动仲裁)
1
2
3
4
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
  • idea安装lombok插件(现版本默认安装)
  • 直接使用
1
2
3
4
5
6
7
8
9
@Data 					// getter, setter, toString
@ToString // toString
@NoArgsConstructor // 无参构造器
@AllArgsConstructor // 有参构造器
@EqualsAndHashCode // equals, hashCode
public class Car {
private String name;
private Double price;
}

dev-tools

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
  • Ctrl+F9(自动重启)
  • 真正热更新需要付费

Spring Initalizr

  • Developer Tools
    • Spring Boot DevTools
    • Lombok
  • Web
    • Spring Web
  • SQL
    • MyBatis Framework
    • MySQL Driver
  • NoSQL
    • Spring Data Redis (Access+Driver)
  • 标题: SpringBoot-基础入门
  • 作者: 布鸽不鸽
  • 创建于 : 2024-04-10 20:34:10
  • 更新于 : 2024-10-25 16:45:16
  • 链接: https://xuedongyun.cn//post/36288/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论