最近好忙,本部分翻译的不是很完整,随后会重新润色哒
版权声明:本文为博主原创文章,转载时请务必注明本文地址, 禁止用于任何商业用途, 否则会用法律维权。
转载请注明出处:http://blog.csdn.net/HITLiuXiaodong/article/details/53471184
本人水平有限,翻译中的错误还请多多指教
本部分会更加详细的讨论如何使用SpringBoot。主要包含的话题有构建系统,自动配置和运行程序。我们也会讨论一些SpringBoot的最佳实践。虽然SpringBoot没有什么特别之处(你可以把它看作一个第三方库),但是这里会有一些小建议,如果遵循的话会使开发稍微轻松一点。
如果你刚开始接触SpringBoot,在进入本部分之前,你最好先读一读 入门 部分。
我们强烈推荐你使用一套构建工具来进行构建,最好是Maven或者Gradle。虽然你可以用其他构建工具比如ant,但是我们不会提供特定的支持。
SpringBoot的每一个版本都会提供一份依赖清单。在实际应用中,你不需要手动去管理这些版本,因为SpringBoot会帮你管理。当你想升级Spring Boot的时候,这些依赖也会一同升级。
如果需要的话,你也可以自己指定版本进行覆盖
在清单里包含所有的Spring模块,也包含一份精简的第三方库。这份清单可以看作是一个标准的springboot依赖材料。
SpringBoot发布的每个版本都会和特定的Spring框架版本相联系。因此我们强烈建议你不要自己指定Spring版本。
Maven使用者可以通过继承spring-boot-starter-parent
来获取一些默认的配置。这个parent提供以下的配置:
spring-boot-dependencies
,你可以省略 标签最后一点,因为默认配置文件中支持Spring风格的占位符 (${}),因此Maven过滤器中使用 @…@ 风格的占位符。(当然,你也可以通过重载resource.delimiter
配置)
为了让你的工程继承自 spring-boot-starter-parent
,你只需这样配置:
org.springframework.boot
spring-boot-starter-parent
2.0.0.BUILD-SNAPSHOT
你只需要在依赖中指定SpringBoot的版本即可。如果你也使用了其他的 starters 你可以很放心的忽略指定他们的版本。
按照这样设置,你可以通过覆盖一个属性来覆盖相应的以来。例如我们想升级Spring Data的版本,就可以这样设置:
<properties>
<spring-data-releasetrain.version>Fowler-SR2</spring-data-releasetrain.version>
</properties>
查看这里来获取一份支持覆盖的属性清单
并不是每一个人都想继承 spring-boot-starter-parent 。你可能需要继承公司的父节点,也可能单单想更确切的声明maven.
如果你不想继承 spring-boot-starter-parent
,你也可以通过使用 scope=import
来享受依赖管理的便捷(并不是插件管理)
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.0.0.BUILD-SNAPSHOTversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
上面的这种配置并不能让你用来覆盖单独的依赖。为了得到同样的结果,你需要在dependencyManagement
的spring-boot-dependencies
前面添加一个入口,例如你想升级SpringData的版本,你需要在pom.xml中这样配置:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-releasetrainartifactId>
<version>Fowler-SR2version>
<scope>importscope>
<type>pomtype>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.0.0.BUILD-SNAPSHOTversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
在上面的例子中,我们指定了一个 BOM ,你也可以不指定
spring-boot-starter-paren
会选择相对保守的java版本。但是如果你听从我们的建议,选择比较新的Java版本,你可以在配置文件中添加一个 java.version
的属性。
<properties>
<java.version>1.8java.version>
properties>
SpringBoot包含一个可以把工程打包成可执行jar包的maven插件。如果你想使用的话,只需要把她添加到 节点中
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
如果你使用了SpringBoot的父节点,那么你只需要添加这个插件即可,不需要其他的配置,除非你想更改默认的配置。
Gradle用户只需要在 dependencies
中声明即可。不像maven,无需添加单独的父节点。
apply plugin: 'java'
repositories {
maven { url "http://repo.spring.io/snapshot" }
maven { url "http://repo.spring.io/milestone" }
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web:2.0.0.BUILD-SNAPSHOT")
}
我们提供了 spring-boot-gradle-plugin
插件以供你从源码生成jar包。也提供了 依赖管理,它可以帮你管理依赖的版本。
buildscript {
repositories {
maven { url "http://repo.spring.io/snapshot" }
maven { url "http://repo.spring.io/milestone" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT")
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
repositories {
maven { url "http://repo.spring.io/snapshot" }
maven { url "http://repo.spring.io/milestone" }
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
testCompile("org.springframework.boot:spring-boot-starter-test")
}
你也可以通过 ant+Ivy 来构建一个SpringBoot。这个 spring-boot-antlib
模块可以帮助 ant 创建一个可执行jar包。你只需像下面这样配置:
<ivy-module version="2.0">
<info organisation="org.springframework.boot" module="spring-boot-sample-ant" />
<configurations>
<conf name="compile" description="everything needed to compile this module" />
<conf name="runtime" extends="compile" description="everything needed to run this module" />
configurations>
<dependencies>
<dependency org="org.springframework.boot" name="spring-boot-starter"
rev="${spring-boot.version}" conf="compile" />
dependencies>
ivy-module>
一个典型的 build.xml 就像下面这样:
<project
xmlns:ivy="antlib:org.apache.ivy.ant"
xmlns:spring-boot="antlib:org.springframework.boot.ant"
name="myapp" default="build">
<property name="spring-boot.version" value="1.3.0.BUILD-SNAPSHOT" />
<target name="resolve" description="--> retrieve dependencies with ivy">
<ivy:retrieve pattern="lib/[conf]/[artifact]-[type]-[revision].[ext]" />
target>
<target name="classpaths" depends="resolve">
<path id="compile.classpath">
<fileset dir="lib/compile" includes="*.jar" />
path>
target>
<target name="init" depends="classpaths">
<mkdir dir="build/classes" />
target>
<target name="compile" depends="init" description="compile">
<javac srcdir="src/main/java" destdir="build/classes" classpathref="compile.classpath" />
target>
<target name="build" depends="compile">
<spring-boot:exejar destfile="build/myapp.jar" classes="build/classes">
<spring-boot:lib>
<fileset dir="lib/runtime" />
spring-boot:lib>
spring-boot:exejar>
target>
project>
如果你不想使用
spring-boot-antlib
,你可以参看下面的章节 Section 80.10, “Build an executable archive from Ant without using spring-boot-antlib”
SpringBoot无需特定的代码结构,不过这里有一些最佳实践。
当一个类没有包含包声明时,它就位于默认包下。我们不鼓励使用默认包名,也应该避免使用默认包名。因为这可能对SpringBoot的@ComponentScan, @EntityScan or @SpringBootApplication注释产生特定的问题。
我们建议你使用java推荐的包命名规范并且使用公司域名(比如:com.example.project)
我们建议你把 启动类放在根包名下面。因为@EnableAutoConfiguration注释会经常放在启动类里,它会以此为根扫描路径进行搜索。比如你正在写一个JPA程序,@EnableAutoConfiguration注释的类会用来搜索 @Entity注释的条目。
使用根包名时允许你在不指定 basePackage属性时使用@ComponentScan注释。也可以在这种情况下使用@SpringBootApplication
下面是一个典型的项目结构:
+- example
+- myproject
+- Application.java
|
+- domain
| +- Customer.java
| +- CustomerRepository.java
|
+- service
| +- CustomerService.java
|
+- web
+- CustomerController.java
Application.java
文件中会包含 main 方法,也带有 @Configuration注释。
package com.example.myproject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
许多Spring Boot开发者会在他们的 main类中使用 @Configuration, @EnableAutoConfiguration 、 @ComponentScan注释。因为这些注释使用的太频繁了(特别是当你遵循了上面的最佳实践),SpringBoot提供了一个简单的 @SpringBootApplicatio 注释用来取代上面的三个注释。
@SpringBootApplication注释和@Configuration, @EnableAutoConfiguration and @ComponentScan具有相同的效果。
package com.example.myproject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@SpringBootApplication 也提供有别名以供你定制 @EnableAutoConfiguration 和 @ComponentScan
如果你使用SpringMaven或者Gradle插件来创建的可执行jar包,你可以使用 java -jar来运行程序。例如:
$ java -jar target/myproject-0.0.1-SNAPSHOT.jar
你也可以通过绑定远程调试工具来运行程序。比如:
$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \
-jar target/myproject-0.0.1-SNAPSHOT.jar
SpringBoot自带了一些工具集可以使编程体验变得愉悦。你可以把Spring-boot-devtools
模块加入工程来体验额外的功能。为了添加这些开发工具的支持,你只需简单的添加依赖即可:
Maven
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<optional>trueoptional>
dependency>
dependencies>
Gradle
dependencies {
compile("org.springframework.boot:spring-boot-devtools")
}
当你运行打包好的程序时,开发工具会自动关闭。如果你使用
java -jar
或者使用自定义的classloader启动时,它也会被当作 “发布的产品” 。把这个开发工具模块当作可选的部分是非常有用的,它可以避免你影响到工程的其他模块。不过Gradle不支持 可选依赖,所以你同时也需要看看 propdeps-plugin 这部分。
重新打包默认并不会把这个开发工具包打包进去。如果你想使用远程调试模块,你需要关闭excludeDevtools
属性来把它打包进去。Maven和Gradle都支持设置该属性。
SpringBoot支持的库可能使用缓存来提升性能。比如:Thymeleaf 会缓存模版来避免重复解析xml源文件。尽管缓存对发布产品有用,可是对开发确不利。比如你在IDE里修改了一些代码,你想立即看到结果。
Cache选项通常需要手动在 application.properties
里进行设置。比如:Thymeleaf 提供spring.thymeleaf.cache
属性来控制缓存。不过与这些手动设置不同,spring-boot-devtools
模块会自动配置对于时间敏感的属性。
如果想得到完整的自动配置清单列表,请访问DevToolsPropertyDefaultsPostProcessor.
应用程序如果使用了 spring-boot-devtools
模块,那么当位于classpath路径下的文件发生改变后,服务就会重启。这会非常有用当你在IDE里修改了代码想尽快看到修改后的效果。默认情况下,classpath下的所有文件都会被监控。不过,一些特定的资源文件比如静态资源发生改变就无须重启服务器。
触发一个重启操作
因为这个DevTools会自动监测classpath下的资源文件,所以触发重启的唯一办法就是更新classpath下的文件。不过更新classpath下的文件取决于你使用的IDE。在Eclipse下,保存修改的文件会引发classpath的更新从而触发服务重启。在IDEA下,通过Build->Make Project
会起到同样的效果。你也可以通过构建工具的插件来启动项目,只要 forking 是启用的,因为DevTools需要一个独立的应用程序加载器才可以正常工作。当Maven和Gradle检测到classpath目录下有DevTools时就会自动做这些。
自动重启能够和LiveReload很好的配合工作。详情见下面。如果你使用了 JRebel,那么重启就会被关掉,因为JRebel会进行热部署。不过其他的一些特色(比如自动刷新和默认的一些配置)会被保留下来。
DevTools在重启时会依赖 application context的shutdown hook 来关闭它。所以当你关闭了shutdown hook (SpringApplication.setRegisterShutdownHook(false))) 它就没法正常工作了。
当classpath下的文件发生改变时,DevTools会根据改变的内容决定是否重启。DevTools会自动忽略名称为:spring-boot, spring-boot-devtools, spring-boot-autoconfigure, spring-boot-actuator, and spring-boot-starter.下的项目。
重启和重载
SpringBoot提供的重启技术是通过两个类加载器实现的。一些不变的类,(比如第三方的jar包)会被一个基础类加载器加载。一些需要频繁修改的类会被一个重启类加载器加载。当应用重启时,旧的重启类加载器会被丢弃,一个新的类加载器会被创建出来。这意味着应用重启速度会比冷启动快很多,因为基础类加载器已经存在了。
如果你觉得应用的重启速度不够快,或者你遇到类加载问题了,你可以考虑使用其它的重载技术比如JRebel。这些技术通过重写class文件来获得更快的加载速度。SpringLoaded提供了另外一种选择,不过它并不支持太多框架,也不提供商业支持。
一些特定的资源发生改变是无需触发重启。比如:Thymeleaf 模版只需在原处发生改变。默认情况下
/META-INF/maven, /META-INF/resources ,/resources ,/static ,/public or /templates路径下的资源发生改变不会触发重启,不过会引发资源重新加载。如果你想定制需要排除的资源,你可以修改 spring.devtools.restart.exclude
属性。比如,你只想排除 /static and /public 下的资源,你只需像下面这样设置:
spring.devtools.restart.exclude=static/**,public/**
如果你想保留默认的设置,想新增加一些排除想,请修改
spring.devtools.restart.additional-exclude
属性
你可能需要SpringBoot在你修改非classpath路径下的文件时也触发重启。这时你需要修改spring.devtools.restart.additional-paths
来添加额外的路径进行监测。你也可以通过设置上面提到的spring.devtools.restart.exclude
来控制额外路径下的文件变动触发的行为。
如果你不想使用自动重启功能,你可以通过spring.devtools.restart.enabled
来控制。大多数情况下,你只需在application.properties
中进行设置(这仍然会初始化restart类加载器,不过不会监测文件的变化)
如果你想彻底的关闭重启支持,你需要在 调用SpringApplication.run(…)
之前进行设置:
public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(MyApp.class, args);
}
SpringBoot开发工具不仅局限于本地开发。你也可以在远程运行程序时使用一些功能。远程开发是可选的功能,为了启用它,你需要确保 devtools
包含在 打包的压缩文件里:
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<excludeDevtools>falseexcludeDevtools>
configuration>
plugin>
plugins>
build>
然后你需要设置一个 spring.devtools.remote.secre
属性,例如:
spring.devtools.remote.secret=mysecret
在远程开发中启用
spring-boot-devtools
会带来安全风向。因此你不应该在正式发布中启用此属性
远程客户端程序设计的是从IDE内启动。你需要 和远程你需要连接的服务一样启动org.springframework.boot.devtools.RemoteSpringApplication
,同时你必须传递需要连接的URL到应用程序中。
比如:你正在使用Eclipse或者 STS,你创建了了一个叫做 my-app的项目,你想把它部署到 云端服务中,那么你可以按照下面的步骤进行操作:
Run configuration...
launch configuration
org.springframework.boot.devtools.RemoteSpringApplication
作为入口类https://myapp.cfapps.io
到Program arguments
或者你选择的其他url一个运行的远程客户端像下面这样:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ ___ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | | _ \___ _ __ ___| |_ ___ \ \ \ \
\\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' \/ _ \ _/ -_) ) ) ) )
' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / /
=========|_|==============|___/===================================/_/_/_/
:: Spring Boot Remote :: 2.0.0.BUILD-SNAPSHOT
2015-06-10 18:25:06.632 INFO 14938 --- [ main] o.s.b.devtools.RemoteSpringApplication : Starting RemoteSpringApplication on pwmbp with PID 14938 (/Users/pwebb/projects/spring-boot/code/spring-boot-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code/spring-boot-samples/spring-boot-sample-devtools)
2015-06-10 18:25:06.671 INFO 14938 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2a17b7b6: startup date [Wed Jun 10 18:25:06 PDT 2015]; root of context hierarchy
2015-06-10 18:25:07.043 WARN 14938 --- [ main] o.s.b.d.r.c.RemoteClientConfiguration : The connection to http://localhost:8080 is insecure. You should use a URL starting with 'https://'.
2015-06-10 18:25:07.074 INFO 14938 --- [ main] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2015-06-10 18:25:07.130 INFO 14938 --- [ main] o.s.b.devtools.RemoteSpringApplication : Started RemoteSpringApplication in 0.74 seconds (JVM running for 1.105)
远程的客户端也会像在本地调试一样监控你应用程序的classpath中文件的改变。任何资源的改变都会被同步到远程客户端,并且在合适的时候触发重启。这在使用云服务并且需要频繁调试的时候非常有用。通常情况下,远程更新和重启会比一个完整的编译部署流程快上许多。
只有远程客户端在运行时才会监测本地文件的变动。如果你没有启动远程客户端,那么你对文件做出的更改不会被推送的远程服务中。
当你想定位一个问题时,远程调试会变得非常有用。不过,如果你的应用没有部署在数据中心时,远程调试可能会不起作用。在容器技术比如docker中设置远程调试是非常困难的。
为了绕过这些限制,开发工具集采用HTTP的方式进行调试。远程的程序会提供一个服务器,监听8000端口。一旦建立链接,调试指令就可以通过HTTP传给远程调试。如果你想使用一个不同的端口,你可以设置spring.devtools.remote.debug.local-port
属性。
你也应该确保远程程序开启了远程调试。通常情况下可以通过JAVA_OPTS
来设置。比如:在Cloud Foundry
架构中,你可以在manifest.yml中添加:
---
env:
JAVA_OPTS: "-Xdebug -Xrunjdwp:server=y,transport=dt_socket,suspend=n"
注意:你无须给
-Xrunjdwp
指定一个address=NNNN
的选项。如果你忽略此选项,Java会选择一个随机的端口。
在网络上远程调试的话,网速可能会很慢,因此你需要在你的IDE中增加超时时间。比如,在Eclipse中,你可以选择java->Debug->Preferences… 修改Debugger timeout(ms) ,来选择一个合适的超时时间 (大多数情况下60000足够了)。
可执行的jar包可以用于发布。因为他们内部包含有服务器,因此也非常适合云端部署。
如果想了解更多关于发布的知识,比如运行状况、认证以及REST、JMX知识,可以考虑添加上
spring-boot-actuator
。请看第五部分 “Spring Boot Actuator: Production-ready features”
现在你应该已经了解如何根据最佳实践来使用SpringBoot了。那么接下来,你可以深入学习SpringBoot的一些特色,或者你也可以跳过前面的部分,直接阅读 SpringBoot的发布部分。