Spring 使用基于会话的数据源启动

Spring Boot with session-based data source

我一直在为 web 应用程序的一个非常常见的用例而烦恼。我有一个 Spring-Boot 应用程序,它使用 REST 存储库、JPA 等。问题是我有两个数据源:

因为第二个数据源特定于经过身份验证的用户,所以我尝试使用 AbstractRoutingDataSource 在身份验证后根据 Principal 用户路由到正确的数据源。

绝对让我发疯的是 Spring-Boot 正在竭尽全力在启动时实例化此数据源。我已经尝试了所有我能想到的方法,包括 Lazy 和 Scope 注释。如果我使用 Session 范围,应用程序会抛出一个关于启动时不存在会话的错误。 @Lazy 似乎根本没有帮助。无论我使用什么注解,数据库都是在 Spring Boot 启动时实例化的,并且没有找到任何导致整个应用程序崩溃的查找键。

另一个问题是 Rest Repository API 让 IMO 无法指定要使用的实际数据源。如果您有多个带有 Spring Boot 的数据源,您必须处理 Qualifier 注释,这是运行时调试的噩梦。

如有任何建议,我们将不胜感激。

您的问题出在身份验证管理器配置上。所有示例和指南都在 GlobalAuthenticationConfigurerAdapter 中进行了设置,例如它看起来像你的 SimpleEmbeddedSecurityConfiguration:

的内部 class
@Configuration
public static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter
{
    @Bean(name = Global.AUTHENTICATION_DATA_QUALIFIER + "DataSource")
    public DataSource dataSource()
    {
        return new EmbeddedDatabaseBuilder().setName("authdb").setType(EmbeddedDatabaseType.H2).addScripts("security/schema.sql", "security/data.sql").build();
    }

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception
    {
            auth.jdbcAuthentication().dataSource(dataSource()).passwordEncoder(passwordEncoder());
    }
}

如果您不使用 GlobalAuthenticationConfigurerAdapter,则 DataSource 会在创建安全过滤器期间(在 @Primary DataSource bean 甚至已经注册)并且整个 JPA 初始化开始得非常早(坏主意)。

更新:身份验证管理器不是唯一的问题。如果你需要一个会话范围的 @Primary DataSource(我会说这很不寻常),你需要在启动时关闭所有想要访问数据库的东西(Hibernate 和 Spring在不同的地方启动)。示例:

spring.datasource.initialize: false
spring.jpa.hibernate.ddlAuto: none
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults: false
spring.jpa.properties.hibernate.dialect: H2

进一步更新:如果您使用执行器,它还希望在启动时使用主数据源作为运行状况指示器。您可以通过提供相同类型的 bean 来覆盖它,例如

@Bean
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
@Lazy
public DataSourcePublicMetrics dataSourcePublicMetrics() {
    return new DataSourcePublicMetrics();
}

P.S。我相信 GlobalAuthenticationConfigurerAdapter 在 Spring Boot 1.2.2 中可能不是必需的,但它在 1.2.1 或 1.1.10 中是必需的。