主程序

  1. @SpringBootApplication来标注一个springboot主程序类
  2. @Configuration:标记配置类,也是一个容器(@Component)
  3. @EnableAutoConfiguration:开启自动配置功能
  4. @AutoConfigurationPackage:自动配置包
  5. @Import,spring底层组件,给容器中导入一个组件
  6. Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将
    这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作;以前我们需要自己配置的东
    西,自动配置类都帮我们;J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-1.5.9.RELEASE.jar;

yml语法

  1. 基本语法k: v --> 表示一对键值对
name: jiyu
  1. 对象/map
  1. 换行写法
person:
    name: jiyu
    age: 22
  1. 行内写法
person: {name: jiyu, age: 22}
  1. 数组(List, Set)
  1. 换行写法
animal:
    - dog
    - pig
    - flog
  1. 行内写法
animal: [dog, pig, flog]

@Value和@ConfigurationProperties的区别

 

@ConfigurationProperties

@Value

配置方式

批量指定

单个指定属性

松散绑定

支持

不支持

 

SpEL

不支持

支持

JSR303数据校验

支持

不支持

复杂类型封装

支持

不支持

  1. @value用于简单获取配置文件,@ConfigurationProperties用于复杂配置
  2. 松散绑定
  3. Springboot的mq消息重发机制_spring

  4. JSR303校验: @Validated @NotNull
  5. 复杂类型封装: map, list, set等

@PropertySource和@ImportResource和@Bean

  1. @PropertySource读取指定的配置文件(不能读取yml文件,如需要须配置)
  2. @ImportResource导入spring的xml配置文件
  3. @Bean将方法的返回值添加到容器中,在容器的id默认是方法名,配合@Configuration使用

配置文件占位符

  1. 随机数: ${random.int},${random.int(10)},${random.int[1,2,33,444]}
  2. 冒号指定默认值:${server.port:8080}

多profile文件

  1. 主配置文件写成application-{profile}.yml/properties,默认使用application.properties配置文件
  2. 使用spring.profiles.active=profile激活
  3. yml使用---作为文档块,文档块可指定profile,可在第一个文档块中指定profile
  4. 可使用--spring.profiles.active=profile命令行指定
  5. 可使用-Dspring.profiles.active=profile虚拟机参数指定

配置文件路径的优先级

  1. 优先级从高到底
  1. file:./config/application.properties
  2. file:./application.properties
  3. classpath:/config/application.properties
  4. classpath:/application.properties
  1. 这四个文件位置会形成互补配置
  2. 命令行参数使用--spring.config.location=filePath指定配置文件

外部配置文件加载顺序

  1. 优先级从高到低
  1. 命令行
  2. 来自Java:comp/env的JNDI属性
  3. Java系统属性(System.getProperties())
  4. 操作系统环境变量
  5. RandomValuePropertySource配置的random.*属性值
  6. jar包外部application-profile.yml/properties,带profile
  7. jar包内部application-profile.yml/properties,带profile
  8. jar包外部application.yml/properties,不带profile
  9. jar包内部application.yml/properties,不带profile
  10. 通过@Configuration注解类上的@PropertySource指定
  11. 通过SpringApplication.setDefaultProperties()指定默认属性

自动配置原理

  1. springboot启动的时候开启了自动配置功能@EnableAutoConfiguration
  2. @EnableAutoConfiguration的作用
  1. 使用AutoConfigurationImportSelector给容器中导入了一些组件
  2. 导入的组件由selectImports()方法决定
  1. List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);获取候选配置
  2. loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader);扫描META-INF/spring.factories文件,并封装成properties对象
  3. 从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后将其加入到容器中
  4. META-INF/spring.factories中的内容
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
  1. 每一个xxxAutoConfiguration都是容器中的一个组件,都加入到容器中用来做自动配置
  2. 以HttpEncodingAutoConfiguration为例解读自动配置
