[spring-projects/spring-boot]无法禁用从 spring-boot-maven 插件中过滤掉配置处理器 jar

2024-07-08 665 views
7

在我们的项目中,我们在运行时使用来自配置处理器的一些注释工具。在最近的 Spring 版本更新(spring-boot-starter-parent 2.3.8 -> 2.5.2)之后,几乎一切都很好,只是在运行时我们开始得到:

ClassNotFoundException: org.springframework.boot.configurationprocessor.json.JSONException

在我们的WebSecurityConfigurerAdapter.configure代码中。

手动添加spring-boot-configuration-processor-2.5.2.jarBOOT-INF/lib/构建 jar 文件夹后 - >应用程序运行良好(我确信之前未找到的类是由于包装了实际异常 - 但似乎这是原始问题)。

因此,目前我们无法标记此 jar,以便在更改后不会从结果工件中删除

https://github.com/spring-projects/spring-boot/blob/b65cc4d62f4a818e36be8b99b98eba01a28f6f2a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java#L108

是否可以包装注册

filters.addFilter(new JarTypeFilter()); 

带有一些标志?默认情况下它会排除,但如果像我们这样的某些特殊情况需要它,我们可以继续使用它吗?

回答

4

涉及 #22036

5

@stepanovdgspring-boot-configuration-processor在运行时使用非常不常见。您使用该项目中的哪些特定类以及为什么在运行时需要它们?

6

如果我们确实想使事物可配置,我们可以提供一个简单的开/关开关或更改JarTypeFilterJarTypeFileSpec以便他们可以接受要排除的类型列表?

有趣的是,它JarTypeFileSpec不会过滤注释处理器。我猜是因为 Gradle 有更好的注释处理器设置,所以它们一开始就不会出现。

4

@philwebb 不确定我们是否真的直接使用了它。可能是顺序出了问题。它失败的地方实际上是我们用org.reflections自己的注释来扫描方法(如 frontendapi、internalapi 等),并将其RequestMapping分组并应用到 Web 安全设置中,并在其他地方生成正确的开放 API 端点。

我认为在 Spring 版本进行重大更新之后,配置或第三方依赖版本出现了问题,而这掩盖了实际原因。

但是将 jar 放在 classpath 上可以解决所有问题。

5

@stepanovdg 你有完整的堆栈跟踪可以添加到这个问题吗?如果能有一个示例应用程序来复制这个问题就更好了。我很好奇为什么org.reflections需要阅读这个org.springframework.boot.configurationprocessor.json.JSONException类。

9
2021-08-06 01:34:08 ERROR [   main] [o.s.boot.SpringApplication         :843]  Application run failed 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/boot/configurationprocessor/json/JSONException
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:486)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1334)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:338)
    at c.v.t.TcpBullseyeApplication.main(TcpBullseyeApplication.java:34)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/boot/configurationprocessor/json/JSONException
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
    ... 27 common frames omitted
Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/configurationprocessor/json/JSONException
    at c.v.t.config.security.CommonSecurityConfig.configure(CommonSecurityConfig.java:57)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.getHttp(WebSecurityConfigurerAdapter.java:217)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:315)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:93)
    at c.v.t.config.security.CommonSecurityConfig$$EnhancerBySpringCGLIB$$bd90bedf.init(<generated>)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$$FastClassBySpringCGLIB$$432a6c3b.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)
    at c.v.t.config.security.CommonSecurityConfig$$EnhancerBySpringCGLIB$$ce36a12.init(<generated>)
    at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.init(AbstractConfiguredSecurityBuilder.java:338)
    at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:300)
    at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:38)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:127)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
    ... 28 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.configurationprocessor.json.JSONException
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
    at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
    ... 52 common frames omitted

实际堆栈跟踪。错误发生在以下行:

 .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
          .and()

特别指出这一点and()

