Config refresh fails for a @ConfigurationProperties bean that is proxied twice
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 56/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- java, spring, spring-boot
- Área
- backend
Línea de trabajo
Start with ConfigurationPropertiesRebinder.rebind() and trace how it gets the target class and replaces a nested AOP proxy; compare that path with the reproducer at https://github.com/tommyk-gears/spring-cloud-double-proxy-refresh. Run ./gradlew test in the reproducer against the affected versions, then verify refresh succeeds for a double-proxied @ConfigurationProperties bean and that other beans are rebound after a failure.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Versions: Spring Boot 4.1.2, Spring Cloud 2025.1.4 (spring-cloud-context 5.0.4). Also 5.0.2 and the build of #1779. Works with 5.0.1.
Reproducer: https://github.com/tommyk-gears/spring-cloud-double-proxy-refresh. ./gradlew test fails; the README lists how to run it against other versions.
What happens
A config refresh (POST /actuator/refresh, or ContextRefresher.refresh()) throws when a @ConfigurationProperties bean is an AOP proxy around another AOP proxy:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'com.example.repro.ReproApplication$DemoProperties$$SpringCGLIB$$0': Cannot invoke
"org.springframework.cglib.proxy.Dispatcher.loadObject()"
Caused by: java.lang.NullPointerException: Cannot invoke "org.springframework.cglib.proxy.Dispatcher.loadObject()"
at com.example.repro.ReproApplication$DemoProperties$$SpringCGLIB$$0.isFrozen(<generated>)
at org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor.postProcessAfterInitialization(...)
...
at org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.rebind(...)
POST /actuator/refresh returns 500, the refreshScope health indicator is DOWN from then on, and since rebind() stops at the first failure, @ConfigurationProperties beans that had not been rebound yet keep their old values.
A double proxy comes about without anything unusual: in the reproducer, the properties class is @Validated, so the method validation post-processor proxies it, and an application aspect matching @Validated classes makes the AspectJ auto-proxy creator wrap that proxy again. We ran into it in a service whose aspect converts ConstraintViolationExceptions for @Validated classes, which broke refresh for four properties beans, three of them from a shared library.
Listing the class in spring.cloud.refresh.never-refreshable does not help either, since the check compares the same class (the inner proxy's) with the configured names. Only the bean name works.
What we found
Since 5.0.2 (ba34b47e), rebind() creates a fresh instance of an AOP-proxied bean with createBean(targetClass) and swaps it into the proxy. The target object is unwrapped recursively (ProxyUtils.getTargetObject), but targetClass comes from AopUtils.getTargetClass(bean), which unwraps one level. For a double proxy that is the class of the inner proxy, so createBean instantiates a CGLIB proxy class without its callbacks, and the first call on it fails. 5.0.1 rebound the unwrapped bean in place, which worked through the nested proxy.
This is separate from #1778; the build of #1779 fails the same way.
Possible directions, just as food for thought
- Use
AopProxyUtils.ultimateTargetClass(bean)for the target class and thenever-refreshablecheck. - Swap the fresh target into the innermost proxy rather than the outer one, so the advice of the inner proxy (here method validation) is kept.
- Lenguaje dominante
- Java
- Estrellas
- 750
- Forks
- 749
- Merge medio
- 19 h 58 min
- PR fusionados (30 d)
- 23
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de spring-cloud/spring-cloud-commons
-
waiting-for-triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
spring-cloud/spring-cloud-commons#1708 ·
Los mantenedores suelen responder en 1 día
-
waiting-for-triage
Dificultad 1/5 Menos de una hora Aptitud para principiantes 65/100
spring-cloud/spring-cloud-commons#1543 ·
Los mantenedores suelen responder en 1 día
-
`resetBeanToDefaults` transiently nulls nested `@ConfigurationProperties` objects, NPEing concurrent request threadsPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abiertobug
Dificultad 5/5 Más de una semana Aptitud para principiantes 48/100
spring-cloud/spring-cloud-commons#1727 · 5 comentarios · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
enhancement for team discussion
Dificultad 5/5 Más de una semana Aptitud para principiantes 42/100
spring-cloud/spring-cloud-commons#1676 ·
Los mantenedores suelen responder en 1 día
-
waiting-for-triage
Dificultad 5/5 Más de una semana Aptitud para principiantes 38/100
spring-cloud/spring-cloud-commons#1675 · 1 comentario ·
Los mantenedores suelen responder en 1 día
Todos los issues de spring-cloud/spring-cloud-commons
Issues similares
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
breaking change bug needs human review not ready priority medium size S
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
martin-francois/symphony-trello#1193 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 1 día
-
Mend: dependency security vulnerability
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100