Spring @Component在@PostConstruct完成之前可用

时间:2019-02-08 12:20:43

标签: java spring spring-boot dependency-injection

我正在将Spring Boot 2.0.3用于REST应用程序。我的情况很奇怪。

我有这个界面:

public interface ConnectionPoolManager {

    public Connection getConnection(@NotNull String tenantId, boolean longTask);

    public DataSource getDataSource(@NotNull String tenantId, boolean longTask);
}

及其实现:

@Component
@Profile({"prod"})
public class ConnectionPoolManagerImpl implements ConnectionPoolManager {
    private Logger log = LogManager.getLogger();

    private Map<String, DataSource> dataSourceMap = new ConcurrentHashMap<String, DataSource>();


    private Map<String, DataSource> dataSourceLongConnectionsMap = new ConcurrentHashMap<String, DataSource>();

    private Map<String, String> tenantDatabaseInstanceMap = new ConcurrentHashMap<String, String>();

    @Autowired
    private TenantRestClient tenantRestClient;

    @Autowired
    private PasswordEncrypt passwordEncrypt;

    @Autowired
    private Environment env;

    @Autowired
    private DataSource primaryDataSource;

    /**
     * At application startup we cache connection to all DB instances
     */
    @PostConstruct
    public void init() {
        try {
            log.info("Caching datasource connections...");
            Set<String> databaseIds = tenantRestClient.findDatabaseInstanceIds();
            //Creating datasource and caching them for later
            databaseIds.forEach(s -> getLocalCache(false).put(s, createDataSource(s, false)));
            databaseIds.forEach(s -> getLocalCache(true).put(s, createDataSource(s, true)));
            log.info("Cached {} datasources", dataSourceMap.size());
        } catch (Exception e) {
            log.warn("Error trying to cache datasources.", e);
        }
    }

在这堂课中,我打电话给tenantRestClient.findDatabaseInstanceIds(),这就是问题所在。

@Component
public class TenantRestClient {
    private Logger log = LogManager.getLogger();

    @Autowired
    private RestTemplateBuilder restTemplateBuilder;

    private RestTemplate restTemplate;

    @PostConstruct
    public void init() {
        log.debug("------------INIT--------");
        restTemplate = restTemplateBuilder.build();
        log.debug("Post construct {} - {}", restTemplateBuilder, restTemplate);
        log.debug("------------INIT COMPLETED --------");
    }

  public Set<String> findDatabaseInstanceIds() {
           //my logic here

            ResponseEntity<Set<String>> response = restTemplate.exchange(uriBuilder.toUriString(), HttpMethod.GET, entity, new ParameterizedTypeReference<Set<String>>() {
            });

        }
    }

实际上,在调用init()之前先调用findDatabaseInstanceIds()方法。当然,然后我会有一个NullPointerException,因为restTemplate为null。

如何使bean tenantRestClient准备就绪并且可以在调用init()方法之前调用一个方法?

2 个答案:

答案 0 :(得分:3)

您需要创建一个带有RestTemplate bean的Configuration类,并将其自动装配到您的类中。

X = getSet() \\ Get the set of 2D points
H = convexHull(X) \\ Compute the convex hull
while |H| > n do
    n_max = 0
    for h in H:
        H_ = remove(h,H) \\ Remove one point of the convex hull
        n_c = computeCoverage(X,H_) \\ Compute the coverage of the modified convex hull.
        \\ Save which point can be removed such that the coverage is reduced minimally.
        if n_c > n_max:
            n_max = n_c
            h_toremove = h
    \\ Remove the point and recompute the convex hull.
    X = remove(h,X)
    H = convexHull(X)

这将为您的项目创建restTemplate bean。如果您需要多个RestTemplate,请查看@Qualifier。
现在,您可以在类中自动连接RestTemplate。无需PostConstruct

@Configuration
public class Config



@Bean
public RestTemplate restTemplate(){
  return restTemplateBuilder.build();

}

答案 1 :(得分:0)

在这里,您可以使用@DependsOn注释,让您控制Bean的创建顺序

spring @DependsOn

您可以标记从属bean类,即 具有@DependsOn的ConnectionPoolManagerImpl