@Configuration//配置类
//启动指定类的ConfigurationProperties功能,映射HttpEncodingProperties和配置文件并加入ioc容器中
@EnableConfigurationProperties(HttpEncodingProperties.class)
//@Conditional满足条件才会生效,是否web应用
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
//是否有CharacterEncodingFilter类
@ConditionalOnClass(CharacterEncodingFilter.class)
//配置文件中是否有spring.http.encoding为enabled的配置,matchIfMissing 如果判断不存在也是成立的
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

    //此配置已和配置文件映射
    private final HttpEncodingProperties properties;

    //只有一个有参构造器,参数的值会从容器中获取
	public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
		this.properties = properties;
	}

    //给容器中添加组件,这个组件的某些值需要从properties中获取
	@Bean
	@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;
	}

}


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

}
  1. 配置文件能配置的东西参照对应功能的xxxProperties类
  1. 精髓
  1. springboot启动时会加载大量配置类
  2. 如果我们需要的功能springboot已经写好配置类,则默认,如果没有则自定义
  3. 再看自动配置类中定义了哪些组件,如果有我们需要的则不需要配置,如果没有则自定义配置
  4. springboot给容器加组件时,会从properties中读取某些,如果有需要自定义的属性,则从配置文件中自定义

@Conditional

@Conditional扩展注解

作用(判断是否满足当前指定条件)

@ConditionalOnJava

系统的java版本是否符合要求

@ConditionalOnBean

容器中存在指定Bean

@ConditionalOnMissingBean

容器中不存在指定Bean

@ConditionalOnExpression

满足SpEL表达式指定

@ConditionalOnClass

系统中有指定的类

@ConditionalOnMissingClass

系统中没有指定的类

@ConditionalOnSingleCandidate

容器中只有一个指定的Bean,或者这个Bean是首选Bean

@ConditionalOnProperty

系统中指定的属性是否有指定的值

@ConditionalOnResource

类路径下是否存在指定资源文件

@ConditionalOnWebApplication

当前是web环境

@ConditionalOnNotWebApplication

当前不是web环境

@ConditionalOnJndi

JNDI存在指定项

配置文件debug=true启动时可打印自动配置报告

面向接口编程

  1. 代码里使用接口里定义的方法
  2. 接口里定义的方法通过具体类实现(可插拔)

日志框架

  1. 日志门面(接口)
  1. slf4j(simple logging facade for Java): 流行
  2. jcl(jakarta commons logging): 停止更新
  3. jboss-jboss-loggin: 使用少
  1. 日志实现
  1. logback: log4j的升级版
  2. log4j: slf4j的实现,性能不太好
  3. log4j2: apache的,使用少
  4. jul(Java utils logging): Java原生日志
  1. slf4j的使用
  1. 兼容log4j,导入log4j-to-slf4j包
  2. 兼容其它日志,排除其它框架里的日志框架,增加替代的jar包

springboot对静态资源的映射规则

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
	public static final String DEFAULT_PREFIX = "";
	public static final String DEFAULT_SUFFIX = "";
	private static final String[] SERVLET_LOCATIONS = { "/" };

        @Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {

        }
}
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {
    //设置映射规则,缓存时间等
	private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
			"classpath:/META-INF/resources/", "classpath:/resources/",
			"classpath:/static/", "classpath:/public/" };

}
  1. /webjars/**会到classpath:/META-INF/resources/webjars/寻找资源
  2. /**没有匹配的情况会到一下路径寻找资源(静态资源文件夹)
"classpath:/META-INF/resources/", 
"classpath:/resources/",
"classpath:/static/", 
"classpath:/public/",
"/"
  1. 欢迎页,静态资源文件夹下的所有index.html页面
  2. 图标,**/favicon.ico都在静态资源文件夹下查找

springboot thymeleaf模板引擎

  1. 引入starter
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
  1. 导入名称空间(非必须):<html lang="en" xmlns:th="http://www.thymeleaf.org">
  2. 语法
  1. th:html属性: 改变html的属性
  2. 基础标签

 

标签

功能

类比jsp标签

1

th:insert

插入子片段

jsp:include

2

th:replace

替换当前节点片段

jsp:include

3

th:each

遍历

c:forEach

4

th:if

条件判断

c:if

5

th:unless

条件判断

c:if

6

th:switch

条件判断

c:when

7

th:case

条件判断

c:choose

8

th:object

申明变量

c:set

9

th:with

申明变量

c:set

10

th:attr

属性修改

 

11

