1. SpringBoot原理分析
1.1 SpringBoot依赖原理
传统的Spring框架要开发一个Web服务,需要导入各种依赖JAR包,而SpringBoot只需要导入相应的起步依赖即可。
SpringBoot的pom文件有个核心依赖:
- spring-boot-starter-parent
spring-boot-starter-parent底层有一个父依赖spring-boot-dependencies
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
继续啊查看spring-boot-dependencies源码文件,可以看出该文件通过
<properties>
<activemq.version>5.15.9</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<appengine-sdk.version>1.9.75</appengine-sdk.version>
<artemis.version>2.6.4</artemis.version>
<aspectj.version>1.9.4</aspectj.version>
<assertj.version>3.11.1</assertj.version>
<atomikos.version>4.0.6</atomikos.version>
<bitronix.version>2.1.4</bitronix.version>
<build-helper-maven-plugin.version>3.0.0</build-helper-maven-plugin.version>
<byte-buddy.version>1.9.13</byte-buddy.version>
<caffeine.version>2.6.2</caffeine.version>
<cassandra-driver.version>3.6.0</cassandra-driver.version>
<classmate.version>1.4.0</classmate.version>
1.2 SpringBoot自动配置原理
传统的Spring需要由大量的xml配置,其中还需要指定我们扫描的Bean所在的包。
SpringBoot并没有配置扫描Bean的包也能自动扫描到那些使用注解的类,这是怎么回事?
我们知道SpringBoot的入口是他的启动类,我们来看看@SpringBootApplication的内部源码怎么回事吧。
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
// 从上述源码可以看出,@SpringBootApplication注解是一个组合注解,包含@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan 3个核心注解。
1.2.1 @SpringBootConfiguration介绍
该注解其实就是Spring里面的@Configuration,标识当前类为一个配置类。只不过被SpringBoot重新封装换成了SpringBootConfiguration这个名称而已。
// @SpringBootConfiguration源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
1.2.2 @EnableAutoConfiguration介绍
该注解表示开启自动配置功能
// @EnableAutoConfiguration源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // 自动配置包
@Import({AutoConfigurationImportSelector.class}) // 自动配置类扫描导入
public @interface EnableAutoConfiguration {
// 从源码中可以看出该注解也是一个核心注解,包含 @AutoConfigurationPackage ,@Import 2个核心注解
@AutoConfigurationPackage介绍:
// @AutoConfigurationPackage源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class}) // 导入Registrar中注册的组件
public @interface AutoConfigurationPackage {
// @Import注解:用于导入另一个配置类。
// 从源码可以看出它通过@Import注解导入了Registrar类。
Registrar类介绍
// Registrar类源码
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]) );
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
}
}
// 从源码中可以看出Registrar类中,有个registerBeanDefinitions()方法,通过debug看出它是去 获取项目主启动类所在根目录。
// ======================总的来说:@AutoConfigurationPackage 就是用于获取项目主启动类所在的根目录,从而指定后续组件扫描器要扫描的包位置。===========================
// ======================因此:我们在开发的时候,需要将需要被扫描的Bean放在主启动类所在同级目录或子目录下=========================
// ======================注意:如果我们实在不想放在主启动类所在同级目录或子目录下,我们可以通过 @ComponentScan注解,将其放在主启动类上。指定我们要被扫描的Bean所在的位置。 =========================
1.2.3 @Import介绍
可以看出@Import导入了一个类AutoConfigurationImportSelector。
// AutoConfigurationImportSelector源码
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
...
// getAutoConfigurationEntry() 是用于筛选出当前项目环境需要启动的自动配置类,从而实现当前项目运行所需的自动配置环境。
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// 该方法主要是从 Spring Boot 提供的自动配置依赖 META-INF/spring.factories文件中获取所有候选自动配置类 XxxAutoConfiguration 【有100多个】
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
// 该方法时对所有候选自动配置类进行赛选,根据项目的pom文件中加入的依赖文件筛选出最终符合当前项目运行环境对应的自动配置类。 【最终根据你的pom筛选后可能就只有几十个】
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
}
// getAutoConfigurationEntry() 是用于筛选出当前项目环境需要启动的自动配置类,从而实现当前项目运行所需的自动配置环境。
1.2.4 @ComponentScan介绍
该注解是一个组件包扫描器,用于将指定包中的注解类自动装配到Spring的Bean容器中。
2. SpringBoot配置文件介绍与配置文件属性值的注入
SpringBoot的全局配置文件是用于对一些默认配置进行修改。因为SpringBoot是基于"约定优于配置的思想"实现的,对于一些常用配置都有默认配置。比如端口号,默认就是8080.
关于全局配置文件的存放:
- src/main/resource目录
- 类路径的/config目录
关于全局配置命名的格式:
- application.yml
- application.yaml
- application.properties
注意:3种命名格式加载的先后顺序 yml->yaml->properties,若同时配置,后加载的如果与先加载的内容有冲突,则先加载的会被覆盖。如:application.yml里面指定了端口号为80,然后又创建了application.properties,并指定端口号为81。则项目启动的端口号为81。
关于全局配置文件属性值的注入:
@Value注解:由Spring提供,用于读取配置文件中的属性值。
使用要求:
- 需要使用该注解的类必须加入IOC容器
- 不支持复杂类型的注入【如:list】
@ConfigurationProperties注解:由Spring Boot提供,用于读取配置文件中的属性值【可批量,可覆去复杂类型】。
使用要求:
- 需提供setter方法
如何加载XML配置文件:
如果你有XML配置文件你想加载它,可以使用@ImportResource注解加载启动类上,指定xml配置文件的位置。
@SpringBootApplication
@ImportResource("classpath:beans.xml")
public class ApplicationApplication {
3. SpringBoot编写自定义配置类
SpringBoot采用"约定大于配置"的思想,推荐使用配置类的方式代替传统Spring的xml配置。
使用@Configuration注解,用于指定当前类为一个配置类。【相当于声明了一个XML配置文件】。
在配置类中,使用@Bean注解作用于方法上,用于将方法的返回对象作为Bean注入Spring容器。方法的方法名就是组件名【相当于XML配置中的
4. SpringBoot多环境配置
因为SpringBoot支持3种配置文件类型,其中可以将yml与yaml的语法是一样的,而properties与他们的语法差别很大。
针对这上述2种语法的不同,所以多环节的配置也有所不同。
介绍基于yml语法的多环境配置:
spring:
profiles:
active: prd # 指定使用哪套配置环境
---
#开发环境配置-------------------------
server:
port: 8081
spring:
profiles: dev
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/kyx?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
#------------------
---
#测试环境配置
server:
port: 8082
spring:
profiles: test
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/kyx?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
#------------------
5. SpringBoot与SpringMVC的整合
其实SpringBoot在你导入web场景依赖的时候,默认就帮我们对SpringMVC进行了整合。几乎可以在无任何SpringMVC额外配置的情况下进行Web开发。比如:SpringBoot的就默认采用了Thymeleaf作为我们的视图模板引擎。
如果我们要对SpringMVC修改它的默认配置,怎么做:编写自定义配置类,实现WebMvcConfigurer接口,根据你的需求,重写相关方法即可。
比如:指定视图管理,重写addViewControllers()方法
比如:指定拦截器,重写addInterceptors()方法
6. SpringBoot整合三大组件
百度吧
7. SpringBoot打包和部署
SpringBoot默认是以Jar包形式进行打包部署的。当然你也可以打包成War包。
7.1 SpringBoot打包成Jar包
- 添加Maven打包插件
- 打包
- 部署
java -jar 打包后的文件
7.1 SpringBoot打包成War包
百度