Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,20 @@ protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable

// Initialize the bean instance.
Object exposedObject = bean;

// If the instance supplier was bypassed (e.g. explicit args were provided),
// apply any post-processing that was registered via InstanceSupplier.andThen().
// Note: this runs after early singleton caching. For the typical case where
// post-processing returns the same instance, this is safe. If post-processing
// wraps the instance, circular reference detection at the end of this method
// will detect the mismatch and throw BeanCurrentlyInCreationException.
if (args != null && mbd.getInstanceSupplier() instanceof InstanceSupplier<?>) {
exposedObject = applyInstanceSupplierPostProcessing(exposedObject, beanName, mbd);
if (exposedObject != instanceWrapper.getWrappedInstance()) {
instanceWrapper = new BeanWrapperImpl(exposedObject);
initBeanWrapper(instanceWrapper);
}
}
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
Expand Down Expand Up @@ -1285,6 +1299,23 @@ private BeanWrapper obtainFromSupplier(Supplier<?> supplier, String beanName, Ro
return supplier.get();
}

/**
* Apply any post-processing from the bean definition's
* {@link InstanceSupplier} to an already-created instance. This is called
* when the instance supplier was bypassed during creation (for example,
* when explicit constructor arguments were provided) but the post-processing
* registered via {@link InstanceSupplier#andThen} still needs to be applied.
* @param bean the already-created bean instance
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return the post-processed bean instance
* @since 7.0
* @see InstanceSupplier#postProcessInstance
*/
protected Object applyInstanceSupplierPostProcessing(Object bean, String beanName, RootBeanDefinition mbd) {
return bean;
}

/**
* Overridden in order to implicitly register the currently created bean as
* dependent on further beans getting programmatically retrieved during a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,26 @@ protected boolean isBeanEligibleForMetadataCaching(String beanName) {
return super.obtainInstanceFromSupplier(supplier, beanName, mbd);
}

@Override
@SuppressWarnings("unchecked")
protected Object applyInstanceSupplierPostProcessing(Object bean, String beanName, RootBeanDefinition mbd) {
InstanceSupplier<?> instanceSupplier = (InstanceSupplier<?>) mbd.getInstanceSupplier();
if (instanceSupplier != null) {
try {
return ((InstanceSupplier<Object>) instanceSupplier)
.postProcessInstance(RegisteredBean.of(this, beanName, mbd), bean);
}
catch (RuntimeException ex) {
throw ex;
}
catch (Exception ex) {
throw new BeanCreationException(beanName,
"Post-processing of instance supplier failed", ex);
}
}
return bean;
}

@Override
protected void cacheMergedBeanDefinition(RootBeanDefinition mbd, String beanName) {
super.cacheMergedBeanDefinition(mbd, beanName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,25 @@ default T getWithException() {
return null;
}

/**
* Apply only the post-processing steps of this supplier to an
* already-created instance, without invoking the instance creation itself.
* <p>This is used when the instance was created through a different path
* (for example, when explicit constructor arguments bypass the instance
* supplier) but post-processing registered via {@link #andThen} still
* needs to be applied.
* @param registeredBean the registered bean
* @param instance the already-created instance to post-process
* @return the post-processed instance
* @throws Exception on error
* @since 7.0
* @see #andThen
*/
@SuppressWarnings("unchecked")
default T postProcessInstance(RegisteredBean registeredBean, T instance) throws Exception {
return instance;
}

/**
* Return a composed instance supplier that first obtains the instance from
* this supplier and then applies the {@code after} function to obtain the
Expand All @@ -83,6 +102,12 @@ public V get(RegisteredBean registeredBean) throws Exception {
return after.applyWithException(registeredBean, InstanceSupplier.this.get(registeredBean));
}
@Override
@SuppressWarnings("unchecked")
public V postProcessInstance(RegisteredBean registeredBean, V instance) throws Exception {
T postProcessed = InstanceSupplier.this.postProcessInstance(registeredBean, (T) instance);
return after.applyWithException(registeredBean, postProcessed);
}
@Override
public @Nullable Method getFactoryMethod() {
return InstanceSupplier.this.getFactoryMethod();
}
Expand Down
Loading