一、概念简介

SpringBoot 的关键词是“约定俗成”,它根据长久以来的 Spring 开发配置经验,整理出一套适用、普遍、大家都认可的配置方案。所以 SpringBoot 的学习过程中心态一定要放宽,没必要太去钻牛角尖,重点是配置和自定义...

Spring Boot 简化了基于Spring的应用开发,为Spring平台及第三方库提供了开箱即用的设置,你只需要“run”就能创建一个独立的,产品级的 Spring 应用。

SpringBoot 的 Startsers 是以一个依赖描述符的集合,包含了很多搭建,快速运行项目所需要的依赖,并提供一致的,可管理传递性的依赖集。你可以获取所有 Spring 及相关技术的一站式服务,而不需要翻阅示例代码,拷贝粘贴大量的依赖描述符。所有官方的 starters 遵循相似的命名模式:spring-boot-starter-* 。

SpringBoot 的 Auto-configuration 设计成可以跟 Starters 一起很好的使用,AutoConfiguration 会根据你所依赖的 jar 包,会尽最大努力去自动配置你的应用。

Spring Boot 每次发布都关联一个 Spring 框架的基础版本,所以强烈建议你不要自己指定Spring版本。

二、spring-boot-devtools 开发者工具

spring-boot-devtools 是 SpringBoot 中内置的一个开发者工具 ,用于自重启,功能当然没有 Jrebel 那么强大,但正常的开发也差不多够用了。spring-boot-devtools 默认检测 classpath 路径下的文件,只要目录下的文件有变动,它就会自动重启。

自动重启跟 LiveReload 可以一起很好的工作。

如果你使用 JRebel,自动重启将禁用以支持动态类加载。

1、Maven 依赖

        <!--
1、在运行一个完整的,打包过的应用时(Java -jar),会禁用开发者工具。
2、防止 devtools 传递到项目中的其他模块,需要设置依赖级别 optional
3、只要 classpath 下的文件有变动(Eclipse 中文件保存就能重启,IDEA 中需要 Build ——> Build Project),系统就会自动重启。
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>

2、application.yml 配置

spring:
devtools:
restart:
# devtools 排除不需要检测的资源 和 增加额外需要监测的资源
exclude: application.yml
additional-paths: src/main/webapp
# 是否重启,如果设置为false禁用,依旧会初始化重启类加载器,但它不会监控文件变化
enabled: true
# 触发器文件,只有在修改该文件的时候,才能触发工程重启
#trigger-file: trigger-file
livereload:
# 内嵌的 LiveReload 服务器,可以在资源改变时,触发浏览器更新,禁用设置为false
enabled: true

3、spring-boot-devtools 和 LiveReload 搭配使用

LiveReload 是一个 spring-boot-devtools 模块中的内嵌服务器,它可以在资源改变时触发浏览器更新,LiveReload 浏览器扩展的谷歌插件下载地址:https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei ,如果不想使用该功能的话,可以在 application.yml 中禁用,如上。这工具还是很值得推荐的,可以大大的节约开发时间。

三、SpringApplication

SpringApplication 姑且称它为 SpringBoot 的引导类吧!它将为我们创建正确类型的 Spring 上下文 ApplicationContext 。默认情况下,SpringApplication 根据我们开发的是否为web应用(可以手动指定是否为 Web 应用)决定使用 AnnotationConfigApplicationContext 或 AnnotationConfigEmbeddedWebApplicationContext。除此之外,SpringApplication 还有一些无关痛痒的设置,比如:是否打印 Banner 这些的。

常常需要在 SpringApplication 加载前或者退出后做一些相关的操作,比如初始化一些信息,关闭一些流、文件 什么的。怎么实现呢?

实现 CommandLineRunner 或者 ApplicationRunner 接口可以在 SpringApplication 启动后,run() 方法运行前执行一些特殊的代码。
    实现 ExitCodeGenerator 接口可以在 Application 退出后返回特殊的特征码,用于 SpringApplication.exit() 时使用。
    实现 DisposableBean 接口,用于在 SpringApplication 退出后(SpringApplication.exit())实现自己的一些逻辑,或者使用 @PreDestroy 注解。

