我们处于使用多种语言、框架和架构为每个生命周期阶段开发应用程序的世界,这造成了巨大的复杂性。有一种进行基于容器的部署的冲动。Spring Boot和 Docker 一起是开发 RESTful Web 服务应用程序的伟大组合。在这篇文章中,我将尝试解释:
Docker其优势。
创建Spring Boot应用程序。
在 Docker 中托管Spring Boot应用程序。
Docker
Docker 是一种开源技术,主要用于开发、运输和运行应用程序。Docker 的辉煌是,一旦将应用程序及其所有依赖项打包到 Docker 容器中,您就可确保它将在任何环境中运行。Docker 容器映像是一个轻量级的独立、可执行的软件包,具有运行应用程序所需的一切。例如,创建 Java 应用程序需要 Java 库,当我们在任何系统或 VM 上部署它时,我们需要先安装 Java。但是,在容器中,所有内容都保存在一起,作为一个包裹发货,例如在 Docker 容器中。有关 Docker容器的详细信息,请阅读文档。
Spring Boot
Spring Boot 是一个基于微服务的框架,在中创建生产就绪应用程序只需要很少的时间。开发人员可以自动配置其 Spring 应用程序。但是,Spring Boot 也能够根据你列出的依赖项更改配置。例如,当你将"MySQL"作为依赖项列出时,它将使用包含的"MySQL 连接器"配置您的 Spring 应用程序。无需将应用程序部署到 Web 服务器。只需输入运行命令即可启动应用程序。让我们看看如何创建一个示例春靴应用程序。
打开Spring Boot,使用 Spring 初学者库创建 Java Maven 应用程序。
提供项目组和名称,并在依赖项中添加"Web",并将其他所有内容保留为默认值,这将创建一个使用 Java 和 Spring Boot 的 Maven 项目。这将生成一个 ZIP,该 ZIP 将作为 Maven 项目导入 IDE。
导入应用程序后,创建一个示例终结点以检查应用程序的功能。
在运行应用程序并访问浏览器中的终结点后,将能够看到如下结果:
项目结构:
有文件的简要概述:
ApplianceController:包含所有其余终结点的业务逻辑。
ApplianceRepository :负责在数据库表上提供 CRUD 操作。
ApplianceEntity :指定类是一个实体,并映射到数据库表。
pom. xml:包含应用程序所需的所有依赖项。
application.properties:用于配置 Web 属性和数据库配置。
Dockerfile:Docker 允许用户创建自己的 Docker 映像并在 Docker 中部署它们。要创建您自己的 Docker 映像,我们必须创建自己的 Dockerfile。基本上,Dockerfile 是一个简单的文本文件,其中包含生成映像所需的所有说明
docker-compose.yml:指定应部署哪些服务/容器,并定义容器的映像是如何构建的。
schema.sql:包含用于执行数据库操作的脚本。
让我们通过每个类来演练:
HouseHoldApplication
这是一个弹簧靴主类。Spring Boot REST 应用程序通过此类加载。我们还可以看到,此类是使用注释创建@SpringBootApplication。根据 Spring 文档,注释@SpringBootApplication等效于使用@Configuration、@EnableAutoConfiguration和@ComponentScan,并且这些注释经常一起使用。大多数时候,在 Spring Boot 开发中,主类始终用这三个重要注释进行注释。
我们将修改具有组件@SpringBootApplication(在Java类中给出的)的参数。如果没有这一点,应用程序就无法找出控制器类。
package com.user.household;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.autoconfigure.domain.EntityScan;import org.springframework.cache.annotation.EnableCaching;import org.springframework.context.annotation.ComponentScan;import org.springframework.data.jpa.repository.config.EnableJpaRepositories;import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.persistence.EntityListeners;@SpringBootApplication@EnableTransactionManagement@EnableCaching@ComponentScan(basePackages = {"com.user"})@EntityScan("com.user.model")@EnableJpaRepositories("com.user.repository")public class HouseHoldApplication { public static void main(String[] args) { SpringApplication.run(HouseHoldApplication.class, args); }}
ApplianceController
此类负责创建应用程序所需的 RESTful 终结点,并在单独定义的存储库的帮助下访问数据库。默认情况下@RequestMapping注释映射所有 HTTP 操作,并且在此应用程序中,它确保将 HTTP请求映射到getAllAppliance()方法。正如我们完成了 GET 调用一样,我们需要使用相同的路径实现 RESTful POST 调用。
POST 调用使用户能够在数据库中创建设备或条目。同样,我们需要为更新、搜索和删除操作实现 RESTful 服务。
import org.springframework.web.bind.annotation.*;import javax.validation.Valid;import java.time.LocalDate;import java.util.HashMap;import java.util.List;import java.util.Map;@CrossOrigin(origins = "*", allowedHeaders = "*")@RestController@RequestMapping("/appliances")public class ApplianceController { @Autowired private ApplianceRepository repository; /** * Get the entire list of appliances **/ @GetMapping("/") public List<ApplianceEntity> getAllAppliances() { return repository.findAll(); } /** * Create a new appliance **/ @PostMapping("/") public ApplianceEntity createAppliance(@Valid @RequestBody ApplianceEntity appliance) throws RecordWithSameModelException, RecordWithSameBrandException { return repository.save(appliance); }
ApplianceEntity
这是设备实体。每个实体必须至少定义两个注释:@Entity和@Id。@Entity指定类是实体并映射到数据库表。@Table注释指定要用于映射的数据库表的名称。@Id指定实体的主要键,@GeneratedValue为主键的值指定生成策略。
package com.user.model;import javax.persistence.*;import java.time.LocalDate;import java.util.Date;@Entity@Table(name="HOUSEHOLD")public class ApplianceEntity { @Id @Column @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer serialnumber; @Column(name="brand") private String brand; @Column(name="model") private String model; @Column(name="status") private String status; @Column(name="date") private LocalDate date; public ApplianceEntity() { } public ApplianceEntity(Integer id, String brand, String model, String status,LocalDate date) { super(); this.serialnumber = id; this.brand = brand; this.model = model; this.status = status; this.date=date; } public Integer getSerialnumber() { return serialnumber; } public void setSerialnumber(Integer serialnumber) { this.serialnumber = serialnumber; } public LocalDate getDate() { return date; } public void setDate(LocalDate date) { this.date = date; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public String getModel() { return model; } public void setModel(String model) { this.model = model; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status;
}
}
ApplianceRepository
@Repository注释用于定义存储库。
package com.user.model;import javax.persistence.*;import java.time.LocalDate;import java.util.Date;@Entity@Table(name="HOUSEHOLD")public class ApplianceEntity { @Id @Column @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer serialnumber; @Column(name="brand") private String brand; @Column(name="model") private String model; @Column(name="status") private String status; @Column(name="date") private LocalDate date; public ApplianceEntity() { } public ApplianceEntity(Integer id, String brand, String model, String status,LocalDate date) { super(); this.serialnumber = id; this.brand = brand; this.model = model; this.status = status; this.date=date; } public Integer getSerialnumber() { return serialnumber; } public void setSerialnumber(Integer serialnumber) { this.serialnumber = serialnumber; } public LocalDate getDate() { return date; } public void setDate(LocalDate date) { this.date = date; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public String getModel() { return model; } public void setModel(String model) { this.model = model; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; }}
schema.sql
此文件负责创建数据库条目。
DROP TABLE IF EXISTS HOUSEHOLD;CREATE TABLE HOUSEHOLD(SERIALNUMBER SERIAL PRIMARY KEY NOT NULL, BRAND VARCHAR(30) NOT NULL, MODEL VARCHAR(30) NOT NULL, STATUS VARCHAR(30) NOT NULL, DATE DATE DEFAULT CURRENT_TIMESTAMP); INSERT INTO HOUSEHOLD(BRAND,MODEL,STATUS,DATE) VALUES('samsung','S100','active',NOW());INSERT INTO HOUSEHOLD(BRAND,MODEL,STATUS,DATE) VALUES('samsung','S200','active',NOW());INSERT INTO HOUSEHOLD(BRAND,MODEL,STATUS,DATE) VALUES('LG','L100','inactive',NOW());INSERT INTO HOUSEHOLD(BRAND,MODEL,STATUS,DATE) VALUES('HITACHI','H100','active',NOW());INSERT INTO HOUSEHOLD(BRAND,MODEL,STATUS,DATE) VALUES('samsung','S900','inactive',NOW());INSERT INTO HOUSEHOLD(BRAND,MODEL,STATUS,DATE) VALUES('sony','SS100','active',NOW());INSERT INTO HOUSEHOLD(BRAND,MODEL,STATUS,DATE) VALUES('OGENERAL','O100','active',NOW());
在编写所有业务逻辑并设置终结点后,我们需要按照以下步骤创建应用程序的 JAR。
mvn 干净安装
mvn 清洁包装
因此,创建 JAR 如下所示:
创建 JAR 后,我们需要通过定义以下文件来对应用程序进行 Docker:
Dockerfile
从 openjdk:8表示这是一个 Java 应用程序,需要所有 Java 库。因此,它将提取所有与Java相关的库,并将它们添加到容器中。
复制复制应用程序生成的 JAR 并将其添加到容器中。
Cmd s指出这是一个 Jar, 我们需要从 Docker 内部运行此 Jar 。
FROM openjdk:8-jdk-alpineCOPY target/household-0.0.1-SNAPSHOT.jar /app/app.jarCMD ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar"]
docker-compose.yml
它包含关键字postgres 和 Web,它们定义应用程序的 Web 和数据库部分的服务。
图像关键字用于为我们的postgres和 Web 容器指定来自 Dockerhub 的图像
对于数据库,我们使用端口关键字来提及需要为postgres公开的端口。
最后,我们需要为postgres 指定环境变量,这些变量是运行postgres 所需要的。
version: '3.2'services: postgres: restart: always container_name: sample_db image: postgres:10.4 ports: - '5432:5432' environment: - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_DB=${POSTGRES_DB} # APP** web: build: . environment: SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/test expose: - '8080' ports: - '8080:8080'
现在,我们已经到了一个阶段,我们有以下:
Java = Spring Boot应用程序
将创建要在 Docker 容器中运行的映像的 Dockerfile。
若要在 Docker 容器中加载这些映像,我们必须首先创建映像,然后从 Docker 容器运行该映像。我们需要在包含 Dockerfile 的文件夹中运行某些命令。
这将在 Docker 中创建我们的映像,并将它加载到容器中。
我们已成功构建了可以运行的映像,如下所示:
Spring Boot 应用程序已启动,服务器在端口 8080 上运行。
Spring Boot应用程序从 Docker 容器运行。