Comments (8)
Unfortunately, the stack trace isn't useful as, while it tells us that a series of beans is being created, it doesn't tell us what they are. You can figure that out using the debugger by walking back up the stack and looking at the value of the beanName
parameter for each occurrence of ….createBean(AbstractAutowireCapableBeanFactory.java:522)
. If you can share with us those bean names plus details of how each is defined, we may be able to figure out the cause.
from spring-boot.
beans are:
- meterRegistryPostProcessor
- actorSystemHolder
- xlrDatabaseInformation
- sqlConfiguration
- databaseProxyFeature
- distributedFeaturesConfiguration
where actorSystemHolder is (most of the code is Scala codebase):
class ActorSystemHolder(xlrConfig: XlrConfig, @Qualifier("xlrDatabaseInformation") dbInfo: DatabaseInfo)
extends Logging with ScalaSpringAwareBean with FactoryBean[ActorSystem] {
private var running: Boolean = false
lazy val actorSystem: ActorSystem = {
info("Starting up actor system.")
if (xlrConfig.isActiveOnStartup) {
NodeState.setActive(true)
}
val pekkoConfig = getSlickConfig.withFallback(xlrConfig.pekko.config)
val system = ActorSystem(xlrConfig.pekko.systemName, pekkoConfig)
system.registerExtension(SpringExtension)
running = true
system
}
def shutdown(): Unit = {
if (running) {
info("Initiating actor system shutdown.")
if (!AutoDowning.isDowning) {
// Actor system should be terminated by Coordinated Shutdown Pekko extension
val result = CoordinatedShutdown.get(actorSystem).run(GracefulShutdownReason)
info("Waiting for actor system shutdown (indefinitely).")
Await.result(result, atMost = Duration.Inf)
}
running = false
info("Actor system shutdown finished.")
}
}
override def getObject: ActorSystem = actorSystem
override def getObjectType: Class[_] = classOf[ActorSystem]
DatabaseInfo is just a bean inside SqlConfiguration:
@Bean
def xlrDatabaseInformation: DatabaseInfo = {
DatabaseInfo(xlrRepositoryDataSourceProxy())
}
where it extracts database information via connection.getMetadata:
object DatabaseInfo {
def apply(ds: DataSource): DatabaseInfo = {
map(ds.getConnection) { connection =>
val metadata = connection.getMetaData
DatabaseInfo(metadata)
}
}
class SqlConfiguration(xlrConfig: XlrConfig,
databaseProxyFeature: DatabaseProxyFeature,
metricsTrackerFactory: MetricsTrackerFactory
)
DatabaseProxyFeature and MetricsTrackerFactory are making it a bit complicated but I can remove them. In that case list of beans is shorter:
- meterRegistryPostProcessor
- actorSystemHolder
- xlrDatabaseInformation
- sqlConfiguration
from spring-boot.
Thanks for the details thus far. What's the bean that's being retrieved right at the bottom of the stack?
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205)
at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:277)
from spring-boot.
Bean at the bottom of the stack is meterRegistryPostProcessor
from spring-boot.
Hmmm I noticed that the bean itself is configured via xml config:
<bean id="actorSystemHolder" class="com.xebialabs.xlrelease.actors.ActorSystemHolder" destroy-method="shutdown"
depends-on="beforeLiquibaseUpgrade">
<constructor-arg name="xlrConfig" ref="xlrConfig"/>
<constructor-arg name="dbInfo" ref="xlrDatabaseInformation" />
</bean>
not sure if that makes difference
from spring-boot.
It being defined in XML may make a difference. It may mean that the bean factory can't tell statically what type the com.xebialabs.xlrelease.actors.ActorSystemHolder
factory bean will produce so it's being created really early to figure that out. Defining it in an @Configuration
class may help with that as may using ObjectProvider
to injects its arguments as injection into a FactoryBean
is a known cause of problems:
The XML snippet also shows that beforeLiquibaseUpgrade
is involved here too. That will affect things.
I'm afraid that we're going to need the complete picture here – and ideally a sample that reproduces the problem – to make any further progress.
Injecting the application context into the constructor should not be a problem as there's special handling for that and it isn't treated like a normal bean. We can't change that without a complete understanding of the problem as it may not be the optimal solution and it may have unwanted side-effects that we couldn't justify without a full understanding.
from spring-boot.
TBH I suspect it has something to do with XML vs Annotation config.
It would take me some time to create reproducible sample (as this just works elsewhere).
In the meantime, i have traced this to the applicationContext passed via org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration#meterRegistryPostProcessor
Maybe it would be fine to make this postprocessor ApplicationContextAware and invoke hasNoCompositeMeterRegistryBeans once postProcessAfterInitialization is invoked?
i.e.
class MeterRegistryPostProcessor implements BeanPostProcessor, SmartInitializingSingleton, ApplicationContextAware {
private final ObjectProvider<MetricsProperties> properties;
private final ObjectProvider<MeterRegistryCustomizer<?>> customizers;
private final ObjectProvider<MeterFilter> filters;
private final ObjectProvider<MeterBinder> binders;
private volatile boolean deferBinding = true;
private final Set<MeterRegistry> deferredBindings = new LinkedHashSet<>();
private ApplicationContext applicationContext;
private boolean hasNoCompositeMeterRegistryBeans(ApplicationContext applicationContext) {
return applicationContext.getBeanNamesForType(CompositeMeterRegistry.class, false, false).length == 0;
}
MeterRegistryPostProcessor(ObjectProvider<MetricsProperties> properties,
ObjectProvider<MeterRegistryCustomizer<?>> customizers, ObjectProvider<MeterFilter> filters,
ObjectProvider<MeterBinder> binders) {
this.properties = properties;
this.customizers = customizers;
this.filters = filters;
this.binders = binders;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MeterRegistry meterRegistry) {
postProcessMeterRegistry(meterRegistry);
}
return bean;
}
@Override
public void afterSingletonsInstantiated() {
synchronized (this.deferredBindings) {
this.deferBinding = false;
this.deferredBindings.forEach(this::applyBinders);
}
}
private void postProcessMeterRegistry(MeterRegistry meterRegistry) {
// Customizers must be applied before binders, as they may add custom tags or
// alter timer or summary configuration.
applyCustomizers(meterRegistry);
applyFilters(meterRegistry);
addToGlobalRegistryIfNecessary(meterRegistry);
if (isBindable(meterRegistry)) {
applyBinders(meterRegistry);
}
}
@SuppressWarnings("unchecked")
private void applyCustomizers(MeterRegistry meterRegistry) {
List<MeterRegistryCustomizer<?>> customizers = this.customizers.orderedStream().toList();
LambdaSafe.callbacks(MeterRegistryCustomizer.class, customizers, meterRegistry)
.withLogger(MeterRegistryPostProcessor.class)
.invoke((customizer) -> customizer.customize(meterRegistry));
}
private void applyFilters(MeterRegistry meterRegistry) {
if (meterRegistry instanceof AutoConfiguredCompositeMeterRegistry) {
return;
}
this.filters.orderedStream().forEach(meterRegistry.config()::meterFilter);
}
private void addToGlobalRegistryIfNecessary(MeterRegistry meterRegistry) {
if (this.properties.getObject().isUseGlobalRegistry() && !isGlobalRegistry(meterRegistry)) {
Metrics.addRegistry(meterRegistry);
}
}
private boolean isGlobalRegistry(MeterRegistry meterRegistry) {
return meterRegistry == Metrics.globalRegistry;
}
private boolean isBindable(MeterRegistry meterRegistry) {
return hasNoCompositeMeterRegistryBeans(applicationContext) || isCompositeMeterRegistry(meterRegistry);
}
@Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
private boolean isCompositeMeterRegistry(MeterRegistry meterRegistry) {
return meterRegistry instanceof CompositeMeterRegistry;
}
void applyBinders(MeterRegistry meterRegistry) {
if (this.deferBinding) {
synchronized (this.deferredBindings) {
if (this.deferBinding) {
this.deferredBindings.add(meterRegistry);
return;
}
}
}
this.binders.orderedStream().forEach((binder) -> binder.bindTo(meterRegistry));
}
}
I tried this and it does not cause the checker to fail and I do not see any problems.
I'm not sure if there is another post processor that uses the same pattern...
Is there a chance to accept this change or at least somehow make processor instantiation "tweakable" (maybe check presence of the postprocessor with same name)?
from spring-boot.
I tried this and it does not cause the checker to fail and I do not see any problems. I'm not sure if there is another post processor that uses the same pattern...
Is there a chance to accept this change
I tried to address this at the end of my previous comment:
Injecting the application context into the constructor should not be a problem as there's special handling for that and it isn't treated like a normal bean. We can't change that without a complete understanding of the problem as it may not be the optimal solution and it may have unwanted side-effects that we couldn't justify without a full understanding.
I am still of the opinion that we should not change this without a full understanding of the problem. How the ApplicationContext
is injected should not make any difference. Apparently it is making a difference so there's something unknown here that we don't understand. Until we do, it would be hard to justify making a change.
somehow make processor instantiation "tweakable" (maybe check presence of the postprocessor with same name)
You could perhaps use a bean factory post process to replace the definition of the MeterRegistryPostProcessor
. In your situation, I would invest time in creating a reproducer rather than resorting to such a hack.
from spring-boot.
Related Issues (20)
- Make it easier to provide a custom RequestToViewNameTranslator
- Note that spring-boot-docker-compose is excluded by default from packaged jars
- Note that spring-boot-docker-compose is excluded by default from packaged jars
- Remove Concourse CI configuration
- Remove Concourse CI configuration
- Remove Concourse CI configuration HOT 1
- Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: An object of type 'org.springframework.boot.loader.nio.file.NestedFileSystemProvider' was found in the image heap. This type, however, is marked for initialization at image run time for the following reason: classes are initialized at run time by default. HOT 3
- Declare the inputs of GenerateAntoraPlaybook more precisely
- Test Gradle plugin against Gradle 8.8 HOT 1
- Evaluate if adding a @WebEndpointTest for testing custom actuator web points is now feasible HOT 1
- Use ConcurrentHashMap.newKeySet where feasible
- Use ConcurrentHashMap.newKeySet where feasible
- Failing while building spring-boot-devtools version 2.7.10 using ./gradlew build (org.springframework.boot:spring-boot-devtools:2.7.10) HOT 1
- Failing while building spring-boot-starter-actuator version 2.7.10 using gradle build (org.springframework.boot:spring-boot-starter-actuator:2.7.10) HOT 1
- Change or remove dependency exclusion in spring-boot-starter-jersey HOT 1
- 3.2.3 to 3.2.5 upgrade causes Mismatched number of generics HOT 1
- Bump gradle/actions from 3.3.1 to 3.3.2
- Bump gradle/actions from 3.3.1 to 3.3.2
- In some situations, the failure when the AOT-generated initializer cannot be loaded is less helpful than before
- Mapped port can only be obtained after the container is started
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from spring-boot.