目录
Spring Boot Starter是什么?如何自定义Spring Boot Starter
spring boot 核心配置文件是什么?bootstrap.properties 和 application.properties 有何区别 ?
spring-boot-starter-parent 有什么用 ?
Spring Boot 打成的 jar 和普通的 jar 有什么区别 ?
什么是 Spring Boot?
Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要是简化了使用 Spring 的难度,简化了繁重的配置,提供了各种启动器,开发者能快速上手。
Spring Boot 有哪些优点?
Spring Boot 主要有如下优点:
-
容易上手,提升开发效率,为 Spring 开发提供一个更快、更广泛的入门体验。
-
开箱即用,远离繁琐的配置。
-
没有代码生成,也不需要XML配置。
-
提供了一系列大型项目通用的非业务性功能,例如:内嵌服务器、安全管理、运行数据监控、运行状况检查和外部化配置等。
-
避免大量的 Maven 导入和各种版本冲突。
Spring Boot的启动流程
Spring Boot 入口——main方法
@SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
从上面代码可以看出,Annotation定义(@SpringBootApplication)和类定义(SpringApplication.run)最为耀眼,所以分析 Spring Boot 启动过程,我们就从这两方面开始。
从源码声明可以看出,@SpringBootApplication相当于 @SpringBootConfiguration + @ComponentScan + @EnableAutoConfiguration ,因此我们直接拆开来分析。
上面三个注解都在做一件事:注册bean到spring容器。他们通过不同的条件不同的方式来完成:
-
@SpringBootConfiguration 通过与 @Bean 结合完成Bean的 JavaConfig 配置;
-
@ComponentScan 通过范围扫描的方式,扫描特定注解注释的类,将其注册到Spring容器;
-
@EnableAutoConfiguration 通过 spring.factories 的配置,并结合 @Condition 条件,完成bean的注册;
除了上面的三个注解,还可以使用@Import注解将bean注册到Spring容器
-
@Import 通过导入的方式,将指定的class注册解析到Spring容器;
Spring Boot 启动流程
SpringApplication的实例化
-
推断应用类型是否是Web环境
-
设置初始化器(Initializer)
-
设置监听器(Listener)
-
推断应用入口类(Main)
SpringApplication.run方法
-
获取SpringApplicationRunListeners
-
准备配置环境ConfigurableEnvironment
-
创建ApplicationContext应用上下文
-
ApplicationContext前置处理
-
ApplicationContext刷新
-
ApplicationContext后置处理
完成了实例化,下面开始调用run方法
// 运行run方法
public ConfigurableApplicationContext run(String... args) {
// 此类通常用于监控开发过程中的性能,而不是生产应用程序的一部分。
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 设置java.awt.headless系统属性,默认为true
// Headless模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标。
configureHeadlessProperty();
// KEY 1 - 获取SpringApplicationRunListeners
SpringApplicationRunListeners listeners = getRunListeners(args);
// 通知监听者,开始启动
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// KEY 2 - 根据SpringApplicationRunListeners以及参数来准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
// 准备Banner打印器 - 就是启动Spring Boot的时候打印在console上的ASCII艺术字体
Banner printedBanner = printBanner(environment);
// KEY 3 - 创建Spring上下文
context = createApplicationContext();
// 注册异常分析器
analyzers = new FailureAnalyzers(context);
// KEY 4 - Spring上下文前置处理
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// KEY 5 - Spring上下文刷新
refreshContext(context);
// KEY 6 - Spring上下文后置处理
afterRefresh(context, applicationArguments);
// 发出结束执行的事件
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, exceptionReporters, ex);
throw new IllegalStateException(ex);
}
}
Spring Boot Starter是什么?如何自定义Spring Boot Starter
Spring boot之所以流行,很大原因是因为有Spring Boot Starter。Spring Boot Starter是Spring boot的核心,可以理解为一个可拔插式的插件,例如,你想使用Reids插件,那么可以导入spring-boot-starter-redis依赖
Starter的命名
官方对Starter项目的jar包定义的 artifactId 是有要求的,当然也可以不遵守。Spring官方Starter通常命名为spring-boot-starter-{name}如:spring-boot-starter-web,Spring官方建议非官方的starter命名应遵守{name}-spring-boot-starter的格式。
传统的做法
在没有starter之前,假如我想要在Spring中使用jpa,那我可能需要做以下操作:
-
在Maven中引入使用的数据库的依赖(即JDBC的jar)
-
引入jpa的依赖
-
在xxx.xml中配置一些属性信息
-
反复的调试直到可以正常运行
需要注意的是,这里操作在我们每次新建一个需要用到jpa的项目都需要重复的做一次。
使用Spring Boot Starter可以提升效率
starter的主要目的就是为了解决上面的这些问题。
使用starter的好处,starter的作用:
-
帮助用户去除了繁琐的重复性的构建操作
-
在“约定大于配置”的理念下,ConfigurationProperties还帮助用户减少了无谓的配置操作
-
因为
application.properties
文件的存在,用户可以集中管理自定义配置
创建自己的Spring Boot Starter
如果你想要自己创建一个starter,那么基本上包含以下几步
-
新建一个Maven项目,在pom.xml文件中定义好所需依赖;
-
新建配置类,写好配置项和默认值,使用
@ConfigurationProperties
指明配置项前缀; -
新建自动装配类,使用
@Configuration
和@Bean
来进行自动装配; -
新建
spring.factories
文件,用于指定自动装配类的路径; -
将starter安装到maven仓库,让其他项目能够引用
spring.factories文件位于resources/META-INF目录下,需要手动创建;org.springframework.boot.autoconfigure.EnableAutoConfiguration
后面的类名说明了自动装配类,如果有多个 ,则用逗号分开;使用者应用(SpringBoot)在启动的时候,会通过org.springframework.core.io.support.SpringFactoriesLoader
读取classpath下每个Starter的spring.factories文件,加载自动装配类进行Bean的自动装配;
什么是 JavaConfig?
Spring JavaConfig 是 Spring 社区的产品,它提供了使用注释来配置Bean的纯 Java 方法。因此它有助于避免使用 XML 配置。使用 JavaConfig 的优点在于:
(1)面向对象的配置。由于配置被定义为 JavaConfig 中的类,因此用户可以充分利用 Java 中的面向对象功能。一个配置类可以继承另一个,重写它的@Bean 方法等。
(2)减少或消除 XML 配置。基于依赖注入原则的外部配置的好处已被证明。但是,许多开发人员不希望在 XML 和 Java 之间来回切换。JavaConfig 为开发人员提供了一种纯 Java 方法来配置与 XML 配置概念相似的 Spring 容器。从技术角度来讲,只使用 JavaConfig 配置类来配置容器是可行的,但实际上很多人认为将JavaConfig 与 XML 混合匹配是理想的。
(3)类型安全和重构友好。JavaConfig 提供了一种类型安全的方法来配置 Spring容器。由于 Java 5.0 对泛型的支持,现在可以按类型而不是按名称检索 bean,不需要任何强制转换或基于字符串的查找。
spring boot 核心配置文件是什么?bootstrap.properties 和 application.properties 有何区别 ?
单纯做 Spring Boot 开发,不太容易遇到 bootstrap.properties 配置文件,但是在结合 Spring Cloud 时,这个配置就会经常遇到了,特别是在需要加载一些远程配置文件的时侯。
spring boot 核心的两个配置文件:
-
bootstrap (. yml 或者 . properties):bootstrap 由父 ApplicationContext 加载的,比 applicaton 优先加载,配置在应用程序上下文的引导阶段生效。一般来说我们在 Spring Cloud Config 或者 Nacos 中会用到它。且 bootstrap 里面的属性不能被覆盖;
-
application (. yml 或者 . properties):由ApplicatonContext 加载,用于 spring boot 项目的自动化配置。
什么是 Spring Profiles?
Spring Profiles 主要有下面两个使用场景:
-
根据不同的使用环境定义不同的profiles文件,比如开发,测试和生产,可以大大省去我们修改配置信息而带来的烦恼
-
根据不同的profiles(dev,test,prod)注册不同的bean,当应用程序在开发中运行时,只有某些 bean 可以加载,而在生产中,某些其他 bean 可以加载
spring-boot-starter-parent 有什么用 ?
我们都知道,新创建一个 Spring Boot 项目,默认都是有 parent 的,这个 parent 就是 spring-boot-starter-parent ,spring-boot-starter-parent 主要有如下作用:
-
定义了 Java 编译版本为 1.8 。
-
使用 UTF-8 格式编码。
-
继承自 spring-boot-dependencies,这个里边定义了依赖的版本,也正是因为继承了这个依赖,所以我们在写依赖时才不需要写版本号。
-
执行打包操作的配置。
-
自动化的资源过滤。
-
自动化的插件配置。
-
针对 application.properties 和 application.yml 的资源过滤,包括通过 profile 定义的不同环境的配置文件,例如 application-dev.properties 和 application-dev.yml。
Spring Boot 打成的 jar 和普通的 jar 有什么区别 ?
Spring Boot 项目最终打包成的 jar 是可执行 jar ,这种 jar 可以直接通过 java -jar xxx.jar
命令来运行,这种 jar 不可以作为普通的 jar 被其他项目依赖,即使依赖了也无法使用其中的类。
Spring Boot 的 jar 无法被其他项目依赖,主要还是他和普通 jar 的结构不同。普通的 jar 包,解压后直接就是包名,包里就是我们的代码,而 Spring Boot 打包成的可执行 jar 解压后,在 \BOOT-INF\classes
目录下才是我们的代码,因此无法被直接引用。如果非要引用,可以在 pom.xml 文件中增加配置,将 Spring Boot 项目打包成两个 jar ,一个可执行,一个可引用。
Spring Boot 中如何解决跨域问题 ?
跨域可以在前端通过 JSONP 来解决,但是 JSONP 只可以发送 GET 请求,无法发送其他类型的请求,在 RESTful 风格的应用中,就显得非常鸡肋,因此我们推荐在后端通过 (CORS,Cross-origin resource sharing) 来解决跨域问题。这种解决方案并非 Spring Boot 特有的,在传统的 SSM 框架中,就可以通过 CORS 来解决跨域问题,只不过之前我们是在 XML 文件中配置 CORS ,现在可以通过实现WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
}
使用上面的方式解决跨域会有点问题,具体描述如下
我们使用cookie存放用户登录的信息,在spring拦截器进行权限控制,当权限不符合时,直接返回给用户固定的json结果。
当用户登录以后,正常使用;当用户退出登录状态时或者token过期时,由于拦截器和跨域的顺序有问题,出现了跨域的现象。
我们知道一个http请求,先走filter,到达servlet后才进行拦截器的处理,如果我们把cors放在filter里,就可以优先于权限拦截器执行。
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}