th:attrprepend

任意属性修改

 

12

th:attrappend

任意属性修改

 

13

th:value

修改value属性

 

14

th:href

修改href属性

 

15

th:src

修改src属性

 

16

th:text

修改text属性(不转意),行内写法[[...]]

 

17

th:utext

修改text属性(转义)行内写法[(...)]

 

18

th:fragment

申明片段

 

19

th:remove

移除片段

 

  1. 表达式
  1. ${...}获取变量值,底层是ognl表达式
  1. 获取对象的属性,调用方法
  2. 可使用字面变量,文本操作,数学运算,逻辑判断,条件运算
  3. 内置基本对象
  1. #ctx
  2. #vars
  3. #locale
  4. #request
  5. #response
  6. #session
  7. #servletContext
  8. param
  9. session
  10. application
  11. -代表无操作
  1. 内置工具对象
  1. #number
  2. #string
  1. *{...}和${..}功能一样,可配合th:object提出共有部分
  2. #{...}获取国际化内容
  3. @{...}定义url链接
  1. <a class="form-signin" th:action="@{localhost:8080/version/login/login}">
  2. <a class="form-signin" th:action="@{/login/login(user=${user}, pass=${pass})}">
  1. ~{...}片段引用表达式:<div th:insert=~{commons :: main}>...</div>

springmvc auto-configuration

  1. ContentNegotiatingViewResolver和BeanNameViewResolver
  1. 自动配置了ViewResolver(视图解析器),视图解析对象决定如何渲染(重定向还是转发)
  2. ContentNegotiatingViewResolver组合所有的视图解析器
  3. 定制视图解析器: 给容器中添加一个自定义的ViewResolver(视图解析器),自定义的ViewResolver实现ViewResolver接口
  1. webjars
  2. 静态首页index.html访问
  3. favicon.ico
  4. 自动注册了Converter,GenericConverter,Formatter组件
  1. Converter:转换器,view和controller类型转换时使用
  2. Formatter:格式化器,转换日期格式时使用,生效条件
  3. 添加格式化器,转换器的方法,如果自定义,则需要往容器里添加Converter的实现
@Override
public void addFormatters(FormatterRegistry registry) {
	for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
		registry.addConverter(converter);
	}
	for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
		registry.addConverter(converter);
	}
	for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
		registry.addFormatter(formatter);
	}
}
  1. HttpMessageConverter
  1. springmvc用来转换http请求和响应的
  1. @ResponseBody时Object-->Json
  2. @RequestBody时json-->Object
  1. 自定义HttpMessageConverter转换器:@Bean或@Component加入HttpMessageConverters到容器中
  1. MessageCodesResolver:定义错误代码生成规则的(jsr303校验)
  2. ConfigurableWebBindingInitializer:初始化WebDataBinder组件
  1. 自定义:往容器中加入一个ConfigurableWebBindingInitializer组件
  2. WebDataBinder的作用:请求数据-->JavaBean

修改springboot的默认的自动配置

  1. springboot在自动配置时,会先查看容器中是否有用户自定义的配置(@Bean或@Component注入),如果有则使用用户自定义的,如果没有则使用默认配置的;如果该组件是一个列表(ViewResolver),则将用户定义的和默认的组合起来
  2. springboot中会有很多xxxConfigurer帮助我们扩展自动配置

扩展springmvc

  1. 编写一个WebMvcConfigurer或WebMvcConfigurerAdapter类型的配置类(@Configuration),并且不能标注@EnableWebMvc
  2. 原理
  1. WebMvcAutoConfiguration是springmvc的自动配置类
  2. 在做其它配置时,会导入@Import(EnableWebMvcConfiguration.class)
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {


}

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
	private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

	//@Autowired标注会从容器中获取参数的值
	@Autowired(required = false)
	public void setConfigurers(List<WebMvcConfigurer> configurers) {
		if (!CollectionUtils.isEmpty(configurers)) {
				this.configurers.addWebMvcConfigurers(configurers);
			
        //将WebMvcConfiguration相关配置一起调用
				//public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
				//	if (!CollectionUtils.isEmpty(configurers)) {
				//		this.delegates.addAll(configurers);
				//	}
				//}
		}
	}
}
  1. 所有的WebMvcConfiguration一起起作用
  2. 我们的配置类也会起作用
  3. 配置添加@EnableWebMvc会全面接管springmvc,springmvc的自动配置全部失效(最好不要用),原理如下
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
}
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class,ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
}
  1. @EnableWebMvc将WebMvcConfigurationSupport导入进来,只具有springmvc的基础功能