@Component
public class ApplicationArgumentsBean implements CommandLineRunner, ApplicationRunner, ExitCodeGenerator, DisposableBean { private static final Logger logger = LoggerFactory.getLogger(ApplicationArgumentsBean.class); /**
* 如果运行的时候使用 java -jar *.jar --debug logfile.txt
* 则:debug = true,files=["logfile.txt"]
*
* @param args
*/
@Autowired
public ApplicationArgumentsBean(ApplicationArguments args) {
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
} @Override
public void run(ApplicationArguments args) throws Exception {
logger.info("重写 ApplicationRunner 的 run 方法:{}", args.containsOption("debug"));
} @Override
public void run(String... args) throws Exception {
logger.info("重写 CommandLineRunner 的 run 方法:{}", args);
} @Override
public int getExitCode() {
return 0;
} @Override
public void destroy() throws Exception {
logger.info("重写 DisposableBean 的 destroy 方法,用于在 SpringApplication 退出后执行一些操作");
} @PreDestroy
public void predestroy() {
logger.info("使用 @PreDestroy 用于在 SpringApplication 退出后执行一些操作");
}
}

ApplicationArgumentsBean.java

@EnableAutoConfiguration
@Configuration
@ComponentScan
public class Example { public static void main(String[] args) {
// 我们需要将Example.class作为参数传递给run方法,以此告诉SpringApplication谁是主要的Spring组件
SpringApplication app = new SpringApplication(Example.class);
// 手动调用setWebApplicationType() 指定为 web 应用
app.setWebApplicationType(WebApplicationType.SERVLET);
// 设置打印 Banner 的方式
app.setBannerMode(Banner.Mode.LOG);
// 是否将启动时的命令行属性添加到 Environment
app.setAddCommandLineProperties(true);
ConfigurableApplicationContext run = app.run(args);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
SpringApplication.exit(run, (ExitCodeGenerator) run.getBean("applicationArgumentsBean"));
}
});
}
}

tips:建议将应用的main类放在其他类所在包的顶层(root package)。

四、引入外部配置文件

SpringBoot 的默认配置文件是 application.yml 或者 application.properties,如果想要引入其他的 properties 文件 或者 yml 文件,该怎么操作呢?

1、properties 文件

properties 文件引入较为简单,跟 Spring 一样。在配置类上使用 @PropertySource 注解引入,在其他地方使用 @Value 注解读取。

2、yml 文件

我们先从 SpringBoot 的默认配置文件 application.yml 文件聊起,application.yml 的文件内容,是可以通过 @Value 的方式读取到的,比如 @Value("${server.port}") 这样。究其原因的话,应该是 SpringBoot 底层把 ApplicationContext 注册进 PropertySourcesPlaceholderConfigurer 导致的吧!

那么我们自定义的 yml 文件要怎么引入呢?看了网上的一些教程,很多人推荐用如下这种方式:

    @Bean
public PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("my.yml"));
configurer.setProperties(yaml.getObject());
return configurer;
}

这种方式,确实可以用,通过这种方式把 yml 文件加载到 PropertySourcesPlaceholderConfigurer 后,通过 @Value 方式读取到属性值。但是!但是!原来的 application.yml 中的 @Value 属性全获取不到了,我猜想是不是 Bean 覆盖导致的,我试着手动把 application.yml 和 my.yml 都加载进 PropertySourcesPlaceholderConfigurer ,以及使用 @Primary 注解,结果都不管用!所以就放弃了这种做法。

那要怎么加载我们自定义的 yml 文件呢 ?通过 YamlPropertiesFactoryBean 或者 YamlMapFactoryBean 类:

    @Test
public void test3() {
YamlPropertiesFactoryBean yml = new YamlPropertiesFactoryBean();
yml.setResources(new ClassPathResource("my.yml"));
Properties properties = yml.getObject();
Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Object, Object> entry = iterator.next();
logger.info("YamlPropertiesFactoryBean 读取的配置文件内容是:{}-{}", entry.getKey(), entry.getValue());
} logger.info("--------华丽的分割线------------"); YamlMapFactoryBean yamlMapFactoryBean = new YamlMapFactoryBean();
yamlMapFactoryBean.setResources(new ClassPathResource("my.yml"));
Map<String, Object> map = yamlMapFactoryBean.getObject();
Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Object> entry = it.next();
logger.info("YamlPropertiesFactoryBean 读取的配置文件内容是:{}-{}", entry.getKey(), entry.getValue());
}
}

另外需要提及的是 SpringBoot 还提供了 @ConfigurationProperties(prefix = "spring.datasource") 注解,将 yml 文件中的属性直接转换成 Bean 中的属性(前提是有 set 方法),而且属性的匹配很宽松,采用 Relaxed 绑定,以 firstName 举例(可匹配firstName、first-name、first_name、FIRST_NAME)。之后再在启动类中使用 @EnableConfigurationProperties(JavaConfig.class) 使之生效。

五、单元测试

不同于 Spring 中的单元测试 —— 采用 @RunWith(SpringJUnit4ClassRunner.class) 和 @ContextConfiguration(locations = "classpath:applicationContext.xml"),SpringBoot 中使用 @RunWith(SpringRunner.class) 和 @SpringBootTest(classes = Example.class) 。

