通过注解学习SpringBoot,通过查看注解介绍SpringBoot的基础知识。Spring Apps 中的许多神奇之处都是通过诸如@Bean, @RestController,@Component之类的注释实现的。

为什么我们关心 Spring 注解

Spring 有一些强大的概念,如依赖注入 (DI),这要归功于 Spring 管理的组件。在这里,所有用 注释的类@Component都是 DI 的候选者,并且可以被其他类使用而无需显式实例化。Spring 提供了一个称为Inversion of Control Container的特性,它会在后台进行所有必要的注入,所有的魔法都在开发人员不做任何工作的情况下发生这是通过研究注解来学习 Spring 的一个很好的例子:给定类的 Java 代码可能看起来完全正常,但是当我们考虑这个元数据时,可能会有更丰富的功能(比如 DI)。有许多注释显着增加了 Spring 独有的功能。

我敢说学习 Spring 的一个好方法是理解最常见的注解。在本文的其余部分,我们将研究不同的注解(来自 Spring 和 javax.persistence),描述它们的用途,并展示一些代码示例。我还创建了一个 Java SpringBoot应用程序,其中包含所有描述的注释,因此如果您想查看一个完整的示例,请查看我的Github 存储库。

1. 学习SpringBoot:注解概述

首先让我们概述一下我认为最重要的 Spring 注解。让我声明我的选择是针对对RESTful web服务感兴趣的人。对于其他人,最佳选择可能略有不同。无论如何,除了 Spring 注释之外,我们还将介绍来自 Javax Persistence API 的元数据标记。这样做的原因:我们几乎总是在后端使用数据库,这是 Javax 支持的功能,而不是 Spring,所以我决定将它包含在这里。

这是我们将要介绍的注释列表:

部分注解表

正如您在上表中所看到的,本博客中包含相当多的注释,因此我决定将它们放入功能组中。让我们从 Main 类中使用的语法元数据开始:

本节涵盖:

@SpringBootApplication
值得庆幸的是,在 Spring 应用程序中,我们的 Main 方法不需要做太多事情:我们不需要编写任何逻辑来组装我们的服务组件并启动它。相反,我们只需要用@SpringBootApplication 注释 Main 类。这主要会触发两件事:首先,SpringBoot会应用默认的配置,比如socket read timeout。其次,Spring 将搜索所有 Spring 管理的组件,例如用@RestController 注释的类。

下面是我们的 Main 类的样子:

@SpringBootApplication 
public class SpringBootAnnotationsApplication { 
    public static void main(final String[] args) { 
        SpringApplication.run(SpringBootAnnotationsApplication.class, args); 
    } 
}

3.学习SpringBoot:REST Point注解

本节涵盖:

@RestController
@RequestMapping
@PathVariable
@RequestBody

假设我们的 Web 服务应该能够响应多个 REST 请求。要实现这一点,我们只需要一个用 @RestController 注释的类,它包含用 @RequestMapping 注释的方法。每个这样的方法代表一个 REST Point。

当一个REST请求到来时,Spring会自动搜索对应的方法,反序列化传入的请求,将所有传入的数据放入我们的方法参数中,我们就可以执行自己的业务逻辑了。最后,我们的结果(一个 Java 对象)将被 Spring 序列化并通过 HTTP 返回。我们需要担心的是我们的方法有正确的足迹,它应该包括以下内容:URI、URI 路径参数、URI 查询参数、HTTP 请求正文和 HTTP 应答正文。

@RequestMapping(method = RequestMethod.PATCH, path = "/api/account/{accountId}") 
public ResponseEntity<AccountRJ> activateAccount( @PathVariable(value = "accountId") Integer accountId, @RequestBody Integer startBalance) {
     // implement method ... 
}

 

下面是相应 REST 请求的示例:

PATCH https://www.../api/account/5 
Request Body: "10"

在我们的代码片段中, theaccountId将是 5 和startBalance10。REST 答案应该是 type 的对象AccountRJ。更具体地说,方法返回值应该是 类型ResponseEntity<T>。这是一个 Spring 类,包含所有 HTTP 回复数据,例如状态码、正文、标头等。

4.学习SpringBoot:定时任务注释

本节涵盖:

@Scheduled
@EnableScheduling
一些 Web 服务需要在后台做常规工作,例如归档旧数据、聚合数据以创建统计信息等。Spring 使周期性任务的实现变得如此简单:

@Configuration @EnableScheduling 
public class TaskConfig { 
    @Scheduled(cron = "* * * * * ?") 
    public void doTask() { 
        System.out.println("hello world"); 
    } 
}

 

如您所见,我们只需要一个注解为 的类@EnableScheduling和一个注解为 的方法@Scheduled(cron=…)。此方法将根据我们的cron 表达式在后台运行,例如每 10 分钟或每小时。

可以在我的 WeatherStatsTask.java 中的 Github 存储库中找到一个完整的示例。

5.学习SpringBoot:Bean注解

本节涵盖:

@Configuration
@Bean
为了让你的应用程序快速启动和运行,SpringBoot有很多合理的默认配置,比如 REST 配置(例如读取超时、连接超时)。我们可以通过定义自己的Beans来覆盖配置默认值。

@Configuration 
public class RestConfig { 
    @Bean 
    public RestTemplate restTemplate(final RestTemplateBuilder builder) { 
        return builder.setConnectTimeout(Duration.parse("PT5s")).setReadTimeout(Duration.parse("PT10s")).build(); 
    } 
}

