Spring Boot Jersey and Monitoring URL's - spring

We have a simple Spring Boot application with Jersey.
Spring Boot provides default monitoring end points
http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#production-ready-monitoring
Example:
#Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
// registering resources from rest package
packages("com.xyx.abc.rest");
}
}
The REST end points that are provided by Spring Boot are not available in the context of a Spring Boot Jersey Application.
The Spring Boot dependency includes Jersey, starter-actuator, starter-tomcat.
Our REST resources show up fine, but the ones provided by Spring Boot for monitoring dont show up.
E.g http://abc.xyx.com:8080/health returns a 404

If you are using it as a Filter you need to tell Jersey not to handle those requests. E.g. by putting the Jersey resources under a separate path, like "/api/*" or something:
#Bean
public FilterRegistrationBean jersey() {
FilterRegistrationBean bean = new FilterRegistrationBean();
...
bean.setUrlPatterns(Lists.newArrayList("/api/*"));
return bean;
}
(from here).
Or by declaring that your admin endpoints are "static" (via another init parameter "com.sun.jersey.config.property.WebPageContentRegex"):
#Bean
public FilterRegistrationBean jersey() {
FilterRegistrationBean bean = new FilterRegistrationBean();
...
bean.addInitParameter("com.sun.jersey.config.property.WebPageContentRegex",
"/admin/.*");
return bean;
}
where we have set management.contextPath=/admin in the Spring Boot external configuration (otherwise you'd have to enumerate all the endpoints in the regex).
You can also tell Jersey to ignore unresolved requests (instead of sending a 404). That would also achieve your goal, but might affect your client apps (if they rely on a 404 for their behaviour).

Related

How to get webflux webClient metrics from custom Webclient Builder

I have created a custom Webclient Builder instead of injecting the default builder.
#Configuration
public class WebClientConfig() {
#Bean(name = "myWebClientBuilder")
public Webclient.Builder customBuilder() {
return WebClient.builder();
}
}
I have multiple services where I use this bean myWebClientBuulder and do further customization with chain of ExchangeFilterFunction.
This might not be the recommended way of using the WebClient but I would like to get some insight if there is a way to get the downstream call metrics from the Webclient based on this configuration.
Actuator Endpoint: actuator/metrics/http.client.requests
Spring Boot auto-configured WebClient.Builder is way powerful than customized version.
I tried to configure the custom builder in WebClientConfig() but it started to structure just like a copy version of WebClientAutoConfiguration. I ended up going with the spring boot autoconfigured WebClient.Builder bean.
If it helps, you can study how WebClientAutoConfiguration tries to configure webClient customizers. For metrics, it would be MetricsWebClientCustomizer.

Spring Boot metrics http.client.requests do not work for WebClient reactive applications

I have a spring boot 2.2.2 microservices, which integrations with other services using WebClient (rective). According to Spring documentation, the actuator should return "http.client.requests" metrics by default as Timer is enabled by default. But it does not work for me. I am able to get http.server.requests" metrics.
My WebClient is a bean configured and build with WebClient.builder(), as documented here: https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-metrics-http-clients
Use Spring Boot's preconfigured WebClient.Builder instead of WebClient.builder() to have an instance of WebClient.
You can find more detail here.
As in the following you can have a bean of WebClient.
#Configuration
public class ClientConfiguration {
#Bean
public WebClient webClient(WebClient.Builder webClientBuilder) {
return webClientBuilder
.baseUrl("https://example.org")
.build();
}
}
WebClient.Builder is an Auto-configuration, means the injected point above will receive a newly cloned instance of the builder.
Here is the source for WebClientAutoConfiguration
I've noticed my application has to make a WebClient call before the metrics/http.client.requests endpoint exists. Prior to my application making a WebClient call that endpoint isn't discoverable and returns NOT FOUND.
Hope that helps others in a similar situation!

What Is the Correct Way To Use AbstractReactiveWebInitializer

I've got a Spring WebFlux application running successfully as a standalone spring boot application.
I am attempting to run the same application in a Tomcat container, and following the documentation, I've created a class that extends AbstractReactiveWebInitializer. The class requires that I implement a method getConfigClasses that would return classes normally annotated with #Configuration. If the working spring boot app started with a class called ApplicationInitializer, then the resulting implementations would look like this:
#SpringBootApplication(scanBasePackages = "my.pkg")
#EnableDiscoveryClient
#EnableCaching
public class ApplicationInitializer {
public static void main(String... args) {
SpringApplication.run(ApplicationInitializer.class, args);
}
}
and
public class ServletInitializer extends AbstractReactiveWebInitializer {
#Override
protected Class<?>[] getConfigClasses() {
return new Class[] {ApplicationInitializer.class};
}
}
When deployed, the only thing that starts is ApplicationInitializer, none of the autoconfigured Spring Boot classes (Cloud Config, DataSource, etc) ever kick off.
The documenation states this is the class I need to implement, I just expected the remainder of the spring environment to "just work".
How should I be using this class to deploy a Reactive WebFlux Spring Boot application to a Tomcat container ?
Edit:
After some additional research, I've narrowed it down to likely just Cloud Config. During bean post processing on startup, the ConfigurationPropertiesBindingPostProcessor should be enriched with additional property sources (from cloud config), but it appears to be the default Spring properties instead, with no additional sources.
The misisng properties is causing downstream beans to fail.
Spring Boot does not support WAR packaging for Spring WebFlux applications.
The documentation you're referring to is the Spring Framework doc; Spring Framework does support that use case, but without Spring Boot.
you can extend SpringBootServletInitializer, add add reactive servlet on onStartup method

How to register resource with javax.ws.rs.core.Applicaiton in spring-boot-starter-jersey powered REST application

In my spring boot application (powered by spring-boot-starter-jersey):
I can easily make a resource config (jersey way but not jaxrs way) like this:
#Configuration
#ApplicationPath("/sample")
public class SampleResourceConfig extends ResourceConfig {
And I just want to try with javax.ws.rs.core.Applicaiton:
#Configuration
#ApplicationPath("/sample")
public class SampleResourceConfig extends javax.ws.rs.core.Applicaiton{
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(SampleResource.class);
return classes;
}
But no lucky, it does not work.
Did I miss something?
Thanks
Leon
It won't work as the Spring Boot auto-configuration is made specifically to look for a bean of type ResourceConfig, not Application. If you want to use Application, you can't use the auto-configuration. You'll need to just create the JAX-RS servlet yourself and register it with a Spring Boot ServletRegistratiobBean, similar to what you'll see in the source code I linked to.

JAX-RS - Spring Boot vs without Spring Boot

I want to use Spring boot with JAX-RS (Jersey Implementation). If we were not using Spring Boot, we could use the following code to register all the Rest service classes
#ApplicationPath("/myrest")
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(HelloWorld.class);
return s;
}
}
This works fine in a Servlet 3.0 supported container.
But when we use Spring Boot with JAX-RS(Jersey) why do we have to extend from org.glassfish.jersey.server.ResourceConfig Why extending from javax.ws.rs.core.Application doesn't work?
But when we use Spring Boot with JAX-RS(Jersey) why do we have to extend from org.glassfish.jersey.server.ResourceConfig Why extending from javax.ws.rs.core.Application doesn't work?
Because Spring Boot uses the ResourceConfig type as the as a service that it injects into its auto configurer, namely the JerseyAutoConfiguration. If you look at the source code, you will see
#Autowired
private ResourceConfig config;
From there, Sprig Boot configures the app with that instance. If a ResourceConfig bean is not available in the Spring context, then not auto-configuration happens.

Resources