国际化

  1. 编辑国际化配置文件
  2. 使用ResourceBundleMessageSource管理国际化资源文件
  1. springboot自动配置
@Configuration
@ConditionalOnMissingBean(value = MessageSource.class, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Conditional(ResourceBundleCondition.class)
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
    	@Bean
	public MessageSource messageSource() {
		MessageSourceProperties properties = messageSourceProperties();
		ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
		if (StringUtils.hasText(properties.getBasename())) {
            //设置基础名(去掉国家代码)
			messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
					StringUtils.trimAllWhitespace(properties.getBasename())));
		}
		if (properties.getEncoding() != null) {
			messageSource.setDefaultEncoding(properties.getEncoding().name());
		}
		messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
		Duration cacheDuration = properties.getCacheDuration();
		if (cacheDuration != null) {
			messageSource.setCacheMillis(cacheDuration.toMillis());
		}
		messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
		messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
		return messageSource;
	}
}
  1. 在页面使用fmt:message取出国际化内容
  1. 使用#{common.loginUser}获取
  2. 根据用户选择获取,使用LocalResolver设置,默认根据请求头信息里的语言设置
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
		@Bean
		@ConditionalOnMissingBean
		@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
		public LocaleResolver localeResolver() {
			if (this.mvcProperties
					.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
				return new FixedLocaleResolver(this.mvcProperties.getLocale());
			}
			AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
			localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
			return localeResolver;
		}
}

restfulCRUD

  1. URL格式: /资源名称/资源标识    HTTP请求方式区分对资源的crud操作
  2. 请求方式

查询

GET

增加

POST

修改

PUT

删除

DELETE

thymeleaf布局

  1. 抽取公共片段
  2. 引入片段
  1. ~{模板名::选择器名(变量1,变量2...)}
  2. ~{模板名::片段名(变量1=值1,变量2=值2)}
  3. 模板名遵循thymeleaf规则
  4. th:insert是在当前节点下插入一个子节点,子节点的内容就是该片段
  5. th:replace是用该片段的内容替换当前节点的内容
  6. th:include是将该片段的内容包含到当前节点中(不包含片段的最外层标签)
  7. th:insert可使用[[~{...}]]和[(...)]行内写法

springboot发送其它请求方式

  1. springmvc中配置HiddenHttpMethodFilter,已自动配置好
  2. form表单使用post方式
  3. 创建一个input项,name为_method,value为put,不区分大小写

错误处理机制

  1. 浏览器默认返回一个错误页面
  2. 其它客户端默认返回json数据
  3. 原理
  1. ErrorMvcAutoConfiguration配置
public class DefaultErrorAttributes implements ErrorAttributes {
	@Override
	public Map<String, Object> getErrorAttributes(ServerRequest request,
			boolean includeStackTrace) {
		Map<String, Object> errorAttributes = new LinkedHashMap<>();
		errorAttributes.put("timestamp", new Date());
		errorAttributes.put("path", request.path());
		Throwable error = getError(request);
		HttpStatus errorStatus = determineHttpStatus(error);
		errorAttributes.put("status", errorStatus.value());
		errorAttributes.put("error", errorStatus.getReasonPhrase());
		errorAttributes.put("message", determineMessage(error));
		handleException(errorAttributes, determineException(error), includeStackTrace);
		return errorAttributes;
	}
}
  1. 给容器中添加了以下组件
  1. DefaultErrorAttributes: 响应错误数据,json格式
  2. BasicErrorController: 处理/error请求
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
    	@RequestMapping(produces = "text/html")//html数据,响应浏览器
	public ModelAndView errorHtml(HttpServletRequest request,
			HttpServletResponse response) {
		HttpStatus status = getStatus(request);
		Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
				request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
		response.setStatus(status.value());

        //响应的页面地址
		ModelAndView modelAndView = resolveErrorView(request, response, status, model);
        	/**
                protected ModelAndView resolveErrorView(HttpServletRequest request,
			HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
		    for (ErrorViewResolver resolver : this.errorViewResolvers) {
			    ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
			    if (modelAndView != null) {
				    return modelAndView;
    			    }
	    	    }
		    return null;
	        }
                */

		return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
	}

	@RequestMapping
	@ResponseBody//json数据,响应其它客户端
	public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
		Map<String, Object> body = getErrorAttributes(request,
				isIncludeStackTrace(request, MediaType.ALL));
		HttpStatus status = getStatus(request);
		return new ResponseEntity<>(body, status);
	}
}
  1. ErrorPageCustomizer: 发生错误就会来到/error请求
