S1E2_Developing with Spring Boot

246 阅读6分钟

1.构建工具

1.1 依赖管理

每个Spring Boot发布版本都会提供一系列的依赖支持,包括所有会使用到的Spring模块及精简的三方依赖。开发者不需要关注依赖版本,只需按需引用即可,依赖都由Spring Boot管理。升级Spring Boot这些依赖也会一并升级。

自带的依赖清单通过spring-boot-dependencies提供,官方优先支持Maven和Gradle作为带有依赖管理功能的构建工具。

当然,如有必要开发者是可以覆盖具体的某些依赖的版本。

1.2 Starters

Starters是Spring Boot提供的一站式依赖描述集合,不需要手动拷贝与管理众多依赖描述。比如想使用Spring和JPA做数据库访问,只需在应用程序中引入spring-boot-starter-data-jpa依赖即可。

有了starters,应用程序的组建速度与依赖管理能力得到大幅提升。除了官方提供的starter之外,社区贡献的starter也很丰富。通过自动装配机制开发者可以完成自己的starter定制。

Spring Boot对Starters做了命名约束:

a.所有官方提供的starter的命名规则是spring-boot-starter-**代表具体的某一类型应用;

b.除官方提供外,所有其他(三方)starter的命名规则是thirdpartyproject-spring-boot-starter,应用名称作为前缀。

举几个官方提供的经典starter,都在org.springframework.boot路径下:

NameDescription
spring-boot-starterCore starter, including auto-configuration support, logging and YAML
spring-boot-starter-webStarter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container
spring-boot-starter-amqpStarter for using Spring AMQP and Rabbit MQ
spring-boot-starter-aopStarter for aspect-oriented programming with Spring AOP and AspectJ
spring-boot-starter-artemisStarter for JMS messaging using Apache Artemis
spring-boot-starter-data-jpaStarter for using Spring Data JPA with Hibernate
spring-boot-starter-cacheStarter for using Spring Framework’s caching support

2.代码结构

2.1 不建议使用缺省包

如果一个类没有声明在任何一个包下面也就是默认放在src/main/java目录下成为缺省包。虽然Java支持这样编译,但是Spring Boot不建议这么做,会使@ComponentScan, @ConfigurationPropertiesScan, @EntityScan@SpringBootApplication逐个扫描class的注解出问题。

建议遵循Java包名约定,使用反转的领域名称组织包路径。 比如com.example.project

2.2 主类Main

建议将主类Main放置代码工程根目录上,在所有其他类之上。

@SpringBootApplicaiont注解作用于主类上,它所在的包圈定了搜索其他特定部件的范围。比如一个JPA应用,Spring会扫描标记@SpringBootApplication的类所在的包下所有带有@Entity部件的类。

也可以使用@EnableAutoConfiguration@ComponentScan代替@SpringBootApplication

如下是一个经典代码组织结构:

 com
  +- example
      +- myapplication
          +- MyApplication.java
          |
          +- customer
          |   +- Customer.java
          |   +- CustomerController.java
          |   +- CustomerService.java
          |   +- CustomerRepository.java
          |
          +- order
              +- Order.java
              +- OrderController.java
              +- OrderService.java
              +- OrderRepository.java

MyApplication类使用@SpringBootApplication标记,并声明主函数main:

 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 ​
 @SpringBootApplication
 public class MyApplication {
 ​
     public static void main(String[] args) {
         SpringApplication.run(MyApplication.class, args);
     }
 ​
 }

3.配置类

Spring Boot更倾向于基于Java的配置方式,尽管Spring Boot应用程序支持xml作为数据源启动,但使用@Configuration标记某个类作为主类更合适,通常是定义main函数的类。

不需要将所有@Configuration注解放入一个类中,可以使用@Import引入其他的配置类,@ComponentScan可以自动扫描包括@Configuration的所有Spring组件。

4.自动装配

Spring Boot的自动装配机制是对添加到classpath的jar依赖自动加载到Spring容器中。 比如添加了HSQLDB依赖,Spring Boot就会自动装配一个内存数据库,如果手动添加了自己的数据源,默认嵌入式数据库就会自动失效。

自动装配机制生效需要添加@SpringBootApplication@EnableAutoConfiguration注解,官方建议直接在带有@Configuration的主类添加即可。

排除自动装配的类可以通过注解或配置项,比如@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })spring.autoconfigure.exclude

有一项需要注意的,尽管自动装配的类都是public的,但是唯一被认为是public API的是可作为禁用自动配置的类名。事实上,这些类的内部嵌套类及方法是为Spring Boot使用的,不建议开发者直接使用他们。

5.Spring Bean与DI

Spring Boot可以使用标准的Spring框架定义bean并注入他们需要的依赖,官方建议使用构造器注入依赖,使用@ComponentScan发现这些bean。

如果按照上文约定将主类在工程结构中置顶,Spring Boot会自动将带有@Component@Service@Repository@Controller等注解的组件注册为Spring Bean。

比如,一个用@Service标记使用构造器注入RiskAccessor bean的Bean:

 import org.springframework.stereotype.Service;
 ​
 @Service
 public class MyAccountService implements AccountService {
 ​
     private final RiskAssessor riskAssessor;
 ​
     public MyAccountService(RiskAssessor riskAssessor) {
         this.riskAssessor = riskAssessor;
     }
 ​
     // ...
 }

如果有不止一个构造器,就需要用@Autowired标记一个:

 import java.io.PrintStream;
 ​
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 ​
 @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;
     }
 ​
     // ...
 }

需要注意的是,使用构造器注入,需要将注入的私有对象riskAccessor标记为final,保证以后不可能被改变。

6.使用@SpringBootApplication注解

@SpringBootApplication注解等同于同时使用@EnableAutoConfiguration@ComponentScan@SpringBootConfiguration这三个注解。

他们分别用于激活Spring Boot自动装配机制,激活组件自动扫描,激活上下文中自定义的bean与引入的其他配置类的注册。

注意,这些特性都不是强制的,可以选择替换其中任一特性,比如不想使用自动组件扫描及注册自定义bean:

 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.SpringBootConfiguration;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.context.annotation.Import;
 ​
 @SpringBootConfiguration(proxyBeanMethods = false)
 @EnableAutoConfiguration
 @Import({ SomeConfiguration.class, AnotherConfiguration.class })
 public class MyApplication {
 ​
     public static void main(String[] args) {
         SpringApplication.run(MyApplication.class, args);
     }
 ​
 }

MyApplication跟其他Spring Boot应用没有区别,除了以下几点:

a.无法自动扫描@Component注解的组件

b.无法自动装配@ConfigurationProperties注解的配置

c.开发者自定义的bean需要@Import显式引入

7.运行程序

将Spring Boot应用程序打包成jar并使用内嵌式Http服务器的好处是可以直接运行程序。

Spring Boot推荐将应用程序打包成jar而不是war。

如何加载一个Maven工程就不仔细讲了,这取决于所用的IDE。不过就Java而言,IDEA仍然是当下不二选择,即使是免费的IDEA Community依然可以满足日常开发工作。

运行程序,可以在IDE中debug运行,也可以打包为jar后通过java -jar运行,也可以借助构建工具运行,比如使用Maven就执行命令mvn spring-boot:run

程序更新与重启也有被提及,因为Spring Boot是纯Java应用也应做到开箱即用,但是JVM热交换受限于可替换的字节码,更完整的解决方案可以参考JRebel

8.开发工具

Spring Boot提供了专门用于开发阶段的工具,通过引入spring-boot-devtools依赖实现,包括热部署、自动重启、远程启动、全局开发工具配置等。