Configuring a DataSource Programmatically in Spring Boot – 在Spring Boot中以编程方式配置一个数据源

最后修改: 2019年 1月 25日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Spring Boot uses an opinionated algorithm to scan for and configure a DataSource. This allows us to easily get a fully-configured DataSource implementation by default.

Spring Boot使用一种有主见的算法来扫描和配置DataSource。这使我们能够在默认情况下轻松地获得一个完全配置好的DataSource实现。

In addition, Spring Boot automatically configures a lightning-fast connection pool, either HikariCPApache Tomcat, or Commons DBCP, in that order, depending on which are on the classpath.

此外,Spring Boot 还会自动配置一个快速的连接池,即HikariCPApache TomcatCommons DBCP,按顺序排列,取决于哪些在classpath上。

While Spring Boot’s automatic DataSource configuration works very well in most cases, sometimes we’ll need a higher level of control, so we’ll have to set up our own DataSource implementation, hence skipping the automatic configuration process.

虽然Spring Boot的自动DataSource配置在大多数情况下效果很好,但有时我们需要更高水平的控制,因此我们必须设置自己的DataSource实现,从而跳过自动配置过程。

In this tutorial, we’ll learn how to configure a DataSource programmatically in Spring Boot.

在本教程中,我们将学习如何在Spring Boot中以编程方式配置一个DataSource

2. The Maven Dependencies

2.Maven的依赖性

Creating a DataSource implementation programmatically is straightforward overall.

以编程方式创建DataSource的实现总体上是直接的

To learn how to accomplish this, we’ll implement a simple repository layer, which will perform CRUD operations on some JPA entities.

为了学习如何实现这一点,我们将实现一个简单的存储库层,它将对一些JPA实体执行CRUD操作。

Let’s take a look at our demo project’s dependencies:

让我们来看看我们的演示项目的依赖性。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>2.4.1</version> 
    <scope>runtime</scope> 
</dependency>

As shown above, we’ll use an in-memory H2 database instance to exercise the repository layer. In doing so, we’ll be able to test our programmatically-configured DataSource, without the cost of performing expensive database operations.

如上所示,我们将使用内存中的H2 数据库实例来行使资源库层。这样一来,我们就能够测试我们以编程方式配置的DataSource,而不需要进行昂贵的数据库操作的成本。

In addition, let’s make sure to check the latest version of spring-boot-starter-data-jpa on Maven Central.

此外,让我们确保检查Maven中心的spring-boot-starter-data-jpa的最新版本。

3. Configuring a DataSource Programmatically

3.以编程方式配置数据源

Now, if we stick with Spring Boot’s automatic DataSource configuration and run our project in its current state, it will work just as expected.

现在,如果我们坚持使用Spring Boot的自动DataSource配置,并在其当前状态下运行我们的项目,它就会像预期的那样工作。

Spring Boot will do all the heavy infrastructure plumbing for us. This includes creating an H2 DataSource implementation, which will be automatically handled by HikariCP, Apache Tomcat, or Commons DBCP, and setting up an in-memory database instance.

Spring Boot将为我们完成所有繁重的基础设施工作。这包括创建一个H2 DataSource实现,这将由HikariCP、Apache Tomcat或Commons DBCP自动处理,并设置一个内存数据库实例。

Additionally, we won’t even need to create an application.properties file, as Spring Boot will provide some default database settings as well.

此外,我们甚至不需要创建一个application.properties文件,因为Spring Boot也会提供一些默认的数据库设置。

As we mentioned before, at times we’ll need a higher level of customization, so we’ll have to programmatically configure our own DataSource implementation.

正如我们之前提到的,有时我们需要更高层次的定制,所以我们必须以编程方式配置我们自己的DataSource实现。

The simplest way to accomplish this is by defining a DataSource factory method, and placing it within a class annotated with the @Configuration annotation:

实现这一目标的最简单方法是定义一个DataSource工厂方法,并将其置于一个带有@Configuration注解的类中。

@Configuration
public class DataSourceConfig {
    
    @Bean
    public DataSource getDataSource() {
        DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
        dataSourceBuilder.driverClassName("org.h2.Driver");
        dataSourceBuilder.url("jdbc:h2:mem:test");
        dataSourceBuilder.username("SA");
        dataSourceBuilder.password("");
        return dataSourceBuilder.build();
    }
}

In this case, we used the convenient DataSourceBuilder class, a non-fluent version of Joshua Bloch’s builder pattern, to programmatically create our custom DataSource object.

在这种情况下,我们使用了方便的DataSourceBuilder类,Joshua Bloch 的构建器模式的非流畅版本,以编程方式创建我们的自定义DataSourceobject

This approach is really nice because the builder makes it easy to configure a DataSource using some common properties. It uses the underlying connection pool as well.

这种方法真的很好,因为构建器使得使用一些常见的属性来配置一个DataSource变得很容易。它也使用底层连接池。

4. Externalizing DataSource Configuration With the application.properties File

4.通过application.properties文件将DataSource配置外部化

Of course, it’s also possible to partially externalize our DataSource configuration. For instance, we could define some basic DataSource properties in our factory method:

当然,也可以将我们的DataSource配置部分外部化。例如,我们可以在工厂方法中定义一些基本的DataSource属性。

