Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Actuator is not working with Jersey starter #2025

Closed
ouaibsky opened this issue Nov 30, 2014 · 30 comments
Closed

Actuator is not working with Jersey starter #2025

ouaibsky opened this issue Nov 30, 2014 · 30 comments

Comments

@ouaibsky
Copy link

Hi

I just cloned the starter-jersey sample then tried to add dependency spring-boot-starter-actuator.
Looks like any context mapped by actuator are working
The trouble is stdout looks fine, saying all endpoints are added, but when doing /health or /metrics .... nothing appears in a browser.
In fact it's a 404 error (displayed woth curl -i)
Looks like error page are not working as well.

I guess all this is due to Jersey but not able to do more troubleshooting.

Tested on 1.2.0-BUILD-SNAPSHOT

Christophe

@philwebb
Copy link
Member

philwebb commented Dec 1, 2014

The actuator HTTP endpoints are exposed via Spring MVC and we currently don't provide equivalents for Jersey. I'm not sure if you can easily mix Jersey and Spring MVC (@dsyer might know).

@celkins
Copy link

celkins commented Dec 1, 2014

It can be done, but IME you do have to provide your own FilterRegistrationBean and tweak actuator endpoint paths. For example, with Jersey 1 (and Spring Boot 1.1):

@Bean
public FilterRegistrationBean jersey() {
    final FilterRegistrationBean jersey = new FilterRegistrationBean();
    jersey.setFilter(new ServletContainer(this.config));
    jersey.setMatchAfter(true);
    jersey.addInitParameter("com.sun.jersey.config.feature.FilterForwardOn404", "true");

    final String managementContextPath = stripTrailingSlash(this.management.getContextPath());
    if (managementContextPath.isEmpty()) {
        throw new IllegalStateException("Management context path must be non-empty");
    } else {
        final String managementContextRegex = managementContextPath + "/.+";
        jersey.addInitParameter("com.sun.jersey.config.property.WebPageContentRegex", managementContextRegex);
    }

    return jersey;
}

Jersey 2 would be trivially similar, with slightly different init parameter names. Getting it working with spring-boot-starter-jersey might be more problematic.

@ouaibsky
Copy link
Author

ouaibsky commented Dec 1, 2014

@philwebb: if other starters cannot be used on top of spring-boot-starter-jersey, it doesn't make sense to provide support to another REST fwk
@celkins: Thx for jersey 1 clue. I'm gonna continue my investigation with Jersey 2 & starter-jersey but unfortunately, after playing a few day I'm wondering if philwebb is not right and probably give up jersey ... or find other alternatives.

Thx
Christophe

@dsyer
Copy link
Member

dsyer commented Dec 1, 2014

I don't understand what the problem is really. Jersey (1 or 2) can be installed as either a servlet or a filter, and if you map those to the same path as the Actuator endpoints, of course it's not going to work. You don't need a custom registration for Jersey 2 for vanilla use cases either (filter and servlet and custom paths are supported out of the box, and Jersey has a ton of options that are supported through spring.jersey.*). Or am I missing something?

@celkins
Copy link

celkins commented Dec 1, 2014

@ouaibsky: One option is to set the server.servletPath property to move the default DispatcherServlet out of the way. Alternatively, if you are willing and able to re-route your Jersey resources, you can add @ApplicationPath to your ResourceConfig class to move them out of the way.

@dsyer: I think it's a matter of the perhaps unrealistic expectation that one can add a dependency on spring-boot-starter-actuator to a spring-boot-starter-jersey-based application and have everything just work.

@ouaibsky
Copy link
Author

ouaibsky commented Dec 3, 2014

@dsyer, I'm exactly in the situation describe by @celkins below. Just putting spring-boot-starter-actuator to a spring-boot-starter-jersey and expecting it should work out of the box

But I understand now it's a bit more tricky (and has been designed first to work with Spring MVC)
I'm not an expert of Filter nor DispatchingServlet, Likely I need to read documentation more in details about Jesey configuration and Spring MVC.

