1. Introduction
1.绪论
In this tutorial, we want to run a Spring Boot application with the popular open-source database PostgreSQL. In a previous article, we looked at Docker Compose to handle multiple containers at once. So instead of installing PostgreSQL as a separate application, we’ll use Docker Compose to run Spring Boot and PostgreSQL.
在本教程中,我们希望通过流行的开源数据库PostgreSQL运行一个Spring Boot应用程序。在之前的文章中,我们研究了Docker Compose,以一次处理多个容器。因此,我们将使用Docker Compose来运行Spring Boot和PostgreSQL,而不是将PostgreSQL作为一个单独的应用程序来安装,。
2. Creating the Spring Boot Project
2.创建Spring Boot项目
Let’s go to the Spring Initializer and create our Spring Boot project. We’ll add the PostgreSQL Driver and Spring Data JPA modules. After we download the resulting ZIP file and extract it to a folder, we can run our new application:
让我们进入Spring Initializer并创建我们的Spring Boot项目。我们将添加PostgreSQL驱动程序和Spring Data JPA模块。在我们下载生成的ZIP文件并将其解压到一个文件夹后,我们就可以运行我们的新应用程序。
./mvnw spring-boot:run
The application fails because it can’t connect to the database:
应用程序失败,因为它无法连接到数据库。
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
3. Dockerfile
3.Docker文件
Before we can start PostgreSQL with Docker Compose, we need to turn our Spring Boot application into a Docker image. The first step is to package the application as a JAR file:
在我们用Docker Compose启动PostgreSQL之前,我们需要把我们的Spring Boot应用变成一个Docker镜像。第一步是将应用程序打包成一个JAR文件。
./mvnw clean package -DskipTests
Here, we first clean-up our previous builds before packaging the application. In addition, we skip the tests because they fail without PostgreSQL.
在这里,在打包应用程序之前,我们首先清理了我们以前的构建。此外,我们跳过测试,因为没有PostgreSQL的话,测试会失败。
We now have an application JAR file in the target directory. That file has the project name and version number in its name and ends with -SNAPSHOT.jar. So its name could be docker-spring-boot-postgres-0.0.1-SNAPSHOT.jar.
现在我们在target目录下有一个应用程序JAR文件。该文件的名称中有项目名称和版本号,以-SNAPSHOT.jar结尾。所以它的名字可以是docker-spring-boot-postgres-0.0.1-SNAPSHOT.jar。
Let’s make the new src/main/docker directory. After that, we copy the application JAR file there:
让我们建立新的 src/main/docker目录。之后,我们把应用程序的JAR文件复制到那里。
cp target/docker-spring-boot-postgres-0.0.1-SNAPSHOT.jar src/main/docker
Finally, we create this Dockerfile in that same directory:
最后,我们在同一目录下创建这个Dockerfile。
FROM adoptopenjdk:11-jre-hotspot
ARG JAR_FILE=*.jar
COPY ${JAR_FILE} application.jar
ENTRYPOINT ["java", "-jar", "application.jar"]
This file describes how Docker should run our Spring Boot application. It uses Java 11 from AdoptOpenJDK and copies the application JAR file to application.jar. It then runs that JAR file to start our Spring Boot application.
该文件描述了Docker应如何运行我们的Spring Boot应用程序。它使用来自AdoptOpenJDK的Java 11,并将应用程序JAR文件复制到application.jar。然后它运行该JAR文件来启动我们的Spring Boot应用程序。
4. Docker Compose File
4.Docker编排文件
Now let’s write our Docker Compose file, docker-compose.yml, and save it in src/main/docker:
现在让我们编写我们的Docker Compose文件,docker-compose.yml,并将其保存在src/main/docker。
version: '2'
services:
app:
image: 'docker-spring-boot-postgres:latest'
build:
context: .
container_name: app
depends_on:
- db
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/compose-postgres
- SPRING_DATASOURCE_USERNAME=compose-postgres
- SPRING_DATASOURCE_PASSWORD=compose-postgres
- SPRING_JPA_HIBERNATE_DDL_AUTO=update
db:
image: 'postgres:13.1-alpine'
container_name: db
environment:
- POSTGRES_USER=compose-postgres
- POSTGRES_PASSWORD=compose-postgres
Our application’s name is app. It’s the first of two services (lines 4-15):
我们的应用程序的名字是app。它是两个服务中的第一个(第4-15行)。
- The Spring Boot Docker image has the name docker-spring-boot-postgres:latest (line 5). Docker builds that image from the Dockerfile in the current directory (lines 6-7)
- The container name is app (line 8). It depends on the db service (line 10). That’s why it starts after the db container
- Our application uses the db PostgreSQL container as the data source (line 12). The database name, the user name, and the password are all compose-postgres (lines 12-14)
- Hibernate will automatically create or update any database tables needed (line 15)
The PostgreSQL database has the name db and is the second service (lines 17-22):
PostgreSQL数据库的名称为db,是第二个服务(第17-22行)。
- We use PostgreSQL 13.1 (line 18)
- The container name is db (line 19)
- The user name and password are both compose-postgres (lines 21-22)
5. Running with Docker Compose
5.使用Docker Compose运行
Let’s run our Spring Boot application and PostgreSQL with Docker Compose:
让我们用Docker Compose运行我们的Spring Boot应用程序和PostgreSQL。
docker-compose up
Firstly, this will build the Docker Image for our Spring Boot application. Next, it will start a PostgreSQL container. Finally, it will launch our application Docker image. This time, our application runs fine:
首先,这将为我们的Spring Boot应用程序建立Docker Image。接下来,它将启动一个PostgreSQL容器。最后,它将启动我们的应用程序Docker镜像。这一次,我们的应用程序运行良好。
Starting DemoApplication v0.0.1-SNAPSHOT using Java 11.0.9 on f94e79a2c9fc with PID 1 (/application.jar started by root in /)
[...]
Finished Spring Data repository scanning in 28 ms. Found 0 JPA repository interfaces.
[...]
Started DemoApplication in 4.751 seconds (JVM running for 6.512)
As we can see, Spring Data found no repository interface. That is correct – we didn’t create one yet!
我们可以看到,Spring Data没有发现存储库接口。这是正确的–我们还没有创建一个!
If we want to stop all containers, we need to press [Ctrl-C] first. Then we can stop Docker Compose:
如果我们想停止所有的容器,我们需要先按[Ctrl-C]。然后我们就可以停止Docker Compose了。
docker-compose down
6. Creating a Customer Entity and Repository
6.创建一个客户实体和存储库
To use the PostgreSQL database in our application, we’ll create a simple customer entity:
为了在我们的应用程序中使用PostgreSQL数据库,我们将创建一个简单的客户实体。
@Entity
@Table(name = "customer")
public class Customer {
@Id
@GeneratedValue
private long id;
@Column(name = "first_name", nullable = false)
private String firstName;
@Column(name = "last_name", nullable = false)
private String lastName;
The Customer has a generated id attribute and two mandatory attributes: firstName and lastName.
客户有一个生成的id属性和两个强制属性。firstName和lastName。
Now, we can write the repository interface for this entity:
现在,我们可以为这个实体编写存储库接口。
public interface CustomerRepository extends JpaRepository<Customer, Long> { }
By simply extending JpaRepository, we inherit methods for creating and querying our Customer entity.
通过简单地扩展JpaRepository,我们继承了用于创建和查询Customer实体的方法。
Finally, we’ll use these methods in our application:
最后,我们将在我们的应用程序中使用这些方法。
@SpringBootApplication
public class DemoApplication {
@Autowired
private CustomerRepository repository;
@EventListener(ApplicationReadyEvent.class)
public void runAfterStartup() {
List allCustomers = this.repository.findAll();
logger.info("Number of customers: " + allCustomers.size());
Customer newCustomer = new Customer();
newCustomer.setFirstName("John");
newCustomer.setLastName("Doe");
logger.info("Saving new customer...");
this.repository.save(newCustomer);
allCustomers = this.repository.findAll();
logger.info("Number of customers: " + allCustomers.size());
}
}
- We access our Customer repository through dependency injection
- We query the number of existing customers with the repository — this will be zero
- Then we create and save a customer
- When we then query the existing customers again, we expect to find the one we just created
7. Running with Docker Compose Again
7.再次使用Docker Compose运行
To run the updated Spring Boot application, we need to rebuild it first. Therefore, we execute these commands once more in the project root directory:
为了运行更新的Spring Boot应用程序,我们需要首先重建它。因此,我们在项目根目录下再执行一次这些命令。
./mvnw clean package -DskipTests
cp target/docker-spring-boot-postgres-0.0.1-SNAPSHOT.jar src/main/docker
How do we rebuild our Docker image with this updated application JAR file? The best way is to remove the existing Docker image whose name we specified in the docker-compose.yml. This forces Docker to build the image again the next time we start our Docker Compose file:
我们如何用这个更新的应用程序JAR文件重建我们的Docker镜像?最好的方法是删除现有的Docker镜像,其名称是我们在docker-compose.yml中指定的。这将迫使Docker在我们下次启动Docker Compose文件时重新构建镜像。
cd src/main/docker
docker-compose down
docker rmi docker-spring-boot-postgres:latest
docker-compose up
So after stopping our containers, we delete the application Docker image. We then start our Docker Compose file again, which rebuilds the application image.
所以在停止我们的容器后,我们删除应用程序的Docker镜像。然后我们再次启动我们的Docker Compose文件,重建应用程序的镜像。
Here’s the application output:
下面是应用程序的输出。
Finished Spring Data repository scanning in 180 ms. Found 1 JPA repository interfaces.
[...]
Number of customers: 0
Saving new customer...
Number of customers: 1
Spring Boot finds our empty customer repository. Therefore, we start with no customer but then successfully create one.
Spring Boot发现我们的空客户库。因此,我们开始时没有客户,但后来成功创建了一个。
8. Conclusion
8.结语
In this short tutorial, we started by creating a Spring Boot application for PostgreSQL. Next, we wrote a Docker Compose file to run our application container with a PostgreSQL container.
在这个简短的教程中,我们首先为PostgreSQL创建了一个Spring Boot应用程序。接下来,我们写了一个Docker Compose文件,让我们的应用容器与PostgreSQL容器一起运行。
Finally, we created a customer entity and repository, which allowed us to save a customer to PostgreSQL.
最后,我们创建了一个客户实体和存储库,这使我们能够将客户保存到PostgreSQL中。
As usual, the source code for this tutorial can be found over on GitHub.
像往常一样,本教程的源代码可以在GitHub上找到超过。