Spring Boot actuator trigger method when endpoint called - spring-boot

I am using this spring boot actuator endpoint "actuator/health/readiness". How can I run some methods when this endpoint is hit?
If I create my own controller with the same endpoint naming what will happen?
Thanks

Works in spring 2.7.2
public class CustomReadinessStateHealthIndicator extends ReadinessStateHealthIndicator {
public CustomReadinessStateHealthIndicator(ApplicationAvailability availability) {
super(availability);
}
#Override
public Health getHealth(boolean includeDetails) {
//YOUR CODE
return super.getHealth(includeDetails);
}
}
#AutoConfiguration(before = {AvailabilityHealthContributorAutoConfiguration.class})
public class Configuration {
#Bean("readinessStateHealthIndicator")
#ConditionalOnMissingBean(name = "readinessStateHealthIndicator")
public ReadinessStateHealthIndicator customReadiness(ApplicationAvailability applicationAvailability) {
return new CustomReadinessStateHealthIndicator(applicationAvailability);
}
}

Related

How do you add reactive interceptors to Spring Boot annotated controllers?

I've set up rsocket metrics using rsocket-micrometer on the CLIENT side, by configuring the RSocketConnector with interceptors, like this (Kotlin):
rSocketReqesterBuilder.rsocketConnector { configureConnector(it) }
// ...
private fun configureConnector(rSocketConnector: RSocketConnector) {
rSocketConnector.interceptors { iRegistry ->
// This gives us the rsocket.* counter metrics, like rsocket.frame
iRegistry.forResponder(MicrometerRSocketInterceptor(registry, *localTags.toArray()))
iRegistry.forRequester(MicrometerRSocketInterceptor(registry, *localTags.toArray()))
iRegistry.forConnection(MicrometerDuplexConnectionInterceptor(registry, *localTags.toArray()))
}
}
But on the SERVER side, I'm using an annotated (#MessageMapping) Spring Boot RSocket Controller, like this (Java):
#MessageMapping("replace-channel-controller")
public Flux<TransformResponse> replace(Flux<String> texts) ...
Here, I'm not explicitly in control of the connector.
How do I add interceptors on the server side?
#Configuration
public class RSocketConfig implements RSocketServerCustomizer {
private final MeterRegistry registry;
public RSocketConfig(MeterRegistry registry) {
this.registry = registry;
}
#Override
public void customize(RSocketServer rSocketServer) {
rSocketServer.interceptors(
iRegistry -> {
log.info("Adding RSocket interceptors...");
iRegistry.forResponder(new MicrometerRSocketInterceptor(registry, tags));
iRegistry.forRequester(new MicrometerRSocketInterceptor(registry, tags));
iRegistry.forConnection(new MicrometerDuplexConnectionInterceptor(registry, tags));
}
);
}
}

Spring Boot with javax Event

I try to get spring boot working with cdi events.
I have the following class which fires the event.
#Component
#UIScope
public class Login extends LoginOverlay
{
#Autowired
private UserInfo userInfo;
#Inject
private Event<UpdateCWViewEvent> cwevent;
#PostConstruct
public void init()
{
addLoginListener(new ComponentEventListener<LoginEvent>()
{
#Override
public void onComponentEvent(LoginEvent event)
{
userInfo.login(event.getUsername(), event.getPassword());
if (userInfo.isLoggedIn())
{
setButtonLabel();
close();
cwevent.fire(new UpdateCWViewEvent());
}
}
});
}
}
And in another class the following method
public void update(#Observes(notifyObserver=Reception.IF_EXISTS) UpdateCWViewEvent event)
{
//do something
}
Now I have the following problem. I need an Implementation of javax.enterprise.event.Event. I tried to take weld and use the standard Eventimpl. Now, I tried to configure a Spring Configuration class to tell my application, there is an implementation of my event.
#Configuration
public class Config
{
#Bean
public Event<UpdateCWViewEvent> cwEvent()
{
//return EventImpl.of(injectionPoint, beanManagerImpl);
}
}
I dont know what to do with the injectionPoint and beanManagerImpl. Does anybody of you had the same problem and solved it? Or does anybody have an alternative to fire easy cdi events in a spring boot application?
Thank you very much and stay healthy!

Spring Boot swagger file without UI

I have a simple service built in Spring Boot that has a simple API. I've added the springfox libraries to use swagger and the swagger UI, but I do not want my application to serve the UI also. I just want to get the definition from from /api/v1/api-docs
How do I switch off the UI part? Not adding swagger-ui library as a dependency doesn't remove the UI for some reason.
You can block the UI and return HTTP code 404. Something similar to below
#Controller //note - this is a spring-boot controller, not #RestController
public class HomeController {
#RequestMapping ("/swagger/api/v1/api-docs")
public String home(HttpServletRequest request) {
throw new ResourceNotFoundException(); //Custom Solution
or
throw new NoSuchRequestHandlingMethodException(request);
}
}
#ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
...
}
If you are using Spring Boot
#SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
#Bean
RouterFunction<ServerResponse> routerFunction() {
return route(GET("/swagger"), req ->
ServerResponse.temporaryRedirect("<some 404 page>").build());
}
}

