I have a circular reference issues in my Spring boot 3 application on one of my service and a Spring boot configuration class and I have no idea to fix it.
I doing a Spring boot migration from version 2 to version 3, and we have a MonitoringService which inject another service but in the another service we dont have any injection. So in fact we should'nt have circular reference between these 2 services.
┌─────┐
| monitoringService defined in URL [jar:file:/C:/dev/sources/project/target/myproject-0.3.0-SNAPSHOT.jar!/BOOT-INF/classes!/com/omb/project/services/MonitoringService.class]
↑ ↓
| healthContributorRegistry defined in class path resource [org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.class]
└─────┘
MonitoringService
package com.omb.services;
import com.omb.restcore.services.HealthCheckSimpleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.health.*;
import org.springframework.stereotype.Component;
@Component
@Endpoint(id = "health")
public class MonitoringService extends HealthEndpoint implements HealthIndicator {
@Autowired
private HealthCheckSimpleService healthCheckSimpleService;
public MonitoringService(HealthContributorRegistry registry, HealthEndpointGroups groups) {
super(registry, groups, null);
}
@Override
public Health getHealth(boolean includeDetails) {
return HealthIndicator.super.getHealth(includeDetails);
}
@Override
public Health health() {
String status = healthCheckSimpleService.healthCheck(null, null).getBody();
if ("RUNNING".equalsIgnoreCase(status)) {
return new Health.Builder(Status.UP).build();
}
return new Health.Builder(Status.DOWN).build();
}
}
HealthService
package com.omb.restcore.services;
import com.omb.restcore.exception.InternalServerException;
import com.omb.restcore.services.utils.HTTPHelper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.logging.Level;
import java.util.logging.Logger;
@CrossOrigin
@RestController
public class HealthCheckSimpleService {
private static final Logger LOG = Logger.getLogger(HealthCheckSimpleService.class.getName());
@Value("${api.healthMessage:API is healthy}")
private String healthMessage;
@Value("${api.maintenanceMessage:API is in maintenance}")
private String maintenanceMessage;
@Value("${apiStatus:RUNNING}")
private Status status;
private static void waitToDiscourageAttacks() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// Spend some time waiting to discourage DOS attacks
throw new RuntimeException(e);
}
}
@RequestMapping(value = "healthCheck", method = RequestMethod.GET)
public ResponseEntity<String> healthCheck(HttpServletRequest request, HttpServletResponse response) {
String message;
if (status == Status.RUNNING) {
message = healthMessage;
} else if (status == Status.MAINTENANCE) {
message = maintenanceMessage;
} else {
throw new InternalServerException("Unsupported status -> " + status);
}
waitToDiscourageAttacks();
return new ResponseEntity<String>(message, HttpStatus.OK);
}
@RequestMapping(value = "status", method = RequestMethod.GET)
public @ResponseBody
Status[] getStatusList(HttpServletRequest request, HttpServletResponse response) {
return Status.values();
}
@RequestMapping(value = "status", method = RequestMethod.PUT, consumes = MediaType.TEXT_PLAIN_VALUE)
public @ResponseBody
Status setStatus(HttpServletRequest request, HttpServletResponse response,
@RequestBody(required = true) String status) {
this.status = Status.valueOf(status);
LOG.log(Level.WARNING, "User " + HTTPHelper.getUserFromAuthentication() + " changed status to " + status
+ " from IP " + HTTPHelper.getRequesterIp(request));
return this.status;
}
private enum Status {
RUNNING, MAINTENANCE
}
}
I fix my issue with the code below