如上所示,我们的 Bean 被放在一个@Configuration类中,方法被注释为@Bean. 返回类型在这里是必不可少的:每当 Spring 需要使用 aRestTemplate时,它都会根据我们的规范对其进行配置。

关于依赖注入的快速说明
让我们快速看一下依赖注入的概念,因为这对于理解 Spring 管理的组件至关重要。

Spring 提供了一个控制反转(IoC) 容器:Spring 将注入所有必要的依赖项,而不是手动初始化对象的所有成员。在下图中,您可以看到一个类需要另一个类的对象:

Configuration注解图片

该类Parent包含一个Child对象:

public class Parent { 
    private final Child child; 
    public Parent(Child child) {
        this.child = child; 
    } 
}

我们现在可以用@Component如下方式注释依赖项:

@Component 
public class Child { … }

现在,当 Spring IoC 必须创建一个 Parent 类型的对象时,它会自动创建一个 Child 对象,然后将该对象作为参数传递给 Parent 构造函数,从而创建一个所有依赖项都已初始化的对象。

请注意,复杂应用程序中的实际依赖链可以具有多个层次结构级别。Spring IoC 也适用于复杂的情况,其中一个类需要另一个类,而另一个类又需要第三个类,依此类推。此外,Spring IoC 甚至适用于接口依赖:当一个类需要一个接口类型的对象时,Spring 将搜索一个实现该接口的类并注入它。

6.学习SpringBoot:Spring托管组件的注解

本节涵盖:

@Component
@Service
@Repository

现在您了解了依赖注入的概念,让我们关注指定 Spring 管理的组件的三种不同注解:

@Component:这个Class注册在Spring-ApplicationContext中,成为依赖注入的候选对象。
@Service:与@Component同义,但用于应用的服务层(有业务逻辑)。
@Repository:与@Component 相同,但用于执行数据库访问的类。标准的数据库异常将被 Spring 自动捕获并适当处理。
请注意,所有这些注释都将在类级别应用。

@Components -> AnnotationsAppProperties.java
@Service -> WeatherService.java
@Repository -> WeatherRepository.java

7.学习SpringBoot:持久性注解

本节涵盖:

@Entity
@Id
@GeneratedValue
@EnableJpaRepositories
@EnableTransactionManagement

与前面的部分类似,注解对于数据持久化非常有用:我们需要的只是正确的注解!对于以下示例,我们只关注 SQL 用例,并使用Spring Data Jpa。要进行ORM 映射,我们需要一个@Entity 类,如下所示:

@Entity 
public class WeatherPO { 
    @Id 
    @GeneratedValue(strategy=GeneratorionType.IDENTITY) 
    private Long id; 
    private Integer temperature; 
}

在上面的代码中,WeatherPO 类包含我们想要从关系数据库中表示的所有数据元素。第一个成员也被注释为@Id表示这是主键。此外,我们定义了一个生成新主键的策略,同样带有注释!

现在我们准备好定义一个 JpaRepository,我们可以用它从数据库中获取 WeatherPO 对象:

@Repository 
public interface WeatherRepository extends JpaRepository<WeatherPO, Long> {}

当 Spring 看到@Repository注解时,它会自动创建一个实现类来访问数据库。我们可以通过依赖注入使用存储库:

@Service 
public class WeatherService { 
    private final WeatherRepository repo; 
    public WeatherService(WeatherRepository repo) { 
        this.repo = repo; 
    } 
    public WeatherPO find(Long id) { 
        return repo.getOne(id); 
    } 
}

到目前为止,我们已经介绍了访问数据库所需的所有 Java 代码。为了使一切正常,我们还需要正确的 Maven 依赖项:Spring 的spring-boot-starter-data-jpa。 SQL数据库种类繁多,如果我们选择使用简单的H2数据库,我们还需要一个Maven依赖:com.h2database.h2.

或者,我们可以配置我们的数据库(用户名、密码、URL 等)。请注意,H2 数据库开箱即用,但对于 Oracle DB 等其他数据库,您将需要此额外配置。也就是说,您可以强制搜索存储库,并且可以使用注释@EnableJpaRepositories创建自己的数据库相关 bean 。@EnableTransactionManagement

@Entity、@Id、@GeneratedValue -> WeatherPO.java
@Repository -> WeatherRepository.java
@EnableJpaRepositories, @EnableTransactionManagement -> JpaConfig.java

8.学习SpringBoot:杂项注释

本节涵盖:

@Autowired
@ConfigurationProperties

@ConfigurationProperties可用于自动从.propertiesor.yaml文件中获取配置值,并将它们放入具有相同数据结构的 Java 类中。这允许我们在配置文件中设置配置值,以后可以轻松更改。

@Autowired强制依赖注入。我们需要在依赖链的根部启动依赖注入机制。当我们要求 Spring 初始化顶层对象时,这将触发依赖链中所有对象的初始化和注入。@Autowired 注释可用于此目的并放在顶级对象之前。

可以在我的 Github 存储库中找到一个完整的示例:

@ConfigurationProperties -> AnnotationsAppProperties.java
@Autowired -> WeatherIntegrationTest.java

 

9.测试注释

本节涵盖:

@SpringBootTest
@AutoConfigureMockMvc
Spring 仅出于测试目的提供注解,这是一个让集成测试更简单的好特性!由于这篇文章已经比原先预期的要长一些,我将停在这里并向您推荐 WeatherIntegrationTest.java 中的完整示例。

10.相关

JavaScript闭包、回调和IIFE的揭秘

什么是Python以及其用途