Persisting Spring Cloud Gateway Routes in Database

I am currently using the spring cloud gateway project to build simple api gateway, the plan was to persist the route in mongodb, then refresh, so that the new route can be available. I have done something simple like this to get my route from mongo.
#Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder){
List<CreateAPIRequest> apiRequestList = repository.findAll();
RouteLocatorBuilder.Builder routeLocator = builder.routes();
for (CreateAPIRequest request: apiRequestList) {
routeLocator
.route(r-> {
r.path("/"+request.getProxy().getListenPath())
.filters(f->f.stripPrefix(1))
.uri(request.getProxy().getTargetUrl())
});
}
return routeLocator.build();
}
I was able to create new route in the db, but I am unable to refresh on the fly.
I need to understand how to refresh the routes on the fly.
Thanks
Whenever you wish to update the routes dynamically send a RefreshRoutesEvent. The following component implements the event sending functionality.
#Component
public class GatewayRoutesRefresher implements ApplicationEventPublisherAware {
ApplicationEventPublisher publisher;
#Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
publisher = applicationEventPublisher;
}
public void refreshRoutes() {
publisher.publishEvent(new RefreshRoutesEvent(this));
}
}
Here is a sample showing how to use the component above:
#Autowired
GatewayRoutesRefresher gatewayRoutesRefresher;
...
public void buildRoutes() {
// build your routes basing on your db entries then refresh the routes in gateway
...
gatewayRoutesRefresher.refreshRoutes();
}
You can find a more complete picture of the concept by looking into the following project code: https://github.com/botorabi/HomieCenter
SCG(Spring Cloud Gateway) has been provided RouteDefinitionRepository, you can write your own RouteDefinitionRepository, and implements RouteDefinitionRepository to override getRouteDefinitions method.
You can refer to this class: InMemoryRouteDefinitionRepository
For example:
#Service
public class MongodbDefinitionRepository implements RouteDefinitionRepository {
#Autowired
private RouteConfigDao routeConfigDao;
#Override
public Flux<RouteDefinition> getRouteDefinitions() {
// todo
List<RouteDefinition> routeConfigs = routeConfigDao.findAll();
return Flux.fromIterable(routeConfigs);
}
#Override
public Mono<Void> save(Mono<RouteDefinition> route) {
return route.flatMap(routeDefinition -> {
// todo
return Mono.empty();
});
}
#Override
public Mono<Void> delete(Mono<String> routeId) {
return routeId.flatMap(id -> {
// todo
int delete = routeConfigDao.delete(routeId);
if (delete > 0) {
return Mono.empty();
}
return Mono.defer(() -> Mono.error(new Exception("delete route definition error, routeId:" + routeId)));
});
}
}
How to refresh the routes on the fly
Enable actuator
place this in your application.yml
management:
endpoints:
web:
exposure:
include: gateway
POST http://ip:port/actuator/gateway/refresh
Publish RefreshRoutesEvent
#Service
public class MyPublishBiz implements ApplicationEventPublisherAware {
protected ApplicationEventPublisher publisher;
#Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public Mono<Void> refresh() {
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return Mono.empty();
}
}
I went quickly to the repo and the open issues.
And it seems that at the moment the only way to refresh the routes is from Actuator via:
/actuator/gateway/refresh
You can check the discussion here: https://github.com/spring-cloud/spring-cloud-gateway/issues/43
Can you use Consul for persisting your route definitions instead of mongo. Then a simple POST call to the actuator's refresh will reload your route definitions on the fly.

How to get Spring REST to lead all endpoints with /v1/ after the domain and port?

How do I make a Spring REST service assign a value after the domain and port, but before the mapped endpoint? For example: http://{domain}/v1/...?
Example:
#RestController
#RequestMapping("home")
public class HomeController {
#RequestMapping("number")
public ResponseEntity getNumber() {
return ResponseEntity.ok(1);
}
}
curl http://localhost:8080/v1/home/number ~ 1
Also, is there a name for what I'm trying to achieve?
Assuming you're using Spring Data Rest, you can configure it in the RepositoryRestConfiguration #Configuration class like so:
public class SDRConfig extends RepositoryRestMvcConfiguration {
#Override
public RepositoryRestConfiguration config() {
RepositoryRestConfiguration config = super.config();
config.setBasePath("/v1");
return config;
}
}
Alternatively, with Spring Boot I believe it's
spring.data.rest.baseUri=api

Resources