Spring 执行器 returns 404 带 Spring 引导(war 项目)

Spring Actuator returns 404 with Spring Boot (war project)

我正在使用 Spring Boot 2.7.0(但我也尝试过 2.6.7 和 2.5)和 Java 17,我想将 actuator 添加到该项目。该项目被打包为 war,因为它仍在使用 JSP,我们在将其打包为 jar 时还没有开始工作。由于兼容性问题,它使用了非常旧的 spring-security 版本(4.2.18.RELEASE,仍在使用 XML 配置),但除此之外,依赖项应该是最新的.在其他项目中,我从未遇到过执行器的任何问题。无论如何,我已经将它添加到 pom.xml 文件中:

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

具有这些属性:

management.server.port=8081
management.endpoint.health.enabled=true
management.endpoint.health.show-details=always
management.endpoint.health.status.http-mapping.DOWN=200
management.endpoints.web.exposure.include=*

我们已将此设置添加到我们的 spring 安全 XML 配置中,以允许对执行器的所有调用:

<http pattern="/actuator/**" auto-config="true" use-expressions="true" create-session="stateless" disable-url-rewriting="true" security="none"/>

我们有(很多)自定义配置,但我能想到的相关部分是这样定义的:

@EnableRabbit
@EnableRetry
@SpringBootApplication
@EnableAsync
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ComponentScan({"com.company.something", "com.company.another"})
@ImportResource(locations = {"classpath*:META-INF/spring/applicationContext*.xml", "classpath:spring/webflow-config.xml"})
public class Bootstrap {

    public static void main(String[] args) {
        SpringApplication.run(Bootstrap.class, args);
    }
}

@Configuration
public class WebappConfiguration implements WebMvcConfigurer {

    @Bean
    public TomcatServletWebServerFactory tomcatFactory() {
        return new CustomTomcatServletWebServerFactory();
    }

    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> servletContainerCustomizer() {
        return container -> {
            container.addContextCustomizers(ctx -> ctx.setReloadable(false));
            container.addConnectorCustomizers(con -> con.setMaxPostSize(5000000));
        };
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/web-resources/**").addResourceLocations("classpath:/META-INF/web-resources/");
    }


    @Bean
    public DispatcherServletRegistrationBean dispatcherServletRegistrationBean() {
        DispatcherServlet servlet = new DispatcherServlet();
        servlet.setApplicationContext(new AnnotationConfigWebApplicationContext());
        return new DispatcherServletRegistrationBean(servlet, "/");
    }

    private static class CustomTomcatServletWebServerFactory extends TomcatServletWebServerFactory {
        @Override
        protected void postProcessContext(Context context) {
            ((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
            context.setResources(new ExtractingRoot());
        }
    }
}

当我 运行 应用程序时,我收到此错误:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 2 of method servletEndpointRegistrar in org.springframework.boot.actuate.autoconfigure.endpoint.web.ServletEndpointManagementContextConfiguration$WebMvcServletEndpointManagementContextConfiguration required a single bean, but 2 were found:
    - dispatcherServletRegistration: a programmatically registered singleton    - dispatcherServletRegistrationBean: defined by method 'dispatcherServletRegistrationBean' in class path resource [com/company/WebappConfiguration.class]

这是我觉得很奇怪的第一件事。据我了解,Spring 似乎检测到两个 servletEndpointRegistrar 豆。如果我尝试删除 dispatcherServletRegistrationBean 我 运行 进入此错误:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method errorPageCustomizer in org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration required a bean of type 'org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath' that could not be found.

如果我改为将 @Primary 注释添加到 dispatcherServletRegistrationBean:

@Primary
@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean() {
    DispatcherServlet servlet = new DispatcherServlet();
    servlet.setApplicationContext(new AnnotationConfigWebApplicationContext());
    return new DispatcherServletRegistrationBean(servlet, "/");
}

应用程序确实启动了。但是,如果我导航到 http://localhost:8081/actuator,我得到的是:

<Map>
  <timestamp>2022-05-24T06:38:58.914+00:00</timestamp>
  <status>404</status>
  <error>Not Found</error>
  <message>No message available</message>
  <path>/actuator</path>
</Map>

这可能是什么原因造成的,我该如何解决?

我设法通过将 DispatchServlet 创建为与 DispatcherServletRegistrationBean 分开的 bean 来解决这个问题:

@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
    DispatcherServlet servlet = new DispatcherServlet();
    servlet.setApplicationContext(new AnnotationConfigWebApplicationContext());
    return servlet;
}

@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet) {
    return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}