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

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

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

  1. <!--
  2. 1、在运行一个完整的,打包过的应用时(Java -jar),会禁用开发者工具。
  3. 2、防止 devtools 传递到项目中的其他模块,需要设置依赖级别 optional
  4. 3、只要 classpath 下的文件有变动(Eclipse 中文件保存就能重启,IDEA 中需要 Build ——> Build Project),系统就会自动重启。
  5. -->
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-devtools</artifactId>
  9. <optional>true</optional>
  10. </dependency>
  1. spring:
  2. devtools:
  3. restart:
  4. # devtools 排除不需要检测的资源 和 增加额外需要监测的资源
  5. exclude: application.yml
  6. additional-paths: src/main/webapp
  7. # 是否重启,如果设置为false禁用,依旧会初始化重启类加载器,但它不会监控文件变化
  8. enabled: true
  9. # 触发器文件,只有在修改该文件的时候,才能触发工程重启
  10. #trigger-file: trigger-file
  11. livereload:
  12. # 内嵌的 LiveReload 服务器,可以在资源改变时,触发浏览器更新,禁用设置为false
  13. enabled: true

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

     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 注解。

  1. @Component
  2. public class ApplicationArgumentsBean implements CommandLineRunner, ApplicationRunner, ExitCodeGenerator, DisposableBean {
  3. private static final Logger logger = LoggerFactory.getLogger(ApplicationArgumentsBean.class);
  4. /**
  5. * 如果运行的时候使用 java -jar *.jar --debug logfile.txt
  6. * 则:debug = true,files=["logfile.txt"]
  7. *
  8. * @param args
  9. */
  10. @Autowired
  11. public ApplicationArgumentsBean(ApplicationArguments args) {
  12. boolean debug = args.containsOption("debug");
  13. List<String> files = args.getNonOptionArgs();
  14. }
  15. @Override
  16. public void run(ApplicationArguments args) throws Exception {
  17. logger.info("重写 ApplicationRunner 的 run 方法:{}", args.containsOption("debug"));
  18. }
  19. @Override
  20. public void run(String... args) throws Exception {
  21. logger.info("重写 CommandLineRunner 的 run 方法:{}", args);
  22. }
  23. @Override
  24. public int getExitCode() {
  25. return 0;
  26. }
  27. @Override
  28. public void destroy() throws Exception {
  29. logger.info("重写 DisposableBean 的 destroy 方法,用于在 SpringApplication 退出后执行一些操作");
  30. }
  31. @PreDestroy
  32. public void predestroy() {
  33. logger.info("使用 @PreDestroy 用于在 SpringApplication 退出后执行一些操作");
  34. }
  35. }

ApplicationArgumentsBean.java

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

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

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

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

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

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

  1. @Bean
  2. public PropertySourcesPlaceholderConfigurer properties() {
  3. PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
  4. YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
  5. yaml.setResources(new ClassPathResource("my.yml"));
  6. configurer.setProperties(yaml.getObject());
  7. return configurer;
  8. }

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

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

  1. @Test
  2. public void test3() {
  3. YamlPropertiesFactoryBean yml = new YamlPropertiesFactoryBean();
  4. yml.setResources(new ClassPathResource("my.yml"));
  5. Properties properties = yml.getObject();
  6. Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator();
  7. while (iterator.hasNext()) {
  8. Map.Entry<Object, Object> entry = iterator.next();
  9. logger.info("YamlPropertiesFactoryBean 读取的配置文件内容是:{}-{}", entry.getKey(), entry.getValue());
  10. }
  11. logger.info("--------华丽的分割线------------");
  12. YamlMapFactoryBean yamlMapFactoryBean = new YamlMapFactoryBean();
  13. yamlMapFactoryBean.setResources(new ClassPathResource("my.yml"));
  14. Map<String, Object> map = yamlMapFactoryBean.getObject();
  15. Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
  16. while (it.hasNext()) {
  17. Map.Entry<String, Object> entry = it.next();
  18. logger.info("YamlPropertiesFactoryBean 读取的配置文件内容是:{}-{}", entry.getKey(), entry.getValue());
  19. }
  20. }

    另外需要提及的是 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) :

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest(classes = Example.class)
  3. public class Test1 {
  4. private static final Logger logger = LoggerFactory.getLogger(Test1.class);
  5. @Autowired
  6. private DataSource dataSource;
  7. @Test
  8. public void test1() {
  9. logger.info("@ConfigurationProperties 注解的实现效果:" + ((DruidDataSource) dataSource).getUrl());
  10. }
  11. }

 

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

版权声明:本文为jmcui原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/jmcui/p/9683354.html