spring-kafka starting another container with #RefreshScope annotation - spring

I am integrating my spring-kafka consumer with spring-cloud. Here is the bean that basically has the #KafkaListener
#ConditionalOnMissingBean
#Bean
#RefreshScope
SinkGenericKafkaConsumer<String, MessageEvent, MessageEntity> sinkGenericKafkaConsumer(final ContainerConfigProperties containerConfigProperties,
DataSource dataSource,
final SinkKafkaConsumerProperties<MessageEvent, MessageEntity> kafkaConsumerProperties) {
return new SinkGenericKafkaConsumer<>(containerConfigProperties, kafkaConsumerProperties, dataSource);
}
So when I make a config change and context gets refreshed I was hoping that since I am using #RefreshScope when beans are refreshed spring-kafka framework will use the new bean that gets created, but it spawns the new bean as a new container so now I have 2 containers which is not the desired thing. May be I am doing something wrong but can't figure out. Also the datasource i am injecting is not getting refreshed even though it has #ConfigurationProperties annotated.

Related

How to initialize the dataSource, transactionManager configuration beans later after the server startup?

I am aware of initializing the dataSource and transactionManager beans. But we have a requirement where at the time of server startup, database may not be available so we don't want to initialize these beans at the time of server startup otherwise we used to see the exception in logs.
We are using #Configuration, #EnableJpaRepositories annotation for managing the persistence context.
Can we achieve such kind of configuration in Spring where we want to initialize the dataSource bean at the time of first API request i.e. lazily?
If you are using Spring boot, can exclude as below
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})

How does spring work when class is not a spring managed bean but an object referred inside is

I have a RestTemplate Bean in a spring application like this
#Bean
public RestTemplate createRT(HttpClient httpClient) {
return new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
}
Note that HttpComponentsClientHttpRequestFactory isn't a spring managed bean.
HttpClient bean is created as follows:
#Bean
public CloseableHttpClient createHttpClient(PoolingHttpClientConnectionManager poolingConnectionManager, RequestConfig rc) throws NoSuchAlgorithmException {
CloseableHttpClient httpClient = HttpClientBuilder
.create()
.setConnectionManager(poolingConnectionManager)
.setDefaultRequestConfig(rc)
.build();
return httpClient;
}
Note that both PoolingHttpClientConnectionManager and RequestConfig are created as spring managed beans.
My question is that in my case, the http client factory object i.e. HttpComponentsClientHttpRequestFactory isn't a spring managed bean but all it's internal objects that it uses to create an HttpClient object for connections are spring managed beans.
So will the HttpClient object that this factory creates going to be a singleton and managed by Spring ? Also would this implementation be considered erroneous in any sense based on the outer object being jvm managed and all inner objects being spring managed ?
I am little confused with it.
There should be no problem with the given snippet with respect to beans lifecycle. You are right that bean HttpComponentsClientHttpRequestFactory will not be Spring managed, but it would still be singleton, because the it is created inside a bean RestTemplate which is singleton. Note that RestTemplate bean would be created with name createRT.
Now coming to the point if it's considered erroneous: Although this is suggested that you should leave the bean and its dependency to be managed by Spring container. But for simple dependencies like in this case, I have seen developers create bean dependencies this way all the time, and everything works just well.
So, if you can, you should make this as a separate bean and let it come as a dependency for bean RestTemplate.

How to get Spring Boot to create a bean validator before creating all the other beans

I'm trying to add a LocalValidatorFactoryBean to an existing Spring Boot web application.
No matter what I have tried (listed in a moment) it only creates the validator after most other beans (verified with both logging and breakpoints), so they never get validated.
Tangentially, I have hibernate-validator on the classpath and am attempting to use javax.validation.constraints on my #Component properties.
Application class has #Configuration, #EnableAutoConfiguration and #ComponentScan({"my.package.**"}).
Adding an application.xml with the bean <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
Adding the above bean to validator.xml and adding #ImportResource("validator.xml")
Adding a new #Bean to the Application class. public Validator validator() { return new LocalValidatorFactoryBean(); }
Adding #Order(Ordered.HIGHEST_PRECEDENCE) to the above #Bean
Adding a BeanValidator #Component to the scanned packages.
And adding #Order to it.
In all cases, the validator is loaded only after FilterRegistrationBean has finished logging its business, but the beans I want to validate have already been created and used in setting up data connections and security for example.
Its been a few years since I've used Spring, but I don't remember these problems when defining everything in an application.xml. Is this just something that spring-boot doesn't support and I should move back to traditional Spring application config?
How can I get it to validate all my beans?
I forgot to make a BeanValidationPostProcessor.

Integrate Mongeez with Spring Boot and Spring Data MongoDB

I want to integrate Mongeez with my Spring Boot application and was wondering how to properly run Mongeez during application startup. Mongeez suggests creating a MongeezRunner bean. However, the challenge is to run Mongeez before any of the Spring Data initialization is happening, specifically, before the MongoTemplate instance is created. This is crucial because there might be changes in the database that prevent the application to start at all (e.g. changing index definitions).
My current approach is to provide the MongoTemplate bean myself, running Mongeez before creating it:
#Bean
public MongoTemplate mongoTemplate(Mongo mongo, MongoDbFactory mongoDbFactory,
MongoConverter converter) throws IOException {
// make sure that Mongeez runs before Spring Data is initialized
runMongeez(mongo);
return new MongoTemplate(mongoDbFactory, converter);
}
private void runMongeez(Mongo mongo) throws IOException {
Mongeez mongeez = new Mongeez();
mongeez.setMongo(mongo);
mongeez.setDbName(mongodbDatabaseName);
mongeez.setFile(new ClassPathResource("/db/migrations.xml"));
mongeez.process();
}
It works, but it feels like a hack. Is there any other way to do this?
After taking a look at Spring Boot's source code, it turns out that this problem isn't anything new. The FlywayAutoConfiguration for example has to make sure that Flyway (a migration tool for SQL-based databases) runs before any EntityManagerFactory beans are created. To achieve this the auto-configuration registers a BeanFactoryPostProcessor that dynamically makes every EntityManagerFactory bean depend on the Flyway bean, thus forcing Spring to create the Flyway bean first.
I solved my problem by creating a Spring Boot starter with a similar auto-configuration for Mongeez: mongeez-spring-boot-starter.

Multiple DataSource beans with Spring Boot Actuator's EndpointAutoConfiguration possible?

I have a spring-boot application that uses several DataSource beans and would still like to use the EndpointAutoConfiguration from spring-boot-actuator that is loaded as part of using the #EnableAutoConfiguration annotation. This doesn't seem possible as there is a DataSource bean injected into EndpointAutoConfiguration to setup the HealthEndpoint bean. Due to the multiple instances of DataSource that exist in my application, a NoUniqueBeanDefinitionException is thrown upon application startup unless I exclude EndpointAutoConfiguration but then I must setup all the other endpoints manually (/env, /metrics, etc).
Is there a better way to do this?
You could mark one of your DataSources as #Primary or you could provide your own HealthIndicator (it's not the endpoint that wants your DataSource but that bean, which is designed to be overridden by just adding one of your own).

Resources