@Bean 
public DataSource getDataSource() { 
    DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(); 
    dataSourceBuilder.username("SA"); 
    dataSourceBuilder.password(""); 
    return dataSourceBuilder.build(); 
}

Then we can specify a few additional ones in the application.properties file:

然后我们可以在application.properties文件中指定一些额外的。

spring.datasource.url=jdbc:h2:mem:test
spring.datasource.driver-class-name=org.h2.Driver

The properties defined in an external source, such as the above application.properties file, or via a class annotated with @ConfigurationProperties, will override the ones defined in the Java API.

在外部资源中定义的属性,例如上述application.properties文件,或者通过一个用@ConfigurationProperties注释的类,将覆盖Java API中定义的属性。

It becomes evident that, with this approach, we’ll no longer keep our DataSource configuration settings stored in one single place.

很明显,通过这种方法,我们将不再把我们的DataSource配置设置存储在一个地方

On the other hand, it allows us to keep compile-time and run-time configuration settings nicely separated from each other.

另一方面,它允许我们将编译时和运行时的配置设置很好地分开。

This is really good, as it allows us to easily set a configuration binding point. That way we can include different DataSource settings from other sources, without having to refactor our bean factory methods.

这真的很好,因为它允许我们轻松地设置一个配置绑定点。这样我们就可以包括来自其他来源的不同DataSource设置,而不必重构我们的Bean工厂方法。

5. Testing the DataSource Configuration

5.测试DataSource配置

Testing our custom DataSource configuration is very simple. The whole process boils down to creating a JPA entity, defining a basic repository interface, and testing the repository layer.

测试我们的自定义DataSource配置非常简单。整个过程可以归结为创建一个JPA实体,定义一个基本的资源库接口,并测试资源库层。

5.1. Creating a JPA Entity

5.1.创建JPA实体

Let’s start by defining our sample JPA entity class, which will model users:

让我们从定义我们的JPA实体类开始,它将为用户建模。

@Entity
@Table(name = "users")
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String name;
    private String email;

    // standard constructors / setters / getters / toString
    
}

5.2. A Simple Repository Layer

5.2.一个简单的存储库层

Next we need to implement a basic repository layer, which allows us to perform CRUD operations on instances of the User entity class defined above.

接下来我们需要实现一个基本的存储库层,它允许我们对上面定义的User实体类的实例进行CRUD操作。

Since we’re using Spring Data JPA, we don’t have to create our own DAO implementation from scratch. We simply have to extend the CrudRepository interface to get a working repository implementation:

由于我们使用的是Spring Data JPA,我们不必从头开始创建自己的DAO 实现。我们只需扩展CrudRepository接口,就可以得到一个有效的存储库实现。

@Repository
public interface UserRepository extends CrudRepository<User, Long> {}

5.3. Testing the Repository Layer

5.3.测试存储库层

Lastly, we need to check that our programmatically-configured DataSource is actually working. We can easily accomplish this with an integration test:

最后,我们需要检查我们以编程方式配置的DataSource是否真的在工作。我们可以通过集成测试轻松实现这一目标。

@RunWith(SpringRunner.class)
@DataJpaTest
public class UserRepositoryIntegrationTest {
    
    @Autowired
    private UserRepository userRepository;
   
    @Test
    public void whenCalledSave_thenCorrectNumberOfUsers() {
        userRepository.save(new User("Bob", "bob@domain.com"));
        List<User> users = (List<User>) userRepository.findAll();
        
        assertThat(users.size()).isEqualTo(1);
    }    
}

The UserRepositoryIntegrationTest class is pretty self-explanatory. It simply exercises two of the repository interface’s CRUD methods to persist and find entities.

UserRepositoryIntegrationTest类是不言而喻的。它只是简单地行使了存储库接口的两个CRUD方法来坚持和寻找实体。

Notice that regardless of whether we decide to programmatically configure our DataSource implementation, or split it into a Java config method and the application.properties file, we should always get a working database connection.

请注意,无论我们是决定以编程方式配置我们的DataSource实现,还是将其分割成一个Java配置方法和application.properties文件,我们都应该得到一个工作的数据库连接

5.4. Running the Sample Application

5.4.运行示例应用程序

Finally, we can run our demo application using a standard main() method:

最后,我们可以使用标准的main()方法运行我们的演示应用程序。

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public CommandLineRunner run(UserRepository userRepository) throws Exception {
        return (String[] args) -> {
            User user1 = new User("John", "john@domain.com");
            User user2 = new User("Julie", "julie@domain.com");
            userRepository.save(user1);
            userRepository.save(user2);
            userRepository.findAll().forEach(user -> System.out.println(user);
        };
    }
}

We already tested the repository layer, so we’re sure that our DataSource has been configured successfully. Thus, if we run the sample application, we should see in our console output the list of User entities stored in the database.

我们已经测试了存储库层,所以我们确信我们的DataSource已经配置成功了。因此,如果我们运行示例应用程序,我们应该在控制台输出中看到存储在数据库中的User实体列表。

6. Conclusion

6.结论

In this article, we learned how to configure a DataSource implementation programmatically in Spring Boot.

在这篇文章中,我们学习了如何在Spring Boot中以编程方式配置DataSource实现

As usual, all the code samples shown in this article are available over on GitHub.

像往常一样,本文中显示的所有代码样本都可以在GitHub上找到