Can't create an AbstractRoutingDataSource that needs some data from another database

大憨熊 提交于 2019-12-11 10:54:59

问题


We currently have an application which uses multiple databases with the same schema. At the moment we're using a custom solution for switching between them based on the user's session. This works via

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();
    }
}

Now we want to build a solution using AbstractRoutingDataSource. The problem is:

@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;
    }   
}

Inside the constructor (or even via @PostConstruct) we have to fill the targetDataSources Map. But(!) for this we need the connection details which are stored in another database, which has its own DataSource and Entity Manager.

It seems like Spring can't determine the order of Bean construction, or maybe I'm just missing something. It always gives a NullPointerException when accessing the repository (which btw is a JpaRepository).

We're using Spring 3.2.3, Spring Data, Hibernate 4.2. Complete Annotation and Java-Code configuration of Spring and Spring Security.

Please help us!


回答1:


Spring of course has to call the constructor before it can populate the properties. But that's not a Spring thing, that's basic Java 101 and one of the plenty downsides of using field injection.

To avoid this, simply add your dependencies to the constructor:

@Component
class CustomRoutingDataSource extends AbstractRoutingDataSource {

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


来源:https://stackoverflow.com/questions/17561183/cant-create-an-abstractroutingdatasource-that-needs-some-data-from-another-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!