Spring Boot的@*Test注解会自动搜索主配置类,即使你没有显式定义它。(不过还是建议显示配置下)

你可以使用@SpringBootTest的webEnvironment属性定义怎么运行测试:

MOKE -- 默认,加载WebApplicationContext,并提供一个mock servlet环境,使用该注解时内嵌servlet容器将不会启动。如果classpath下不存在servlet APIs,该模式将创建一个常规的non-web ApplicationContext。
RANDOM_PORT -- 加载EmbeddedWebApplicationContext,并提供一个真实的servlet环境。使用该模式内嵌容器将启动,并监听在一个随机端口。
DEFINED_PORT -- 加载EmbeddedWebApplicationContext,并提供一个真实的servlet环境。使用该模式内嵌容器将启动,并监听一个定义好的端口(比如application.properties中定义的或默认的8080端口)。
NONE -- 使用SpringApplication加载一个ApplicationContext,但不提供任何servlet环境(不管是mock还是其他)。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Example.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class Test1 { @Autowired
private TestRestTemplate testRestTemplate;
@LocalServerPort // 用于注入测试用例实际使用的端口
private Integer localServerPort; static {
//for localhost testing only
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() {
public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
if (hostname.equals("localhost")) {
return true;
}
return false;
}
});
} @Test
public void Test1() {
System.out.println("测试启动的随机端口是" + localServerPort);
Area area = testRestTemplate.getForObject("/area/list", Area.class);
System.out.println(area.getInfo());
}
}

Spring Boot 提供一个 @MockBean 注解,可用于为 ApplicationContext 中的bean定义一个Mockito mock,你可以使用该注解添加新beans,或替换已存在的bean定义。该注解可直接用于测试类,也可用于测试类的字段,或用于@Configuration注解的类和字段。当用于字段时,创建mock的实例也会被注入。Mock beans每次调用完测试方法后会自动重置。

import static org.mockito.BDDMockito.*;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Example.class)
public class Test2 { @MockBean
private UserSercice userSercice; @Test
public void test2(){
User user = new User("111111", "张三", "15980292662", 23, 1);
given(this.userSercice.getUserByUuid("111111")).willReturn(user);
User userByUuid = userSercice.getUserByUuid("111111");
System.out.println(userByUuid);
}
}

tips:Spring测试框架在测试过程中会缓存应用上下文,因此,只要你的测试共享相同的配置(不管是怎么发现的),加载上下文的潜在时间消耗都只会发生一次。

六、理解 Auto-configuration 和 Startsers

一个完整的Spring Boot Starter 可能包含以下组件:

-- Autoconfigure模块,包含自动配置类的代码。比如一些可以直接使用的 Bean 定义。
-- Starter模块,提供 Autoconfigure模块 及其他有用的 jar 依赖,简而言之,添加本 Starter 就能开始使用该library。

自动配置可以捆绑在外部的jar包中,由Spring Boot提取 ———— Spring Boot会检查你发布的jar中是否存在META-INF/spring.factories文件,该文件中以EnableAutoConfiguration为key的属性列出你的配置类。

自动配置可以关联一个 "Starter",用于提供 auto-configuration 的代码及需要引用的libraries。

Starter 其实是一个空的模块,它的唯一目的其实就是提供一个必要的依赖关系。

官方 Auto-configuration 示例:https://github.com/snicoll-demos/spring-boot-master-auto-configuration

 演示源代码地址https://github.com/JMCuixy/Boot