@celkins Meaning if I move out DispatcherServlet, request will be automatically handle by jerseyServlet ?

For information the output when I start the example and doing some REST requests (in facto no more output if a request works or not)

[INFO] Attaching agents: []

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v1.2.0.BUILD-SNAPSHOT)

2014-12-03 22:10:33.284  INFO 4190 --- [           main] org.icroco.haura.kra.KraMain             : Starting KraMain on legolas with PID 4190 (/home/christophe/git/haura/haura-kra/target/classes started by christophe in /home/christophe/git/haura/haura-kra)
2014-12-03 22:10:33.352  INFO 4190 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@64485a47: startup date [Wed Dec 03 22:10:33 CET 2014]; root of context hierarchy
2014-12-03 22:10:34.351  INFO 4190 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2014-12-03 22:10:35.125  INFO 4190 --- [           main] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2014-12-03 22:10:36.019  INFO 4190 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080/http
2014-12-03 22:10:36.454  INFO 4190 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2014-12-03 22:10:36.456  INFO 4190 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.0.15
2014-12-03 22:10:36.594  INFO 4190 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2014-12-03 22:10:36.594  INFO 4190 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3247 ms
2014-12-03 22:10:37.755  INFO 4190 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'metricFilter' to: [/*]
2014-12-03 22:10:37.756  INFO 4190 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'requestContextFilter' to: [/*]
2014-12-03 22:10:37.756  INFO 4190 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'webRequestLoggingFilter' to: [/*]
2014-12-03 22:10:37.756  INFO 4190 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2014-12-03 22:10:37.757  INFO 4190 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'applicationContextIdFilter' to: [/*]
2014-12-03 22:10:37.757  INFO 4190 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'characterEncodingFilter' to: [/*]
2014-12-03 22:10:37.757  INFO 4190 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'jerseyServlet' to [/*]
2014-12-03 22:10:37.760  INFO 4190 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2014-12-03 22:10:38.105  INFO 4190 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@64485a47: startup date [Wed Dec 03 22:10:33 CET 2014]; root of context hierarchy
2014-12-03 22:10:38.184  INFO 4190 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[text/html],custom=[]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2014-12-03 22:10:38.184  INFO 4190 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2014-12-03 22:10:38.215  INFO 4190 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-12-03 22:10:38.215  INFO 4190 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-12-03 22:10:38.289  INFO 4190 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-12-03 22:10:38.773  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/dump],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.775  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/autoconfig],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.778  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/env/{name:.*}],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint.value(java.lang.String)
2014-12-03 22:10:38.778  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/env],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.779  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/mappings],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.781  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/shutdown],methods=[POST],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint.invoke()
2014-12-03 22:10:38.782  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/health],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(java.security.Principal)
2014-12-03 22:10:38.782  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/metrics/{name:.*}],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)
2014-12-03 22:10:38.783  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/metrics],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.784  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/configprops],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.785  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/info],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.795  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/beans],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.796  INFO 4190 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/trace],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2014-12-03 22:10:38.822  INFO 4190 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-12-03 22:10:38.850  INFO 4190 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 0
2014-12-03 22:10:39.147  INFO 4190 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080/http
2014-12-03 22:10:39.149  INFO 4190 --- [           main] org.icroco.haura.kra.KraMain             : Started KraMain in 6.252 seconds (JVM running for 6.759)

@celkins
Copy link

celkins commented Dec 3, 2014

@ouaibsky These lines indicate the crux of your problem:

2014-12-03 22:10:37.757  INFO 4190 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'jerseyServlet' to [/*]
2014-12-03 22:10:37.760  INFO 4190 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]

jerseyServlet effectively shadows everything under the root, so dispatcherServlet never sees any requests that it would otherwise forward to the actuator endpoints.

Compare that to what happens when you override server.servletPath to, for example, /spring:

2014-12-03 15:49:26.904  INFO 91671 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'jerseyServlet' to [/*]
2014-12-03 15:49:26.907  INFO 91671 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/spring/*]

With such a configuration, the actuator endpoints (as well as everything else handled by dispatcherServlet) are exposed as /spring/health, /spring/metrics, etc. For example,

$ curl -i http://localhost:8080/spring/health
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 03 Dec 2014 23:52:39 GMT

{"status":"UP","diskSpace":{"status":"UP","free":181905625088,"threshold":10485760}}

@ouaibsky
Copy link
Author

ouaibsky commented Dec 7, 2014

Thx @celkins

I confirm it works by adding a property server.servletPath.
Don know if it will be a "fragile" solution regarding future enhancement of spring-boot but it works
Thx

@dsyer dsyer added the question label Jul 12, 2015
@wujek-srujek
Copy link

I was also caught by this one, i.e. expecting the actuator to work with boot-starter-jersey. This was after we already committed to Jersey, so going back to webmvc is not an option. So now, it seems we have to depend on both webmvc (for example, via boot-starter-web) and jersey 2 (via boot-starter-jersey), i.e. have two REST libraries, which imho is not nice.
Anyways, I was able to configure it both ways:

  • add @ApplicationPath("api") on the ResourceConfig @component - in this case, all my custom resources are accessed with /api/hello etc.

  • remap the dispatcherServlet to /spring with server.servlet-path - the only thing I find strange is that while log says the dispatcher has been remapped, the endpoints are still reported under their original urls, for example:

    2015-07-15 23:15:24.292 INFO 2272 --- [ main] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/spring/]
    2015-07-15 23:15:26.218 INFO 2272 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
    2015-07-15 23:15:26.219 INFO 2272 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
    2015-07-15 23:15:26.249 INFO 2272 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
    2015-07-15 23:15:26.249 INFO 2272 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/
    ] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
    2015-07-15 23:15:26.290 INFO 2272 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/
    */favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
    2015-07-15 23:15:26.661 INFO 2272 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/configprops],methods=[GET]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()

