#点击图片报名参加武汉、长沙源创会#
本部分将详细介绍如何使用Spring Boot。 这部分涵盖诸如构建系统,自动配置以及如何运行应用程序等主题。 我们还介绍了一些Spring Boot的最佳实践(best practices)。 虽然Spring Boot没有什么特殊之处(它只是一个可以使用的库),但是有一些建议可以让您的开发过程更容易一些。
如果您刚刚开始使用Spring Boot,那么在深入本部分之前,您应该阅读
入门指南
。
强烈建议您选择一个支持
依赖管理
并可以使用“Maven Central”存储库的构建系统。 我们建议您选择Maven或Gradle。 Spring Boot 可以与其他构建系统(例如 Ant )配合使用,但是它们不会得到很好的支持。
每个版本的Spring Boot提供了一个它所支持的依赖关系列表。 实际上,您不需要为构建配置文件中的这些依赖关系提供版本,因为Spring Boot会为您进行管理这些依赖的版本。 当您升级Spring Boot本身时,这些依赖关系也将以一致的进行升级。
如果您觉得有必要,您仍然可以指定一个版本并覆盖Spring Boot建议的版本。
管理的列表中包含可以使用Spring Boot的所有Spring模块以及第三方库的精简列表。 该列表可作为标准的
物料(Materials)清单(spring-boot-dependencies)
使用,并且还提供了对
Maven
和
Gradle
的额外支持。
Spring Boot的每个版本与Spring Framework的基本版本相关联,因此我们强烈建议您不要自己指定其版本。
Maven用户可以从 spring-boot-starter-parent-parent 项目中继承,以获得合理的默认值。 父项目提供以下功能:
-
Java 1.6作为默认编译器级别。
-
源代码UTF-8编码。
-
依赖关系管理
,允许您省略常见依赖的
标签,其默认版本继承自spring-boot-dependencies POM。
-
更合理的
资源过滤
。
-
更合理的插件配置(
exec plugin
,
surefire
,
Git commit ID
,
shade
)。
-
针对application.properties和application.yml的更合理的资源过滤,包括特定的文件(例如application-foo.properties和application-foo.yml)
-
最后一点:由于默认的配置文件接受Spring样式占位符(${...}),Maven过滤更改为使用 @..@ 占位符(您可以使用Maven属性resource.delimiter覆盖它)。
13.2.1 继承启动器parent
要将项目配置为继承spring-boot-starter-parent,只需设置
标签如下:
您只需要在此依赖项上指定Spring Boot版本号。 如果您导入其他起始器,则可以放心地省略他们的版本号。
通过该设置,您还可以通过覆盖自己的项目中的属性来覆盖单个依赖。 例如,要升级到另一个 Spring Data 版本序列,您需要将以下内容添加到您的pom.xml中。
检查
spring-boot-dependencies pom
以获取支持的属性列表。
13.2.2 使用没有父POM的 Spring Boot
不是每个人都喜欢从spring-boot-starter-parent POM继承。 您公司可能有自己标准的父母,或者您可能只希望明确声明所有的Maven配置。
如果您不想使用spring-boot-starter-parent,则仍然可以通过使用scope=import依赖来保持依赖管理(但不能进行插件管理)的好处:
该设置不允许您使用如13.2.1 所述的属性来覆盖单个依赖关系。 要实现相同的结果,您需要在spring-boot-dependencies条目之前在项目的dependencyManagement中添加一个条目。 例如,要升级到另一个Spring Data发行版本,您需要将以下内容添加到您的pom.xml中。
在上面的例子中,我们指定了一个BOM,但是任何依赖关系类型都可以被这样覆盖。
13.2.3 更改Java版本
spring-boot-starter-parent选择相当保守的Java兼容性版本。 如果要遵循我们的建议并使用更高版本的Java版本,可以添加java.version属性:
13.2.4 使用Spring Boot Maven插件
Spring Boot包括一个Maven插件,可以将项目打包成可执行jar。 如果要使用它,请将插件添加到
部分:
如果您使用Spring Boot启动器 parent pom,则只需要添加这个插件,除非您要更改parent中定义的设置,否则不需要进行配置。
Gradle用户可以直接在其依赖关系部分导入“启动器”。 不像Maven,没有“超级父”导入来共享一些配置。
spring-boot-gradle-plugin也是可用的,它提供了从源代码创建可执行jar并运行项目的任务。 它还提供依赖关系管理,除其他功能外,还允许您省略由Spring Boot管理的任何依赖关系的版本号:
可以使用Apache Ant + Ivy构建Spring Boot项目。 spring-boot-antlib“AntLib”模块也可用于帮助Ant创建可执行文件。
要声明依赖关系,典型的ivy.xml文件将如下所示:
典型的build.xml将如下所示:
请参见
第84.10节“从Ant构建可执行存档,而不使用spring-boot-antlib”
如果不想使用spring-boot-antlib模块,请参阅“操作方法”。
启动器是一组方便的依赖关系描述符,可以包含在应用程序中。 您可以获得所需的所有Spring和相关技术的一站式服务,无需通过示例代码搜索和复制粘贴依赖配置。 例如,如果要开始使用Spring和JPA进行数据库访问,那么只需在项目中包含spring-boot-starter-data-jpa依赖关系即可。
启动器包含许多依赖关系,包括您需要使项目快速启动并运行,并具有一致的受支持的依赖传递关系。
What’s in a name
所有正式起动器都遵循类似的命名模式: spring-boot-starter- ,其中 是特定类型的应用程序。 这个命名结构旨在帮助你快速找到一个启动器。 许多IDE中的Maven插件允许您按名称搜索依赖项。 例如,安装Eclipse或STS的Maven插件后,您可以简单地在POM编辑器中点击 Dependency Hierarchy,并在filter输入“spring-boot-starter”来获取完整的列表。 如
创建自己的启动器
部分所述,第三方启动程序不应该从Spring-boot开始,因为它是为正式的Spring Boot artifacts 保留的。 acme 的 第三方启动器通常被命名为acme-spring-boot-starter。
Spring Boot在org.springframework.boot组下提供了以下应用程序启动器:
表13.1. Spring Boot应用程序启动器
除了应用程序启动器,以下启动器可用于添加
生产准备(production ready)
功能:
表13.2 Spring Boot生产环境启动器
最后,Spring Boot还包括一些启动器,如果要排除或替换特定的技术,可以使用它们:
有关社区贡献的更多启动器的列表,请参阅GitHub上的spring-boot-startters模块中的
README文件
。
Spring Boot不需要任何特定的代码组织结构,但是有一些最佳实践可以帮助您。
当类不包括包声明时,它被认为是在“默认包”中。 通常不鼓励使用“默认包”,并应该避免使用。 对于使用@ComponentScan,@EntityScan或@SpringBootApplication注解的Spring Boot应用程序,可能会有一些特殊的问题,因为每个jar的每个类都将被读取。
我们建议您遵循Java推荐的软件包命名约定,并使用反向域名(例如,com.example.project)。
我们通常建议您将应用程序主类放到其他类之上的根包(root package)中。 @EnableAutoConfiguration注解通常放置在您的主类上,它隐式定义了某些项目的基本“搜索包”。 例如,如果您正在编写JPA应用程序,则@EnableAutoConfiguration注解类的包将用于搜索@Entity项。
使用根包(root package)还可以使用@ComponentScan注释,而不需要指定basePackage属性。 如果您的主类在根包中,也可以使用@SpringBootApplication注释。
这是一个典型的布局:
Application.java文件将声明main方法以及基本的@Configuration。
Spring Boot支持基于Java的配置。虽然可以使用XML配置用SpringApplication.run(),但我们通常建议您的主source是@Configuration类。 通常,定义main方法的类也是作为主要的@Configuration一个很好的选择。
许多使用XML配置的Spring示例已经在网上发布。 如果可能的话我们建议始终尝试使用等效的基于Java的配置。 搜索 enable* 注解可以是一个很好的起点。
您不需要将所有的@Configuration放在一个类中。 @Import注解可用于导入其他配置类。 或者,您可以使用@ComponentScan自动扫描所有Spring组件,包括@Configuration类。
如果您必须使用基于XML的配置,我们建议您仍然从@Configuration类开始。 然后,您可以使用的@ImportResource注释来加载XML配置文件。
Spring Boot 会根据您添加的jar依赖关系自动配置您的Spring应用程序。例如,如果HSQLDB在您的类路径上,并且您没有手动配置任何数据库连接bean,那么我们将自动配置内存数据库。
您需要通过将@EnableAutoConfiguration或@SpringBootApplication注解添加到您的一个@Configuration类中来选择自动配置。
您应该只添加一个@EnableAutoConfiguration注解。 我们通常建议您将其添加到主@Configuration类中。
自动配置是非侵入式的,您可以随时定义自己的配置来替换自动配置。 例如,如果您添加自己的 DataSource bean,则默认的嵌入式数据库支持将会退回。
如果您需要了解当前有哪些自动配置,以及为什么,请使用--debug开关启动应用程序。 这将启用debug日志,并将自动配置日志记录到控制台。
如果您发现正在使用一些不需要的自动配置类,可以使用@EnableAutoConfiguration的exclude属性来禁用它们。
如果类不在classpath路径上,则可以使用注释的excludeName属性,并指定全限定名(fully qualified name)。 最后,您还可以通过spring.autoconfigure.exclude属性控制要排除的自动配置类列表。
注解和使用属性(property)定义都可以指定要排除的自动配置类
您可以自由使用任何标准的Spring Framework技术来定义您的bean及其依赖注入关系。 为了简单起见,我们发现使用@ComponentScan搜索bean,结合@Autowired构造函数(constructor)注入效果很好。
如果您按照上述建议(将应用程序类放在根包(root package)中)构建代码,则可以使用 @ComponentScan而不使用任何参数。 所有应用程序组件(@Component,@Service,@Repository,@Controller等)将自动注册为Spring Bean。
以下是一个@Service Bean的例子,我们可以使用构造函数注入获取RiskAssessor bean。
如果一个bean 只有一个构造函数,则可以省略@Autowired。
注意,如何使用构造函数注入允许将RiskAssessor字段标记为final,表示不能更改。
使用@SpringBootApplication注解
许多Spring Boot开发人员总是使用@Configuration,@EnableAutoConfiguration和@ComponentScan来标注它们的主类。 由于这些注解经常一起使用(特别是如果您遵循之前说的
最佳实践
),Spring Boot提供了一个方便的@SpringBootApplication注解作为这三个的替代方法。
@SpringBootApplication注解相当于使用@Configuration,@EnableAutoConfiguration和@ComponentScan和他们的默认属性:
@SpringBootApplication还提供了别名来定制@EnableAutoConfiguration和@ComponentScan的属性。
将应用程序打包成jar并使用嵌入式HTTP服务器的最大优点之一就是可以按照你想用其他任何方式运行应用程序。调试Spring Boot应用程序也很容易; 您不需要任何专门的IDE插件或扩展。
本节仅涵盖基于jar的打包,如果您选择将应用程序打包为war文件,则应参考您的服务器和IDE的文档。
您可以从IDE中运行 Spring Boot 应用程序作为一个简单的Java应用程序,但是首先需要导入项目。 导入步骤将根据您的IDE和构建系统而有所不同。 大多数IDE可以直接导入Maven项目,例如Eclipse用户可以从File菜单中选择import...→Existing Maven Projects。
如果您无法将项目直接导入到IDE中,则可以使用构建插件生成IDE元数据。 Maven包括Eclipse和IDEA的插件; Gradle为各种IDE提供插件。
如果您不小心运行了两次Web应用程序,您将看到“Port already in use”中的错误。 使用STS用户可以使用重新启动按钮而不是运行以确保任何现有实例已关闭。
如果您使用Spring Boot 的 Maven或Gradle插件创建可执行jar,则可以使用java -jar运行应用程序。 例如:
也可以打包的应用程序运行时也可以启用远程调试支持。 这允许您将调试器添加到打包的应用程序中:
Spring Boot Maven 插件包含一个运行目标(goal ),可用于快速编译和运行应用程序。 应用程序以exploded的形式运行,就像在IDE中一样。
您可能还需要使用一些有用的操作系统环境变量:
Spring Boot Gradlet插件还包括一个bootRun任务,可用于以exploded 形式运行应用程序。 每当导入spring-boot-gradle-plugin时,都会添加bootRun任务:
您可能还想使用这个有用的操作系统环境变量:
由于Spring Boot应用程序只是纯Java应用程序,所以JVM热插拔应该是开箱即用的。 JVM热插拔在一定程度上受到可替代的字节码的限制,更完整的解决方案,可以使用
JRebel
或者
Spring Loaded
项目。 spring-boot-devtools模块还支持快速重新启动应用程序。
有关详细信息,请参阅
第20章“开发人员工具”
部分和
热插拔“操作方法”
。
Spring Boot包括一组额外的工具,可以使应用程序开发体验更加愉快。 spring-boot-devtools模块可以包含在任何项目中,以提供额外的
开发时
功能。 要包含devtools支持,只需将模块依赖关系添加到您的构建中:
Maven:
Gradle:
当运行完全打包的应用程序时,开发人员工具将自动禁用。 如果您的应用程序是使用java -jar启动的,或者是使用特殊的类加载器启动,那么它将会被认为是“生产环境的应用程序”。 将开发工具依赖关系标记为可选(optional)是一种最佳做法,可以防止使用项目将devtools传递性地应用于其他模块。 Gradle不支持开箱即用的可选依赖项,因此您可能希望在此期间查看
propdeps-plugin
。
重新打包的jar包默认情况下不包含devtools。 如果要使用某些
远程devtools功能
,您需要禁用excludeDevtools 构建下的属性以包含devtools。 该属性支持Maven和Gradle插件。
Spring Boots支持的几个库使用缓存来提高性能。 例如,
模板引擎
将缓存编译的模板,以避免重复解析模板文件。 此外,Spring MVC可以在返回静态资源时向响应中添加HTTP缓存头。
虽然缓存在生产中非常有益,但它在开发过程中可能会产生反效果,从而阻止您看到刚刚在应用程序中进行的更改。 因此,spring-boot-devtools将默认禁用这些缓存选项。
缓存选项通常由您的application.properties文件中的设置配置。 例如,Thymeleaf提供了spring.thymeleaf.cache属性。 spring-boot-devtools模块不需要手动设置这些属性,而是自动应用更加合理的开发时(development-time)配置。
有关应用的属性的完整列表,请参阅
DevToolsPropertyDefaultsPostProcessor
。
使用spring-boot-devtools的应用程序将在类路径上的文件发生更改时自动重新启动。 这在IDE中开发时可能是一个有用的功能,因为它为代码更改提供了非常快的反馈循环。 默认情况下,将监视指向文件夹的类路径上的任何条目。 请注意,某些资源(如静态资源和视图模板)不需要重新启动应用程序。
触发重启
当DevTools监视类路径资源时,触发重新启动的唯一方法是更新类路径中的文件时。 导致类路径更新的方式取决于您正在使用的IDE。 在Eclipse中,保存修改的文件将导致类路径被更新并触发重新启动。 在IntelliJ IDEA中,构建项目(Build→Make Project)将具有相同的效果。
只要 forking 被启用,您也可以通过支持的构建插件(即Maven和Gradle)启动应用程序,因为DevTools需要一个单独的应用程序类加载器才能正常运行。Gradle和Maven默认情况下在类路径上检DevTools。
自动重启当与LiveReload一起使用时工作非常好。 详见
下文
。 如果您使用JRebel,自动重启将被禁用,有利于动态类重新加载。 其他devtools功能仍然可以使用(如LiveReload和属性覆盖)。
DevTools依赖于应用程序上下文的关闭钩子,以在重新启动期间关闭它。 如果禁用了关闭挂钩(SpringApplication.setRegisterShutdownHook(false)),DevTools将无法正常工作。
当判断类路径中的项目是否会在更改时触发重新启动时,DevTools会自动忽略名为spring-boot,spring-boot-devtools,spring-boot-autoconfigure,spring-boot-actuator和spring-boot-start的项目。
重新启动(Restart) vs 重新加载(Reload)
Spring Boot提供的重新启动技术使用两个类加载器。 不会改的类(例如,来自第三方的jar)被加载到基类加载器中。 您正在开发的类被加载到重新启动(restart)类加载器中。 当应用程序重新启动时,重新启动类加载器将被丢弃,并创建一个新的类加载器。 这种方法意味着应用程序重新启动通常比“冷启动”快得多,因为基类加载器已经可以使用。
如果发现重新启动对应用程序不够快,或遇到类加载问题,您可以考虑来自ZeroTurnaround的JRebel等重新加载技术。 这些工作通过在加载类时重写(rewriting)类,使其更适合重新加载。 Spring Loaded提供了另一个选项,但是它在很多框架上不支持,并且不支持商用。
20.2.1 排除资源
在类路径下,某些资源在更改时不一定需要触发重新启动。 例如,Thymeleaf模板可以直接编辑不需重启。 默认情况下,有一些排除项,更改 /META-INF/maven,/META-INF/resources,/resources,/static,/public或/templates中的资源不会触发重新启动,但会触发
实时重新加载
。 如果要自定义这些排除项,可以使用spring.devtools.restart.exclude属性。 例如,要仅排除 /static和 /public,您可以设置:
如果要保留这些默认值并添加其他排除项,请改用spring.devtools.restart.additional-exclude属性。
20.2.2 监视额外的路径
有时当您对不在类路径中的文件进行更改时,需要重新启动或重新加载应用程序。为此,请使用spring.devtools.restart.additional-paths属性来配置其他路径以监视更改。 您可以使用
上述
的spring.devtools.restart.exclude属性来控制附加路径下的更改是否会触发完全重新启动或只是
实时重新加载
。
20.2.3 禁用重启
如果不想使用重新启动功能,可以使用spring.devtools.restart.enabled属性来禁用它。 在大多数情况下,您可以在application.properties中设置此项(这仍将初始化重新启动类加载器,但不会监视文件更改)。
例如,如果您需要完全禁用重新启动支持,因为它在一些特定库中不能正常运行,则需要在调用SpringApplication.run(...)之前设置System属性。 例如:
20.2.4 使用触发文件
如果您使用IDE工具编写代码,更改文件,则您可能希望仅在特定时间触发重新启动。 为此,您可以使用“触发文件”,这是一个特殊文件,当您要实际触发重新启动检查时,必须修改它。 更改文件只会触发检查,只有在Devtools检测到它必须执行某些操作时才会重新启动。 触发文件可以手动更新,也可以通过IDE插件更新。
要使用触发器文件,请使用spring.devtools.restart.trigger-file属性。
您可能希望将spring.devtools.restart.trigger-file设置为
全局设置
,以使所有项目的行为方式相同。
20.2.5 自定义重新启动类加载器
如上面的
Restart vs Reload
部分所述,重新启动功能是通过使用两个类加载器实现的。 对于大多数应用程序,此方法运行良好,但有时可能会导致类加载问题。
默认情况下,IDE中的任何打开的项目将使用“重新启动”类加载器加载,任何常规.jar文件将使用“base”类加载器加载。 如果您在多模块项目上工作,而不是每个模块都导入到IDE中,则可能需要自定义事件。 为此,您可以创建一个META-INF / spring-devtools.properties文件。
spring-devtools.properties文件可以包含restart.exclude 和 restart.include.prefixed属性。 include元素是应该被拉入“重新启动(restart)”类加载器的项目,排除元素是应该向下推入“基本(base)”类加载器的项目。 属性的值是将应用于类路径的正则表达式模式。
例如:
所有属性键必须是唯一的。 只要一个属性从restart.include. 或restart.exclude. 开始,将被考虑。
将加载类路径中的所有META-INF/spring-devtools.properties。 您可以在项目中打包文件,或者在项目所使用的库中打包文件。
20.2.6 已知的限制
重新启动功能对于使用标准ObjectInputStream反序列化的对象无效。 如果需要反序列化数据,可能需要使用Spring的ConfigurableObjectInputStream与Thread.currentThread()。getContextClassLoader()组合使用。
不幸的是,几个第三方库在不考虑上下文类加载器的情况下反序列化。 如果您发现这样的问题,您需要向原始作者请求修复。