Home > OS >  Multiple instances of a bean of one class filled with values from application.properties
Multiple instances of a bean of one class filled with values from application.properties

Time:10-15

I intend to write some HealtCheckContributors for a Spring Boot application using spring-boot-actuator. Hence, I implemented two of them. they are intended for checking the health of different apps, of course, but have a nearly identical structure, except the configuration properties, ...

SonarQube complains about that and I wonder if it is possible to have a single health check class but instantiated as many times as defined in application.properties. An example:

application.properties:

# actuator
app1.management.baseUrl=http://localhost:10000
app1.management.name=app1HealthCheckContributor
app2.management.basUrl=http://localhost:10001
app2.management.name=app2HealthCheckContributor

HealthCheckContributor for app1:

@Slf4j
@Component("xxx")
public class App1HealthCheckContributor extends AbstractHealthIndicator {

    private final App1Properties app1Properties;

    public App1HealthCheckContributor(final App1Properties app1Properties) {
        this.app1Properties = app1Properties;
    }

    @Override
    protected void doHealthCheck(Health.Builder builder) {...}
}

...and this code for each HealthCheckContributor only distinct in its appXProperties.

Isn't it possible to have some kind of base class like:

@Slf4j
@Component()
public class MyHealthCheckContributor extends AbstractHealthIndicator {

    private final MyProperties myProperties;

    public MyHealthCheckContributor(final MyProperties myProperties) {
        this.myProperties = myProperties;
    }

    @Override
    protected void doHealthCheck(Health.Builder builder) {...}
}

and let Spring Boot take care of instantiating two HealthCheckContributors (in our case App1HealthCheckContributor and App2HealthCheckContributor)? This would eliminate code duplication.

An example of the properties class file:

@Slf4j
@Data
@ConfigurationProperties(prefix = "app1.management")
public class App1Properties {
    private String baseUrl;
    private String ...;
}

How can I achieve this and how must an application.properties file looks like to achieve what I intend to do?

I found How To Instantiatiate Multiple Beans Dinamically in Spring-Boot Depending on Configuration-Properties but (to be honest) I barely understand that.

CodePudding user response:

Assuming the code in doHealthCheck is exactly the same for all apps to be checked you could do the following.

You would start by creating a single health check class:

@Slf4j
public class AppHealthCheckContributor extends AbstractHealthIndicator {

    private final AppProperties appProperties;

    public App1HealthCheckContributor(final AppProperties appProperties) {
        this.appProperties = appProperties;
    }

    @Override
    protected void doHealthCheck(Health.Builder builder) {...}
}

And the properties model as follows:

@Slf4j
@Data
public class AppProperties {
    private String baseUrl;
    private String name;
}

This means that the configuration would be something like the following (in application.yml):

health-check:
  apps:
    - baseUrl: http://localhost:10000
      name: app1
    - baseUrl: http://localhost:10001
      name: app2

Finally, you would need to create a bean for each app and register them in the application context:

@Slf4j
@Data
@Configuration
@ConfigurationProperties(prefix = "health-check")
public class AllAppPropertiesConfiguration {
    private List<AppProperties> apps;

    @Autowired
    private GenericApplicationContext applicationContext;

    @PostConstruct
    fun init() {
        for (AppProperties app : apps) {
            applicationContext.registerBean(app.getName(), AppHealthCheckContributor.class, app);
        }
    }
}
  • Related