Spring 使用基于会话的数据源启动
Spring Boot with session-based data source
我一直在为 web 应用程序的一个非常常见的用例而烦恼。我有一个 Spring-Boot 应用程序,它使用 REST 存储库、JPA 等。问题是我有两个数据源:
- 包含用户认证信息的嵌入式H2数据源
- MySQL 特定于经过身份验证的用户的实际数据的数据源
因为第二个数据源特定于经过身份验证的用户,所以我尝试使用 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 中是必需的。
我一直在为 web 应用程序的一个非常常见的用例而烦恼。我有一个 Spring-Boot 应用程序,它使用 REST 存储库、JPA 等。问题是我有两个数据源:
- 包含用户认证信息的嵌入式H2数据源
- MySQL 特定于经过身份验证的用户的实际数据的数据源
因为第二个数据源特定于经过身份验证的用户,所以我尝试使用 AbstractRoutingDataSource 在身份验证后根据 Principal 用户路由到正确的数据源。
绝对让我发疯的是 Spring-Boot 正在竭尽全力在启动时实例化此数据源。我已经尝试了所有我能想到的方法,包括 Lazy 和 Scope 注释。如果我使用 Session 范围,应用程序会抛出一个关于启动时不存在会话的错误。 @Lazy 似乎根本没有帮助。无论我使用什么注解,数据库都是在 Spring Boot 启动时实例化的,并且没有找到任何导致整个应用程序崩溃的查找键。
另一个问题是 Rest Repository API 让 IMO 无法指定要使用的实际数据源。如果您有多个带有 Spring Boot 的数据源,您必须处理 Qualifier 注释,这是运行时调试的噩梦。
如有任何建议,我们将不胜感激。
您的问题出在身份验证管理器配置上。所有示例和指南都在 GlobalAuthenticationConfigurerAdapter
中进行了设置,例如它看起来像你的 SimpleEmbeddedSecurityConfiguration
:
@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 中是必需的。