带有基于会话的数据源的Spring Boot [英] Spring Boot with session-based data source

查看:121
本文介绍了带有基于会话的数据源的Spring Boot的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在整理应该是Web应用程序的一个非常常见的用例.我有一个使用REST信息库,JPA等的Spring-Boot应用程序.问题是我有两个数据源:

  • 包含用户身份验证信息的嵌入式H2数据源
  • MySQL数据源,用于特定于已验证用户的实际数据

由于第二个数据源特定于经过身份验证的用户,因此我尝试使用AbstractRoutingDataSource根据身份验证后的主要用户路由到正确的数据源.

绝对让我发疯的是,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,那么在创建安全过滤器(甚至在@Primary DataSource bean尚未注册之前)期间,Spring Data REST就会使用DataSource初始化开始得太早了(不好的主意).

更新:认证管理器不是唯一的问题.如果您需要具有会话范围的@Primary DataSource(我会说这很不正常),则需要在启动时关闭所有想要访问数据库的内容(Hibernate和Spring Boot在各个地方).示例:

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中是必需的.

I've been tearing my hair out with what should be a pretty common use case for a web application. I have a Spring-Boot application which uses REST Repositories, JPA, etc. The problem is that I have two data sources:

  • Embedded H2 data source containing user authentication information
  • MySQL data source for actual data which is specific to the authenticated user

Because the second data source is specific to the authenticated user, I'm attempting to use AbstractRoutingDataSource to route to the correct data source according to Principal user after authentication.

What's absolutely driving me crazy is that Spring-Boot is fighting me tooth and nail to instantiate this data source at startup. I've tried everything I can think of, including Lazy and Scope annotations. If I use Session scope, the application throws an error about no session existing at startup. @Lazy doesn't appear to help at all. No matter what annotations I use, the database is instantiated at startup by Spring Boot and doesn't find any lookup key which essentially crashes the entire application.

The other problem is that the Rest Repository API has IMO a terrible means of specifying the actual data source to be used. If you have multiple data sources with Spring Boot, you have to juggle Qualifier annotations which is a runtime debugging nightmare.

Any advice would be very much appreciated.

解决方案

Your problem is with the authentication manager configuration. All the samples and guides set this up in a GlobalAuthenticationConfigurerAdapter, e.g. it would look like this as an inner class of your 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());
    }
}

If you don't use GlobalAuthenticationConfigurerAdapter then the DataSource gets picked up by Spring Data REST during the creation of the Security filters (before the @Primary DataSource bean has even been registered) and the whole JPA initialization starts super early (bad idea).

UPDATE: the authentication manager is not the only problem. If you need to have a session-scoped @Primary DataSource (pretty unusual I'd say), you need to switch off everything that wants access to the database on startup (Hibernate and Spring Boot in various places). Example:

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

FURTHER UPDATE: if you're using the Actuator it also wants to use the primary data source on startup for a health indicator. You can override that by prividing a bean of the same type, e.g.

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

P.S. I believe the GlobalAuthenticationConfigurerAdapter might not be necessary in Spring Boot 1.2.2, but it is in 1.2.1 or 1.1.10.

这篇关于带有基于会话的数据源的Spring Boot的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