本节展示了更多关于使用SpringBoot的细节。它包括了build系统、自动配置以及如何运行应用程序等。我们还介绍了一些使用Spring Boot的好习惯。尽管没有什么特别的,但有一些建议可以让您的开发过程变得更简单。
1.build系统
我们强烈建议你选择一个支持依赖管理的构建代码的系统工具。比如Maven或者Gradle。比可能也会选择别的,比如Ant,但是他们支持的不是很好。
1.1.依赖管理
每个springboot版本都会列出他所支持的依赖项的详细列表。实际上,您不需要在构建配置中为这些依赖项中的任何一个提供版本号,因为SpringBoot会为您管理这些依赖项。升级Spring Boot本身时,这些依赖项也会以一致的方式升级。
你任然可以提供一个版本号,就替取缔spring默认的版本,如果有必要的话。
Spring Boot的每个版本都与Spring框架的一个基本版本相关联。强烈建议您不要指定其版本。
1.2 maven
mave学习使用,请跳转到maven说明文档:
1.3 Starters启动器
starters是一堆你可以直接引用到你项目中的jar包依赖,你可以一站式的获得所有你所需要的spring和相关技术。而不需要去搜索样例代码,技术所需的依赖。比如:如果您想开始使用Spring和JPA进行数据库访问,在项目中直接添加spring-boot-starter-data-jpa依赖就行了。
springboot提供了以下启动器:(只列了几个)
名字 | 描述 |
---|---|
核心启动器,包括自动话配置支持、日志 and YAML | |
activemq启动器 | |
Spring AMQP 和 Rabbit MQ启动器 | |
面向切面的启动器(Spring AOP and AspectJ) |
2.代码结构
springboot本身不要求代码结构。
2.1包命名
如果一个类开头没有包声明时,就是默认包下(src/mian/java路径下的类)。
这样可能会导致@ComponentScan、@ConfigurationPropertiesScan、@EntityScan或@SpringBootApplication注解出问题。
所以spring建议使用com.example.project这样的包命名方式。
2.2 定位主应用程序类
我们建议你将主应用程序类放在 root package 下,其他类的上层目录(如下面例子中的MyApplication.java类)。
com
+- example
+- myapplication
+- MyApplication.java
|
+- customer
| +- Customer.java
| +- CustomerController.java
| +- CustomerService.java
| +- CustomerRepository.java
|
+- order
+- Order.java
+- OrderController.java
+- OrderService.java
+- OrderRepository.java
@SpringBootApplication注解放在主类上,他隐示的定义了基本的包扫描路径,他会扫描主类下层目录中的类(有兴趣可以试试放在自己定义的dao或者别的包下,看能不能扫描到同级包里的类)。
如果不想用@SpringBootApplication, 也可以用@ComponentScan和@EnableAutoConfiguration代替
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
3.配置类(Configuration Classes)
springboot支持Java编码方式的配置。虽然使用XML也可以,但是我们建议你使用@Configuration。通常,主应用程序类可以作为一个主配置类。
3.1 引入额外的配置类
你不比将所有的配置都放在一个类里面。@Import注解可以用来引入额外的配置类(创建好bean对象)。或者,你可以使用@ComponentScan自动获取spring所有的component,包括带有@Configuration注解的类。
3.2 导入XML配置
如果你必须使用xml配置,我们任然建议你定义一个@Configuration注解的类,然后使用@ImportResource注解将xml配置引入。
4.自动配置
springboot自动配置,会根据你添加的jar包依赖,自动的配置你的应用程序。例如,如果你导入了HSQLDB包,但是没有手动配置任何数据库先关的连接对象,springboot也会自动配置一个内存数据库。
你需要通过添加@SpringBootApplication或者@EnableAutoConfiguration在你的其中一个配置类上来开启自动配置。
4.1 逐步取代自动配置
Springboot自动配置对代码没有入侵。任何时候,你都可以通过定义自己的配置来代替自动配置。比如,添加自己的DataSource bean,那么默认的配置就会被代替。
如果你需要查看项目中使用了哪些自动配置,以及为什么。可以通过添加--debug开关参数启动,这样就能记录相关日志到控制台。
idea中可以这样配置
Positive matches:
-----------------
AopAutoConfiguration matched:
- @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)
4.2 禁用特定的自动配置类
如果不想使用某些自动配置类,可以通过@SpringBootApplication的exclude属性去禁用。
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class MyApplication {
}
如果要禁用的类不再类路径下,也可以使用excludeName属性填写类名代替。如果你用的是@EnableAutoConfiguration开启的自动配置,这个注解也支持exclude和excludeName。最后,你还可以在配置文件中用spring.autoconfigure.exclude来定义要排除的自动配置类list
spring:
autoconfigure:
exclude: org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
注解方式可配置文件方式可以一起使用
虽然自动配置类是公用的,但只是指这些自动配置的类名可以被用来禁用自动配置。这些类的实际内容,比如嵌套的配置类,bean method仅供内部使用,我们不建议直接使用他们。
5.Spring Beans和依赖注入
你可以自由的使用标准的spring框架技术来定义bean以及为其注入依赖项,我们通常建议你使用构造函数的方式来注入bean,使用@ComponentScan去获取bean对象。
如果你按我们建议的方式(之前讲的)安排代码结构,你可以直接使用@ComponentScan不需要任何参数,或者使用@SpringBootApplication(包含@ComponentScan),你所有的组件(@Component
, @Service
, @Repository
, @Controller等
)都会被自动注册到spring bean对象中。
下面展示了一个service bean使用构造函数的方式来注入需要的RiskAssessor bean对象
@Service
public class MyAccountService implements AccountService {
private final RiskAssessor riskAssessor;
public MyAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
// ...
}
如果有多个构造函数,你需要通过@Autowired注解告诉spring使用哪个
@Service
public class MyAccountService implements AccountService {
private final RiskAssessor riskAssessor;
private final PrintStream out;
@Autowired
public MyAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
this.out = System.out;
}
public MyAccountService(RiskAssessor riskAssessor, PrintStream out) {
this.riskAssessor = riskAssessor;
this.out = out;
}
// ...
}
请注意如何使用构造函数将RiskAssessor申明为final,这表明,之后将不会被改变。
6. 使用@SpringBootApplication注解
使用一个@SpringBootApplication可以支持一下三个功能:
- @EnableAutoConfiguration 开启自动配置
- @ComponentScan 开启组件扫描
- @SpringBootConfiguration 在spring context中注册额外的bean,或者导入额外的配置类。是@Configuration的替代品,在集成测试中可以被自动发现。
@SpringBootApplication // 等同于 @SpringBootConfiguration @EnableAutoConfiguration
// @ComponentScan
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
@SpringBootApplication注解也支@
EnableAutoConfiguration
和 @ComponentScan的定制化(禁用某些自动化配置、扫描路径配置)
介绍的这三个功能都不是必须的,你可以替代这些注解,比如,你不想使用组件扫描,下面的例子中,除了没有开启包扫描外,其他都一样。使用@Import明确的导入了用户自定义的配置类。
@SpringBootConfiguration(proxyBeanMethods = false)
@EnableAutoConfiguration
@Import({ SomeConfiguration.class, AnotherConfiguration.class })
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
7. 运行你的项目
将你的程序打包成jar包,并使用了嵌入式的http服务器,这样做最大的好处是,你可以想运行别的程序一样运行你的项目程序,同样适用于debug。你不需要任何特殊的IDE插件或扩展。
7.1 使用IDE启动
你可以把springboot应用当做java程序在ide上启动。
如果你以外启动了2次,会有端口占用的报错(Port already in use),Spring Tools用户可以使用Relaunch按钮启动来确保关闭已有的实例。(得下载SpringTools, idea没有找到这个按钮,我一般是打开进程管理器,杀掉java进程)。
7.2 打包运行
如果你用Maven或者Gradle 将程序创建成了一个可执行jar包,就可以用java -jar来运行
$ java -jar target/myapplication-0.0.1-SNAPSHOT.jar
也支持在运行的时候添加远程调试器:
$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \
-jar target/myapplication-0.0.1-SNAPSHOT.jar
7.3 使用maven
run快速变异和运行程序。
//启动
$ mvn spring-boot:run
//maven修改系统后环境变量
$ export MAVEN_OPTS=-Xmx1024m
7.4 使用Gradle
$ gradle bootRun
$ export JAVA_OPTS=-Xmx1024m
7.5 Hot Swapping (热启动)
springboot是普通的java程序,热启动应该是开箱即用的。JVM热启动受限与他可以替换的字节码,完整的解决方案,请看JRebel
spring boot devtools模块还包括对快速应用程序重启的支持。有关详细信息,请看: Hot swapping “How-to”
8.Developer Tools(开发者工具)
SpringBoot有一些别的工具可以让开发者体验更好一些。spring-boot-devtools可以被任何项目引入,在开发的时候可以提供帮助。
maven方式:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
Gradle方式:
dependencies {
developmentOnly("org.springframework.boot:spring-boot-devtools")
}
当运行一个完全打包的项目时,工具会自动禁止。如果你的项目是通过java -jar或者特殊的classloader启动,会被认为是生产环境项目。你也可以使用系统参数来控制,-Dspring.devtools.restart.enabled=true来启动,-Dspring.devtools.restart.enabled=false禁止。
在maven中把依赖标记为可选的(<optional>true</optional>),这Gradle中使用developmentOnly,防止devtools被传递到别的模块中。(如果其他项目依赖你的项目,<optional>true</optional>可以防止devtools被包含进去)
如果devtools的远程功能。maven需要这样设置。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeDevtools>false</excludeDevtools>
</configuration>
</plugin>
</plugins>
</build>
8.1 属性默认值
SpringBoot支持的一些库可以通过使用缓存来提高性能。比如模块引擎(例如:Thymeleaf)缓存可以避免重复的编译template文件。Spring MVC可以添加HTTP缓存头来应答静态资源的访问。
虽然缓存在生产环境有好处,但在开发过程中会适得其反,会导致你看不到刚刚做的修改。因此spring-boot-devtools默认禁止缓存功能。
缓存选项通常是在application.properties文件中设置。比如Thymeleaf通过spring.thymeleaf.cache属性设置
因为在开发SpringMVC和Spring WebFlux的时候需要详细的网络请求的信息,所以developer-tools建议你给web日志记录组开启debug日志记录。这样就会给你展示进入的请求、那个handler处理请求、返回的response信息等。如果你想记录所有的请求详情(包括敏感信息),你可以开启spring.mvc.log-request-details或者spring.codec.log-request-details配置属性。
如果你不香使用默认值,你可以在配置文件里面设置spring.devtools.add-properties=false
开发者工具完整的属性列表:DevToolsPropertyDefaultsPostProcessor.
8.2 自动重启
使用spring-boot-devtools后,当classpath下的文件被修改,项目就会自动重启。 在使用IDE开发的时候很有用,因为当代码被修改的时候反馈很快。请注意,某些静态资源、视图模板等不需要重启项目。
触发启动:
DevTools只监听classpath资源,唯一触发启动的方式就是更新classpath下的资源。更新classpath资源的方式取决于你使用的IDE:
- Eclipse 需要手动保存才能触发。
- IntelliJ IDEA :需要building project
- maven: mvn compile
当与LiveReload一起使用时,自动重启效果会非常好,这个接下来会说。
DevTools依赖springboot的shutdown hook在重启的时候关闭。如果SpringApplication.setRegisterShutdownHook(false),会导致他出问题。
使用AspectJ时不支持自动重启。
Restart 和 Reload
重启技术使用2中类加载器。那些不会被修改的类(第三方jar包)被加载到基础的类加载器中。你正在开发的类被加载到重启类加载器中(restart classloader)。当项目重启的时候,会丢弃现有的重启类加载器,创建一个新的加载器。这意味着比完全启动更快。
8.2.1 记录变化
每次重启都会记录变化。可以通过设置去禁止。
spring.devtools.restart.log-condition-evaluation-delta=false
8.2.2 排除资源
某些资源被修改的时候没必要重启。比如Thymeleaf页面。默认情况下,/META-INF/maven
, /META-INF/resources
, /resources
, /static
, /public
, or /templates这些目录下的资源不会触发重启,但会触发live reoad。你可以使用
spring.devtools.restart.exclude定制化排除那些资源。比如只排除/static /public
spring.devtools.restart.exclude=static/**,public/**
如果你想保留默认的排除,添加额外的排除,可以使用spring.devtools.restart.additional-exclude
8.2.3 监听额外的路径
你可以使用spring.devtools.restart.additional-paths属性去配置监听额外的路径。你可以使用spring.devtools.restart.exclude你配置额外路径下的修改是触发重启还是live reload。
spring.devtools.restart.exclude的优先级高。两个同时设置相同目录,结果是被排除。
8.2.4 禁用Restart
如果你不想使用重启功能,你可以使用spring.devtools.restart.enabled属性来禁用。大多数情况下,我们使用的是配置文件的方式(这样任然会初始化restart classloader,但不会监听文件修改)。
如果想要完全禁止,你需要在调用SpringApplication.run(…)方法前设置spring.devtools.restart.enabled的系统参数为false:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(MyApplication.class, args);
}
}
8.2.5 使用触发器文件
如果你使用IDE一直不间断的修改文件,你或许更希望只在特定时间restart。这种情况下,你可以使用触发器文件(trigger file),只有这个文件被修改才会触发重启检查。
使用这个功能,需要在以下目录添加文件:
src
+- main
+- resources
+- .reloadtrigger
然后添加配置:
spring.devtools.restart.trigger-file=.reloadtrigger
现在,只有.reloadtrigger文件被修改才会restart。
8.2.6 定制Restart Classloader
上面说的Restart和Reload,restart功能使用了2个类加载器。对于大多数项目,表现很好。但是有时候会造成类加载问题。
默认情况下,在你IDE上,任何项目都被restart类加载器加载, .jar文件都被base类加载器加载。如果是多模块项目,没有将所有模块都导入IDE,你需要定制话一些东西。如果是这样的话,你可以创建一个META-INF/spring-devtools.properties文件。
spring-devtools.properties文件可以包含restart.exclude和restart.include前缀的属性。include属性设置的是被restart类加载器加载的项,exclude属性设置的是被base类加载器加载的项。属性的值是正则匹配的:
restart.exclude.companycommonlibs=/mycorp-common-[\\w\\d-\\.]+\\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w\\d-\\.]+\\.jar
8.2.7 局限性
restart功能对于标准输入流反序列化出来的对象效果不是很好,如果你想反序列化数据,你或许需要使用spring的ConfigurableObjectInputStream和Thread.currentThread().getContextClassLoader()
不幸的是,一些第三方的lib没有考虑到这点,如果你遇到问题,你需要给作者提fix。
8.3 LiveReload
spring-boot-devtools模块包含一个LiveReload服务,当资源修改的时候,可以触发浏览器刷新。LiveReload浏览器插件Chrome是免费的,Firefox and Safari从 livereload.com下载。
如果想禁用这个服务:spring.devtools.livereload.enabled=false
同一时刻只能运行一个LiveReload服务,就算运行多个项目,只有第一个项目会有这个服务。
只有自动restart开启,才能触发LiveReload
8.4 全局设置
devtools全局设置通过在$HOME/.config/spring-boot目录下添加以下文件中的任何一个:
$HOME指的是当前用户目录。
-
spring-boot-devtools.properties
-
spring-boot-devtools.yaml
-
spring-boot-devtools.yml
在这些文件中添加的配置会应用到你机器上所有使用了devtools的spring项目。比如之前说的触发器文件属性配置,就可以放到全局文件里。
spring.devtools.restart.trigger-file=.reloadtrigger
如果devtools配置文件在$HOME/.config/spring-boot目录下没有找到,就会在$HOME目录下搜索是否有.spring-boot-devtools.properties文件。这样可以让你给那些不支持$HOME/.config/spring-boot路径的项目分享全局配置文件。
8.4.1 配置FileSystemWatcher
FileSystemWatcher每隔一段时间就会检测一次class是否有修改,然后等待预设的静默期保证没有别的修改。由于springboot完全依赖IDE编译和拷贝文件到springboot可以访问的目录下,你可能会发现,当项目restart的时候,某些修改不会生效。这个时候你可以尝试增加spring.devtools.restart.poll-interval
和 spring.devtools.restart.quiet-period参数的值:
spring.devtools.restart.poll-interval=2s
spring.devtools.restart.quiet-period=1s
现在每2秒检查一次classpath的修改,1秒静默期后确保咩有别的修改。
8.5 远程项目
Spring Boot developer tools不止用于本地项目,远程项目也能使用他们的一些功能。远程支持是可选的,因为这样会带来一些安全风险。只应该在信任的网络上或者有ssl保护时使用,否则就不该使用。一定不要在生产环境使用DevTools的远程功能。
使用的时候,pom导入包之后,再添加以下配置:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeDevtools>false</excludeDevtools>
</configuration>
</plugin>
</plugins>
</build>
然后设置spring.devtools.remote.secret属性,属性的值应该和其他重要的密码一样,不会被别人才出来。
Remote devtools支持的功能分为2个:接受连接的服务端端点、运行在IDE的客户端应用程序。
spring.devtools.remote.secret属性设置后,服务端组件自动开启。客户端组件需要手动启动。
8.5.1 运行远程客户端应用
远程客户端程序在IDE上,运行org.springframework.boot.devtools.RemoteSpringApplication。本地项目需要和远程项目有相同的目录结构。本地项目唯一的参数就是你需要连接的远程服务。
具体步骤,加入你的项目名为my-app:
- 选择启动配置
- 创建一个新的Java Application配置
- 地址为my-app项目
- 使用org.springframework.boot.devtools.RemoteSpringApplication作为main class
- Program arguments添加远程url
运行信息:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ ___ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | | _ \___ _ __ ___| |_ ___ \ \ \ \
\\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' \/ _ \ _/ -_) ) ) ) )
' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / /
=========|_|==============|___/===================================/_/_/_/
:: Spring Boot Remote :: 2.5.6
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-project/spring-boot-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code)
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)
如果想要使用代理连接,使用spring.devtools.remote.proxy.host和spring.devtools.remote.proxy.port属性配置
8.5.2 远程更新
任何本地的更新都会被推送到远程项目,触发远程项目的restart。如果你使用远程服务,这会很有帮助。通常,远程更新和重启比重新编译打包部署快的多。
当开发环境很慢的时候,静默期可能会不够,导致你的修改被分为很多批次。远程服务在第一批次的时候重启,其他批次不会被发送到远程服务,因为服务正在重启。
这种情况通常会有某些classes上传失败的告警以及重试的日志,也可能造成代码不一致或者在第一批次代码上传后导致无法启动。出现这些问题,可以尝试去增加spring.devtools.restart.poll-interval和spring.devtools.restart.quiet-period属性的值。
9.打包你的项目
可执行jar包可以用在生产环境。因为他们是自包含的(可独立运行),因此也非常适用于基于云的部署。
10.下一步
现在你应该知道了如何使用springboot,以及应该遵循的一些好的习惯。现在你可以继续深入了解springboot的特性,也可以跳过直接去了解生产环境搭建相关的内容。