public class ErrorProperties {

	/**
	 * Path of the error controller.
	 */
	@Value("${error.path:/error}")
	private String path = "/error";
}
  1. DefaultErrorViewResolver: 决定去哪个页面
public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
	@Override
	public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
			Map<String, Object> model) {
		ModelAndView modelAndView = resolve(String.valueOf(status), model);
		if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
			modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
		}
		return modelAndView;
	}

	private ModelAndView resolve(String viewName, Map<String, Object> model) {
        //去到/error/4xx页面
		String errorViewName = "error/" + viewName;

        //模板引擎解析
		TemplateAvailabilityProvider provider = this.templateAvailabilityProviders
				.getProvider(errorViewName, this.applicationContext);

        //解析成功
		if (provider != null) {
			return new ModelAndView(errorViewName, model);
		}

        //解析失败,就去静态资源文件夹下找errorViewName页面,error/4xx.html
		return resolveResource(errorViewName, model);
	}
}
  1. 定制错误响应
  1. 定制错误页面
  1. 有模板引擎: 去到error/状态码页面,可使用error/4xx和error/5xx表示,精确匹配优先
  2. 页面能获取到信息DefaultErrorAttributes决定
  1. timestamp: 时间戳
  2. status: 状态码
  3. error: 错误提示
  4. exception: 异常对象
  5. message: 异常信息
  6. errors: jsr303数据校验错误的信息
  1. 没有模板引擎: 在静态资源文件夹下查找
  2. 以下页面都没有,则返回springboot默认的页面
  1. 定制错误json数据
  1. 方式一: 编写一个ErrorController实现,放容器中
  2. 方式二: 自定义一个ErrorAttributes放入到容器中

配置嵌入式的servlet容器

  1. 修改容器相关的配置: server.xxx修改通用配置,servlet.tomcat.xxx修改和tomcat相关的配置
  2. 切换容器: 排除默认的tomcat,引入需要的容器
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<exclusions>
		<!--排除默认的tomcat容器-->
		<exclusion>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-tomcat</artifactId>
		</exclusion>
	</exclusions>
</dependency>


<!--性能较高,不支持jsp页面-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
  1. 容器自动配置原理
//自动配置类
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

	public static class BeanPostProcessorsRegistrar
			implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
        }

}


//根据导包选择使用的容器
@Configuration
class ServletWebServerFactoryConfiguration {
	@Configuration
	@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
	@ConditionalOnMissingBean(value = ServletWebServerFactory.class,
			search = SearchStrategy.CURRENT)
	public static class EmbeddedUndertow {

		@Bean
		public UndertowServletWebServerFactory undertowServletWebServerFactory() {
			return new UndertowServletWebServerFactory();
		}

	}
}


//undertow容器工厂
public class UndertowServletWebServerFactory extends AbstractServletWebServerFactory
		implements ConfigurableUndertowWebServerFactory, ResourceLoaderAware {
	protected UndertowServletWebServer getUndertowWebServer(Builder builder,
			DeploymentManager manager, int port) {
		return new UndertowServletWebServer(builder, manager, getContextPath(),
				isUseForwardHeaders(), port >= 0, getCompression(), getServerHeader());
	}
}