Above, the /configprops URL is still reported although the one to use is /spring/configprops. Also, I don't really know if the /webjars/** is now /spring/webjars/**, the same for /error etc.

What makes things very, very confusing is that it is not documented anywhere that the actuator depends on webmvc; what is more, the spring-boot-actuator/pom.xml says the dependency on webmvc is optional (

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<optional>true</optional>
</dependency>
), i.e. webmvc is not really necessary for the actuator to work.

@snicoll
Copy link
Member

snicoll commented Jul 16, 2015

I think the misunderstanding comes from the fact that the "web" exposure is just one feature of the actuator. You can access to the same features via JMX endpoints for instance. That's why it's optional

that it is not documented anywhere that the actuator depends on webmvc;

Granted it's not super obvious but this page on "Monitoring and management over HTTP" starts with:

If you are developing a Spring MVC application, Spring Boot Actuator will ....

I'll add an explicit tip in that section.

snicoll added a commit that referenced this issue Jul 16, 2015
Add an explicit note about the need of Spring MVC for actuator HTTP
endpoints. Also explicitly mention Jersey since it can be a source of
confusion.

See gh-2025
@wujek-srujek
Copy link

Now I understand why it's marked optional, I didn't know about the other options (JMX, shell), now I read the full docs and know better.

As for the note you added - do you think it would be worth adding how both MVC and Jersey can be used together? It seems, even in this very issue, even the Boot core devs weren't sure if and how to make it work.

@snicoll
Copy link
Member

snicoll commented Jul 17, 2015

I think we didn't try to make it work, indeed. You can always create a separate issue to ask for a sample. PR more than welcome.

@snicoll snicoll closed this as completed Jul 17, 2015
@Avec112
Copy link

Avec112 commented Nov 24, 2016

See 77.3 Actuator and Jersey. Can confirm that it works.

@yahyayouness
Copy link

I turn around by adding @ApplicationPath("/api") to my jersey config