SpringBoot 之基础学习篇.的更多相关文章

  1. 鸟哥Linux私房菜基础学习篇学习笔记3

    鸟哥Linux私房菜基础学习篇学习笔记3 第十二章 正则表达式与文件格式化处理: 正则表达式(Regular Expression) 是通过一些特殊字符的排列,用以查找.删除.替换一行或多行文字字符: ...

  2. 鸟哥Linux私房菜基础学习篇学习笔记2

    鸟哥Linux私房菜基础学习篇学习笔记2 第九章 文件与文件系统的压缩打包: Linux下的扩展名没有什么特殊的意义,仅为了方便记忆. 压缩文件的扩展名一般为: *.tar, *.tar.gz, *. ...

  3. 鸟哥Linux私房菜基础学习篇学习笔记1

    鸟哥Linux私房菜基础学习篇学习笔记1 第三章 主导分区(MBR),当系统在开机的时候会主动去读取这个区块的内容,必须对硬盘进行分区,这样硬盘才能被有效地使用. 所谓的分区只是针对64Bytes的分 ...

  4. 拒绝从入门到放弃_《鸟哥的 Linux 私房菜 — 基础学习篇(第三版)》必读目录

    目录 目录 前言 关于这本书 必看知识点 最后 前言 相信部分刚进入这个行业的新同学会对一个问题感到疑惑,为什么从培训学校出来的学员不被欢迎? 这里记录下一些我个人的看法(博主也曾有面试新员工的经历) ...

  5. 【音视频连载-001】基础学习篇- SDL 介绍以及工程配置

    技术开发故事会连载 这是音视频基础学习系列的第一篇文章,主要讲解 SDL 是什么以及为什么要用到它,看似和音视频没啥卵关系,其实必不可少. SDL 简介 SDL 是 "Simple Dire ...

  6. Git 基础学习篇(应用-windows篇)

    此篇教程主要是讲应用,因为理论,,,额,我也说不出来.大家要深入学习还是看廖老师的教程吧. 可以把这篇当作一个简单应用的参考,因为当初看廖老师的也难看啊!!! 以下是资料: 廖雪峰-Git教程 [Gi ...

  7. Linux 基础学习篇 序篇

    读序篇可以知道的: 1.有些指令知道前和知道后,自己的操作是完全不同的,可能知道前,会用reset把系统重新启动一遍,而知道后会使用ps和kill来关闭进程. 2.如果对Linus的学习知识" ...

  8. JS基础学习篇(一)

    近来一直在学习js和jquery.刚刚进入前端工作还没有多久,虽然大学里学习的是编程自认为也学的还可以,但前端接触的不多,一直认为前端十分简单.其实不然,特别是工作的时候要自己设计一个完整的项目前端, ...

  9. Python 基础学习篇

    注:技术尚浅,时间匆忙,如有错误或者不当之处值得商榷的,请留言,吾必思而改之. 第一篇 :Python基础- 安装/变量/输入/及循环语句使用 第二篇:  Python基础- 常用数据类型 第三篇: ...

随机推荐

  1. 简单操作django中session和cookie

    cookie 1.会话技术 2.客户端的会话技术( 数据库保存在浏览器上) 3.问题导致原因: 在web应用中,一次网络请求是从request开始,到response结束,跟以后的请求或者跟其他请求没 ...

  2. 《http权威指南》读书笔记17

    概述 最近对http很感兴趣,于是开始看<http权威指南>.别人都说这本书有点老了,而且内容太多.我个人觉得这本书写的太好了,非常长知识,让你知道关于http的很多概念,不仅告诉你怎么做 ...

  3. 终于明白word-break属性——break-all和break-word的区别

      其实一直不明白,也没有认真去想过 word-break 属性的 break-all 和 break-word 有什么区别 后来看了一个大神写的一篇博客,写得很详细,看了豁然开朗. 所以,我也就不在 ...

  4. java中的全局变量如何实现?ThreadLocal~

    全局变量就是不管你在哪里,都能够直接引用的变量,还不用担心各种问题.每个语言都有自己的全局变量,我想! 一般地,面向过程的语言当中,可能就是一个声明在最前面的变量,后面的代码直接引用,就成了全局变量! ...

  5. 深入浅出 Java 中的包装类

    前阵子,我们分享了<Java中的基本数据类型转换>这篇文章,对许多粉丝还是有带来帮助的,今天讲一下 Java 包装类的的由来,及自动装箱.拆箱的概念和原理. 什么是包装类型 Java 设计 ...

  6. python基础-变量运算符(3)

    一.注释 注释就是对代码的解释和说明.目的是为了让别人和自己很容易看懂.为了让别人一看就知道这段代码是做什么用的.正确的程序注释一般包括序言性注释和功能性注释.序言性注释的主要内容包括模块的接口.数据 ...

  7. “五年经验”年薪50W分享Java程序员掌握什么技术才不会被淘汰

    在这个IT系统动辄就是上亿流量的时代,Java作为大数据时代应用最广泛的语言,诞生了一批又一批的新技术,包括HBase.Hadoop.MQ.Netty.SpringCloud等等 . 一些独角兽公司以 ...

  8. 怎么让Word形状里的文字上下左右居中

    怎么让Word形状里的文字上下左右居中? 第一:左右居中,用段落居中方法: 第二:上下居中,选定图形,单击鼠标右键并选择“设置形状格式”,在选项卡的“文本框”中,选择中部对齐 效果图:

  9. JavaScript递归中的作用域问题

    需求是这样的,从子节点寻找指定className的父节点,一开始就想到递归(笨!),Dom结构如下: <div class="layer_1"> <div cla ...

  10. springBoot(4)---热部署,配置文件使用

    热部署,配置文件使用 一.热加载 spring为开发者提供了一个名为spring-boot-devtools的模块来使Spring Boot应用支持热部署,提高开发者的开发效率,无需手动重启Sprin ...