//undertow容器
public class UndertowServletWebServer implements WebServer {
	public UndertowServletWebServer(Builder builder, DeploymentManager manager,
			String contextPath, boolean useForwardHeaders, boolean autoStart,
			Compression compression, String serverHeader) {
		this.builder = builder;
		this.manager = manager;
		this.contextPath = contextPath;
		this.useForwardHeaders = useForwardHeaders;
		this.autoStart = autoStart;
		this.compression = compression;
		this.serverHeader = serverHeader;
	}

	@Override
	public void start() throws WebServerException {
		synchronized (this.monitor) {
			if (this.started) {
				return;
			}
			try {
				if (!this.autoStart) {
					return;
				}
				if (this.undertow == null) {
					this.undertow = createUndertowServer();
				}
				this.undertow.start();
				this.started = true;
				UndertowServletWebServer.logger
						.info("Undertow started on port(s) " + getPortsDescription()
								+ " with context path '" + this.contextPath + "'");
			}
			catch (Exception ex) {
				try {
					if (findBindException(ex) != null) {
						List<Port> failedPorts = getConfiguredPorts();
						List<Port> actualPorts = getActualPorts();
						failedPorts.removeAll(actualPorts);
						if (failedPorts.size() == 1) {
							throw new PortInUseException(
									failedPorts.iterator().next().getNumber());
						}
					}
					throw new WebServerException("Unable to start embedded Undertow", ex);
				}
				finally {
					stopSilently();
				}
			}
		}
	}
}
  1.  

注册三大组件

  1. servlet使用ServletRegistrationBean注册
  2. filter使用FilterRegistrationBean注册
  3. listener使用ServletListenerRegistrationBean注册
  4. 三大组件的注册方式相同
  5. springboot自动注册DispatcherServlet前端控制器
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {
	@Configuration
	@Conditional(DispatcherServletRegistrationCondition.class)
	@ConditionalOnClass(ServletRegistration.class)
	@EnableConfigurationProperties(WebMvcProperties.class)
	@Import(DispatcherServletConfiguration.class)
	protected static class DispatcherServletRegistrationConfiguration {
		@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
		@ConditionalOnBean(value = DispatcherServlet.class,
				name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
		public DispatcherServletRegistrationBean dispatcherServletRegistration(
				DispatcherServlet dispatcherServlet) {
			DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(
					dispatcherServlet, this.webMvcProperties.getServlet().getPath());

            //默认拦截所有请求(/),不包括jsp,/*包含jsp请求
			registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
			registration.setLoadOnStartup(
					this.webMvcProperties.getServlet().getLoadOnStartup());
			if (this.multipartConfig != null) {
				registration.setMultipartConfig(this.multipartConfig);
			}
			return registration;
		}
    }
}

使用外置容器

  1. 创建war项目,并使用idea生成目录结构
  2. 配置jsp模板规则
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
  1. 将嵌入式的容器指定为provider方式
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provider</scope>
</dependency>
  1. 和ServiceApplication(springboot主程序)同级必须有一个SpringBootServletInitializer类
//运行springboot主程序类
public class ServletInitializer extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(ServiceApplication.class);
    }
}

springboot运行原理

  1. jar包: 执行springboot主程序的主方法,启动ioc容器,创建嵌入式的servlet容器
  2. war包: 启动servlet容器,servlet容器启动springboot的主程序方法,启动ioc容器

整合mybatis框架

  1. 导入mybatis包
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>
  1. 写*Mapper接口,需要使用@mapper标注或主程序上使用@MapperScan("*Mapper接口所在包")
  2. 注解版: 直接在写的接口上使用@Select,@Delete,@Insert,@Update写sql语句
  3. 配置文件版: 写一个全局配置文件和sql映射文件,并在springboot配置文件中指定mybatis配置文件所在地点
  4. 注解版可通过ConfigurationCustomizer自定义mybatis配置
  5. 配置文件版直接在mybatis配置文件中自定义mybatis配置

springboot运行流程

  1. 几个重要的事件回调机制
  1. ApplicationContextInitializer,配置在类路径下的META-INF/spring.factories中
  2. SpringApplicationRunListener,配置在类路径下的META-INF/spring.factories中
  3. ApplicationRunner,加入到ioc容器中,使用@Component注解
  4. CommandLineRunner,加入到ioc容器中,使用@Component注解
  1. 创建SpringApplication对象
public class SpringApplication {
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");