so dispatcher servlet map /
and JerseyServlet override but only map /api/*

@anilkonduru
Copy link

This might help someone using Jersey with Spring Boot.

If you are using Jersey with Spring Boot, actuator doesn't work default
like spring MVC. To make it work, spring.jersey.application-path need
to be set with your context path.

spring.jersey.application-path=/mytest-app

OR

server.servlet-path=/mytest-app

Also make sure following properties are set.

server.context-path=/mytest-app
management.security.enabled=false
management.health.defaults.enabled=true

@philwebb
Copy link
Member

@anilkonduru Jersey actuator endpoints are supported in Spring Boot 2.0

@adenix
Copy link

adenix commented Mar 7, 2018

@philwebb Are you saying that actuator endpoints work by default in Spring Boot 2.0? Because I'm not seeing that behavior. I'm still seeing Jersey overrun the actuator endpoints:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.test</groupId>
	<artifactId>actuator-jersey</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.0.RELEASE</version>
		<relativePath/>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jersey</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
	
</project>
2018-03-07 15:56:57.385  INFO 7661 --- [           main] c.d.t.i.u.Application     : Starting Application on SCRUBBED with PID 7661 (/SCRUBBED/target/classes started by SCRUBBED in /SCRUBBED)
2018-03-07 15:56:57.388  INFO 7661 --- [           main] c.d.t.i.u.Application     : No active profile set, falling back to default profiles: default
2018-03-07 15:56:57.494  INFO 7661 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@624ea235: startup date [Wed Mar 07 15:56:57 EST 2018]; root of context hierarchy
2018-03-07 15:56:58.575  INFO 7661 --- [           main] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2018-03-07 15:56:58.900  INFO 7661 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2018-03-07 15:56:58.947  INFO 7661 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2018-03-07 15:56:58.947  INFO 7661 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.28
2018-03-07 15:56:58.956  INFO 7661 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/SCRUBBED/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
2018-03-07 15:56:59.071  INFO 7661 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-03-07 15:56:59.071  INFO 7661 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1586 ms
2018-03-07 15:56:59.676  INFO 7661 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-03-07 15:56:59.676  INFO 7661 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpTraceFilter' to: [/*]
2018-03-07 15:57:00.088  INFO 7661 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-03-07 15:57:00.133  INFO 7661 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-03-07 15:57:00.137  INFO 7661 --- [           main] c.d.t.i.u.Application     : Started Application in 3.225 seconds (JVM running for 3.794)

@wilkinsona
Copy link
Member

What makes you think the endpoints have been “overrun”? Note that Jersey doesn’t log any mappings at startup so their absence from the log doesn’t mean anything.

@adenix
Copy link

adenix commented Mar 7, 2018

@wilkinsona Navigating to http://localhost:8080/actuator and http://localhost:8080/actuator/health returns 404 - Not Found

@wilkinsona
Copy link
Member

wilkinsona commented Mar 7, 2018

There’s no sign in the log output that you’ve shared that Jersey’s filter or Servlet has been registered so it looks like a broader problem. I’d check for corrupted dependencies, that you have a ResourceConfig bean, and the auto-configuration report to see what’s going on. If that doesn’t help, please open a new issue with a minimal, complete, and verifiable example that reproduces the problem.

@adenix
Copy link

adenix commented Mar 7, 2018

@wilkinsona - Thanks! Ill start working down that path.

@jokerr
Copy link

jokerr commented Mar 10, 2018

@wilkinsona @adenix Hopefully this will help - https://github.com/jokerr/boot2-jersey-actuator

2018-03-09 21:56:15.179  INFO 12148 --- [           main] com.example.BootApp                      : Starting BootApp on REDACTED with PID 12148 (C:\Users\jokerr\dev\boot2-jersey-actuator\target\classes started by jokerr in C:\Users\jokerr\dev\boot2-jersey-actuator)
2018-03-09 21:56:15.182  INFO 12148 --- [           main] com.example.BootApp                      : No active profile set, falling back to default profiles: default
2018-03-09 21:56:15.247  INFO 12148 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@4c22c4ba: startup date [Fri Mar 09 21:56:15 CST 2018]; root of context hierarchy
2018-03-09 21:56:16.386  INFO 12148 --- [           main] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2018-03-09 21:56:16.792  INFO 12148 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2018-03-09 21:56:16.823  INFO 12148 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2018-03-09 21:56:16.823  INFO 12148 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.28
2018-03-09 21:56:16.836  INFO 12148 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [REDACTED]
2018-03-09 21:56:16.958  INFO 12148 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-03-09 21:56:16.959  INFO 12148 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1717 ms
2018-03-09 21:56:18.124  INFO 12148 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-03-09 21:56:18.124  INFO 12148 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2018-03-09 21:56:18.124  INFO 12148 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpTraceFilter' to: [/*]
2018-03-09 21:56:18.124  INFO 12148 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet com.example.jaxrs.JerseyConfig mapped to [/v1/*]
2018-03-09 21:56:18.526  INFO 12148 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-03-09 21:56:18.586  INFO 12148 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-03-09 21:56:18.591  INFO 12148 --- [           main] com.example.BootApp

@wilkinsona
Copy link
Member

Thanks, @jokerr. Hopefully it will. @adenix That sample shows the actuator available at /v1/actuator. For example, you can access the health endpoint like this:

$ curl -i :8080/v1/actuator/health
HTTP/1.1 200
Content-Type: application/vnd.spring-boot.actuator.v2+json
Content-Length: 15
Date: Sat, 10 Mar 2018 07:52:42 GMT

{"status":"UP"}

@snicoll
Copy link
Member

snicoll commented Mar 10, 2018

If it does not, there is another sample here

@jokerr
Copy link

jokerr commented Mar 10, 2018

@wilkinsona This is just my personal opinion, I think a point of confusion is not seeing the actuator endpoints register in the start up logs. Through tinkering with the Jersey + Actuator combo I've found that not all the documented management properties work out of the box unless you make certain changes.

For example, I added a application.properites file to my sample app with only one property, management.server.servlet.context-path=/management. The Actuator is only available at /v1/actuator.

2018-03-10 07:44:15.538  INFO 3472 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-03-10 07:44:15.538  INFO 3472 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1422 ms
2018-03-10 07:44:16.576  INFO 3472 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-03-10 07:44:16.576  INFO 3472 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2018-03-10 07:44:16.576  INFO 3472 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpTraceFilter' to: [/*]
2018-03-10 07:44:16.576  INFO 3472 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet com.example.jaxrs.JerseyConfig mapped to [/v1/*]
2018-03-10 07:44:16.947  INFO 3472 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-03-10 07:44:16.999  INFO 3472 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-03-10 07:44:17.004  INFO 3472 --- [           main] com.example.BootApp                      : Started BootApp in 3.304 seconds (JVM running for 7.064)

However when I also change the port then things start working a little different. management.server.port=8081. The actuator is available at :8081/management/actuator and the Jersey app at :8080/v1/

2018-03-10 07:46:10.204  INFO 8968 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-03-10 07:46:10.205  INFO 8968 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1546 ms
2018-03-10 07:46:10.536  INFO 8968 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-03-10 07:46:10.536  INFO 8968 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2018-03-10 07:46:10.536  INFO 8968 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpTraceFilter' to: [/*]
2018-03-10 07:46:10.536  INFO 8968 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet com.example.jaxrs.JerseyConfig mapped to [/v1/*]
2018-03-10 07:46:11.393  INFO 8968 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-03-10 07:46:11.401  INFO 8968 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@58e34793: startup date [Sat Mar 10 07:46:11 CST 2018]; parent: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5947e435
2018-03-10 07:46:11.465  INFO 8968 --- [           main] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2018-03-10 07:46:11.512  INFO 8968 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8081 (http)
2018-03-10 07:46:11.513  INFO 8968 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2018-03-10 07:46:11.514  INFO 8968 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.28
2018-03-10 07:46:11.531  INFO 8968 --- [ost-startStop-1] o.a.c.c.C.[.[localhost].[/management]    : Initializing Spring embedded WebApplicationContext
2018-03-10 07:46:11.531  INFO 8968 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 130 ms
2018-03-10 07:46:11.644  INFO 8968 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet servletContainer mapped to [/*]
2018-03-10 07:46:11.703  INFO 8968 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path '/management'
2018-03-10 07:46:11.724  INFO 8968 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-03-10 07:46:11.727  INFO 8968 --- [           main] com.example.BootApp                      : Started BootApp in 3.461 seconds (JVM running for 7.29)

Appreciate all your hard work on this project!

@adenix
Copy link

adenix commented Mar 10, 2018

Yeah, I got it working a few days ago. Then I had an issue using packages() with a fat jar so I used someones solution to implement the same functionality for a fat jar.

@wilkinsona
Copy link
Member

wilkinsona commented Mar 12, 2018

This is just my personal opinion, I think a point of confusion is not seeing the actuator endpoints register in the start up logs.

That's a side-effect of using Jersey. Boot itself doesn't log any of the Actuator endpoint mappings. Spring MVC and Spring WebFlux both log mappings at info level by default, Jersey doesn't and I don't believe there's a way to switch it on. I've opened #12442 to consider adding some logging to Boot.

For example, I added a application.properites file to my sample app with only one property, management.server.servlet.context-path=/management. The Actuator is only available at /v1/actuator.

This is the expected behaviour. management.server.servlet.context-path only has an effect if management.server.port has been set and has a different value to server.port.

However when I also change the port then things start working a little different. management.server.port=8081. The actuator is available at :8081/management/actuator and the Jersey app at :8080/v1/

In some ways that's what I'd expect. On one hand, your @ApplicationPath("v1")-annotated resource config isn't part of the management context that's used when a separate port has been specified so it makes some sense that it doesn't affect the actuator in that case. On the other hand, the actuator endpoints must have picked up the ResourceConfig from your app and used it otherwise they wouldn't be available. I don't yet understand why they apparently picked up the ResourceConfig but didn't pick up the @ApplicationPath. I suspect it also means that we're sharing one ResourceConfig across the management "app" and your app. That's unlikely to be a good idea… I've opened #12443.

@bric3
Copy link

bric3 commented Jul 15, 2019

Reading this https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/htmlsingle/#production-ready-customizing-management-server-context-path (Using 2.1.6.RELEASE)

Unless the management port has been configured to expose endpoints by using a different HTTP port, management.endpoints.web.base-path is relative to server.servlet.context-path. If management.server.port is configured, management.endpoints.web.base-path is relative to management.server.servlet.context-path.

I modified the configuration this way

+server:
+  servlet:
+    context-path: /
spring.mvc.servlet.path: /static
spring:
  jersey:
    application-path: /
    servlet:
      load-on-startup: 1

management:
  endpoint:
    health.enabled: true
+  endpoints:
+    web:
+      base-path: /actuator
+      path-mapping.health: healthcheck

However actuators keep showing up under /static instead of /

  • curl localhost:8080/static/actuator/healthcheck => 200
  • curl localhost:8080/actuator/healthcheck => 404

So either there's something missing on the documentation or they are some limitations to how actuator integrate when there's both spring mvc and jersey.

Even switching the dispatcher servlet to / didn't work

-spring.mvc.servlet.path: /static
+spring.mvc.servlet.path: /

@wilkinsona
Copy link
Member

@bric3 If you have both Jersey and Spring MVC on the classpath, Actuator has to pick one so Spring MVC will take precedence. If you believe that something is unclear or that there's an improvement that could be made somewhere please open a new issue and we will take a look.

@bric3
Copy link

bric3 commented Jul 15, 2019

Hi @wilkinsona, I believe that both could be improved.

  1. The doc should state which technology it will take precedence. And as such how other properties are affected, i.e. server.servlet.context-path has no effect when Spring MVC is also present.
  2. Is there a way to configure which technology will be used.
  3. If not maybe indicate how to play with the DispatcherServlet to not hide Spring MVC when jersey and MVC are mapped on the same context path /
Mapping servlets: oldMetricsService urls=[/metrics], company.web.JerseyConfig urls=[/*], dispatcherServlet urls=[/]

This last is actually interesting if one want to migrate one endpoint at a time from one technology to another.

I will open the issue. Thanks a lot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests