无法创建需要来自其他数据库的某些数据的AbstractRoutingDataSource

时间:2013-07-10 01:45:40

标签: spring datasource

我们目前有一个应用程序,它使用具有相同模式的多个数据库。目前,我们正在使用自定义解决方案,根据用户的会话进行切换。这通过

工作
public final class DataSourceProxy extends BasicDataSource {

    ...

    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    if (auth != null && auth.getDetails() instanceof Map) {

        Map<String, String> details = (Map<String, String>) auth.getDetails();
        String targetUrl = details.get("database");

        Connection c = super.getConnection();
        Statement  s = c.createStatement();
        s.execute("USE " + targetUrl + ";");
        s.close();
        return c;
    } else {
        return super.getConnection();
    }
}

现在我们要使用AbstractRoutingDataSource构建解决方案。问题是:

@Component
public class CustomRoutingDataSource extends AbstractRoutingDataSource {
    @Autowired
    Environment env;

    @Autowired
    DbDetailsRepositoy repo;

    public CustomRoutingDataSource() {
        Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
        for(DBDetails dbd : repo.findAll() {
            // create DataSource and put it into the map
        }
        setTargetDataSources(new HashMap<Object, Object>());
    }   

    @Override
    protected Object determineCurrentLookupKey() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && auth.getDetails() instanceof Map) {
            Map<String, String> details = (Map<String, String>) auth.getDetails();
            return details.get("database");
        }
        return null;
    }   
}

在构造函数内部(甚至通过@PostConstruct),我们必须填充targetDataSources Map。但是(!)为此我们需要存储在另一个数据库中的连接细节,该数据库有自己的数据源和实体管理器。

看起来Spring无法确定Bean构造的顺序,或者我可能只是遗漏了一些东西。它在访问存储库时总是给出NullPointerException(btw是JpaRepository)。

我们正在使用Spring 3.2.3,Spring Data,Hibernate 4.2。 Spring和Spring Security的完整注释和Java代码配置。

请帮助我们!

1 个答案:

答案 0 :(得分:1)

Spring当然必须在之前调用构造函数才能填充属性。但这不是Spring的东西,这是基本的Java 101,也是使用现场注入的众多缺点之一。

要避免这种情况,只需将依赖项添加到构造函数中:

@Component
class CustomRoutingDataSource extends AbstractRoutingDataSource {

  @Autowired
  public CustomRoutingDataSource(DbDetailsRepository repo, Environment environment) {
    …
  }
  …
}