@Override
  @Log(Log.LoggingLevel.INFO)
  protected void configure(HttpSecurity http) {
      HashSet<String> skipUrls =
          new HashSet<>(Arrays.asList("/management/health", "/management/prometheus"));
      HttpSecurity httpSecurity = registerSecuredApi(http);
      httpSecurity
          .csrf()
          .disable()
          .sessionManagement()
          .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
          .and()
          .addFilterBefore(
              new AuthenticationFilter(whitelistedIps, skipUrls),
              UsernamePasswordAuthenticationFilter.class)
          .addFilterBefore(new InitiatedFilter(skipUrls), AuthenticationFilter.class)
          .exceptionHandling()
          .authenticationEntryPoint(exceptionHandler)
          .accessDeniedHandler(exceptionHandler);
  }

  @Log(Log.LoggingLevel.INFO)
  protected HttpSecurity registerSecuredApi(HttpSecurity http) throws Exception {
    ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry
        expressionInterceptUrlRegistry = http.authorizeRequests();
    Map<HttpMethod, List<ApiAnnotationsUtils.MethodPatternPair>> apiAnnotatedWith =
        getApiAnnotatedWith(FrontendApi.class);
    apiAnnotatedWith
        .keySet()
        .forEach(
            method ->
                expressionInterceptUrlRegistry
                    .antMatchers(
                        method,
                        apiAnnotatedWith.get(method).stream()
                            .map(ApiAnnotationsUtils.MethodPatternPair::getPattern)
                            .toArray(String[]::new))
                    .authenticated());
    return expressionInterceptUrlRegistry
        .antMatchers("/actuator/**")
        .permitAll()
        .anyRequest()
        .permitAll()
        .and();
  }

  @Log(Log.LoggingLevel.INFO)
    public static Map<HttpMethod, List<MethodPatternPair>> getApiAnnotatedWith(Class<? extends Annotation> annotation) {
        Map<HttpMethod, List<MethodPatternPair>> collect = getRequestMappingStream(annotation)
                .flatMap(
                        request ->
                                Arrays.stream(request.method())
                                        .map(m -> HttpMethod.resolve(m.toString()))
                                        .flatMap(
                                                m ->
                                                        Arrays.stream(request.path())
                                                                .map(path -> new MethodPatternPair(m, path))))
                .collect(Collectors.groupingBy(MethodPatternPair::getMethod));
        return collect;
    }

    @Log
    public static Stream<RequestMapping> getRequestMappingStream(Class<? extends Annotation> annotation) {
        return new Reflections("c.v.t.web.api.controller", new MethodAnnotationsScanner())
                .getMethodsAnnotatedWith(annotation).stream()
                .map(
                        method ->
                                Objects.requireNonNull(
                                        AnnotationUtils.getAnnotation(method, RequestMapping.class)));
    }

    @Data
    @AllArgsConstructor
    public static class MethodPatternPair {
        HttpMethod method;
        String pattern;
    }

不确定现在是否能够创建简单的应用程序。

7

从您所附的代码中我有点不明白是什么导致了问题,特别是如果CommonSecurityConfig.java:57在线的话.sessionCreationPolicy(SessionCreationPolicy.STATELESS)

您是否尝试过搜索您的代码库以确保org.springframework.boot.configurationprocessor.json.JSONException没有意外地被导入到任何地方?

8

@stepanovdg 配置处理器仅将 JSON 着色用于内部目的。它不适用于其他任何地方,尤其是考虑到注释处理器仅供编译时使用。CommonSecurityConfig应该直接依赖 JSON 库,而不是依赖我们的着色内部版本。

com.vaadin.external.google:android-json您可以通过添加依赖项并修复导入来实现这一点CommonSecurityConfig

2

@snicoll 我不确定我们是否已经确定这CommonSecurityConfig是导入的JSONException,它可能是某个Reflections类以某种方式从其他地方获取的。

@stepanovdg 如果您的代码库中没有任何org.springframework.boot.configurationprocessor.json导入,您能否提供一个可复制该问题的示例。

0

@philwebb @snicoll 非常感谢。它出现在侧面身份验证过滤器导入中,来自 JsonObject,并且异常来自配置处理器,而不是 org.json。

抱歉打扰了。

9

我也遇到过这种情况。我在我的代码库中使用了另一种方法。但我尝试了 spring-boot 2.3.x,它成功了。顺便问一下,你会在下一版本中修复这个问题吗?

3

@qyqcswill 据我所知,没有什么需要修复的。请查看上面的帖子。如果您有导入org.springframework.boot.configurationprocessor.json,则不应该。这是一个阴影版本,不打算在用户代码中使用。如果没有,请分享一个重现问题的小样本,我们可以重新打开此问题。

9

好的,太好了。我建议我的团队将 spring-boot 版本从 spring-boot2.2.x 升级到 spring-boot2.4.x。我不知道还有谁导入了org.springframework.boot.configurationprocessor.json。没关系,每个人都检查一下代码。

9

有没有办法包装 lib spring-boot-configuration-processor-2.xxjar。如上所述,在打包时,此 lib 未从版本 2.4.x 打包,运行时发生错误:由异常引起:java.lang.NoClassDefFoundError 消息:org.springframework.boot.configurationprocessor.json.JSONException

这是因为代码使用了 org.springframework.boot.configurationprocessor.json.JSONException 类

9

@retamiro 请参阅上面 Stephane 的评论。听起来你试图使用一些org.springframework.boot.configurationprocessor.json.JSONException你不应该使用的代码。

1

有一些微服务被误用了,目标是尽量减少影响。问题是由于 spring 2.4x 中实现的“Jar 优化”引起的,所以我问它有什么办法,但还是感谢你的反馈