            //保存主配置类
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));

            判断是否web应用
		this.webApplicationType = WebApplicationType.deduceFromClasspath();

            //从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然后保存起来
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));

            //从类路径下找到META-INF/spring.factories配置的所有ApplicationListener,然后保存起来
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		//找到主配置类
                this.mainApplicationClass = deduceMainApplicationClass();
	}
}
  1. 运行run方法
public class SpringApplication {
	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
	
	  //获取SpringApplicationRunListeners,从类路径下找到META-INF/spring.factories获取
		SpringApplicationRunListeners listeners = getRunListeners(args);
	
	  //回调SpringApplicationRunListener.starting()方法
		listeners.starting();
		try {	
	    //封装命令行参数
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			
			/**
			 *准备环境
			 *创建环境,完成后回调SpringApplicationRunListener.environmentPrepared()方法,环境准备完成
			 */
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			
			//打印banner图形
			Banner printedBanner = printBanner(environment);
			
			//创建ioc容器
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
					
			/**
			 *准备上下文环境
			 *将environment保存到ioc中
			 *通过applyInitializers(context)回调所有的ApplicationContextInitializer.initialize()方法
			 *通过listeners.contextPrepared(context);回调SpringApplicationRunListener.contextPrepared(context)方法
			 *最后回调SpringApplicationRunListener.contextLoaded(context)方法
			 */
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			
			//刷新容器,ioc容器初始化
			refreshContext(context);
			
			//从ioc容器中依次获取ApplicationRunner和CommandLineRunner回调
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			
			//回调所有SpringApplicationRunListener.started(context)方法
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}
	
		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		
		//启动完成,返回ioc容器
		return context;
	}
}

自定义starter启动器

  1. 编写自动配置
@Configuration //指定该类是一个配置类
@ConditionalOnWebApplication(type = Type.SERVLET) //判断web应用
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) //有Servlet类
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class) //没有WebMvcConfigurationSupport类
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) //指定顺序
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class,ValidationAutoConfiguration.class }) //指定顺序
public class WebMvcAutoConfiguration {
	@Configuration
	@Import(EnableWebMvcConfiguration.class)
        //让xxxProperties生效并加入到容器中
	@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
	@Order(0)
	public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware {
        }
}


@ConfigurationProperties(prefix = "spring.mvc") //结合xxxProperties绑定相关配置
public class WebMvcProperties {

}

//自定配置类需要放在类路径下的META-INF/spring.factories中才能自动加载
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
  1. 模式
  1. 启动器starter是一个空的jar文件,紧提供辅助性的依赖管理
  2. 名称约定
  1. 启动器
  1. 官方: spring-boot-starter-web
  2. 自定义: mybatis-spring-boot-starter
  1. 自动配置: xxx-autoconfigurer
  1. 步骤
  1. 编写一个[模块名-spring-boot-starter]模块,引用[模块名-spring-boot-starter-autoconfigurer]模块
  2. 编写一个[模块名-spring-boot-starter-autoconfigurer]模块
  1. 编写xxxService处理业务逻辑
public class HelloService {

    HelloProperties helloProperties;

    public String sayHello(String name){
        return helloProperties.getPrefix() + "==>" + name + "<==" + helloProperties.getSuffix();
    }

    public HelloProperties getHelloProperties() {
        return helloProperties;
    }

    public void setHelloProperties(HelloProperties helloProperties) {
        this.helloProperties = helloProperties;
    }

}
  1. 编写xxxServiceAutoConfiguration
@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {

    @Autowired
    HelloProperties helloProperties;

    @Bean
    public HelloService helloService(){
        HelloService helloService = new HelloService();
        helloService.setHelloProperties(helloProperties);
        return helloService;
    }

}
  1. 编写xxxServiceProperties绑定配置文件
@ConfigurationProperties(prefix = "jiyu.hello")
public class HelloProperties {

    private String prefix = "";
    private String suffix = "";

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public String getSuffix() {
        return suffix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
}
  1. 在类路径下的META-INF/spring.factories加入HelloServiceAutoConfiguration类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.version.starter.HelloServiceAutoConfiguration
  1. 在需要使用地点引用该starter即可使用