Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a mechanism to be notified that a bean has been created [SPR-16822] #21362

Closed
spring-projects-issues opened this issue May 14, 2018 · 10 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

Andy Wilkinson opened SPR-16822 and commented

We have some code in Spring Boot that's intended to perform initialisation of a DataSource just before it's first made available to application code. It currently uses a BeanPostProcessor and uses the post-processing of any DataSource as the trigger for initializing a DataSource. For reasons that escape me, this DataSource may not be the same DataSource as the one that is being post-processed so it performs a lookup of a bean while another bean is being post-processed. That has caused several problems.

I think we could simplify the above-described logic so that we only perform initialisation of the DataSource bean that is being post-processed, thereby avoiding the problematic lookup. However, this action that's targeted to a specific bean doesn't feel like a perfect fit for the broader contract of a BeanPostProcessor. A callback that can be registered for a specific bean would be a better fit for our needs.

We'd like any callback that may be introduced to happen after bean post-processing. The crucial thing is that the callback is invoked before the bean can be used by application code. When I was trying to figure out what to do about the referenced Boot issue, a callback at around the point where AbstractBeanFactory.afterPrototypeCreation(String) or DefaultSingletonBeanRegistry.afterSingletonCreation(String) is called seemed to be a good fit. However, this is only based on a visual inspection of the code. I haven't verified that it would work as hoped.


Affects: 5.0.6

Reference URL: spring-projects/spring-boot#13042

2 votes, 8 watchers

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

I'm afraid I don't have the cycles left to properly sort this out for 5.1 RC1, so I'm putting this into the backlog for the time being. The introduction of such a specific callback is quite new territory... after all those years where the existing awareness and post-processing contracts remained largely untouched. I'd rather do a broader revision as a dedicated theme at a later point, assuming that there is a maybe-not-nice-but-effective workaround for the time being.

@spring-projects-issues
Copy link
Collaborator Author

Andy Wilkinson commented

The workaround appears to be effective and its use of BeanPostProcessor is an implementation detail so we're fine for Boot 2.1 and also well-placed to migrate to any new callback that Framework may introduce in the future.

@spring-projects-issues spring-projects-issues added type: enhancement A general enhancement in: core Issues in core modules (aop, beans, core, context, expression) labels Jan 11, 2019
@spring-projects-issues spring-projects-issues added this to the 5.x Backlog milestone Jan 11, 2019
@snicoll
Copy link
Member

snicoll commented Jul 24, 2019

@jhoeller following the recent brainstorm we had on the subject, a bean created event for top-level singleton would help us solve several issues in Spring Boot. I am tentatively assigning this one to 5.2 RC2.

@jhoeller
Copy link
Contributor

Any update/reminder about the state of affairs in Boot land? I suppose the workaround is still in place, and a bean-created event would be desirable towards a replacement where no extra BPP is needed in Boot?

Implementing this would require some delegation between the generic bean creation algorithm and the event facility at context level... that's not super-elegant but doable. The main remaining question for me is how to control the publication of the event since we would probably prefer to avoid it if there is no actual use for it.

@snicoll
Copy link
Member

snicoll commented May 14, 2020

Any update/reminder about the state of affairs in Boot land? I suppose the workaround is still in place, and a bean-created event would be desirable towards a replacement where no extra BPP is needed in Boot?

Absolutely. We do have a fair number of BPP to get a callback before the bean is injected.

The main remaining question for me is how to control the publication of the event since we would probably prefer to avoid it if there is no actual use for it.

If we have a way to register our interest upfront, perhaps that could solve the problem? We can look at concrete use cases on our side while crafting the solution.

@jhoeller
Copy link
Contributor

jhoeller commented May 27, 2020

Revisiting the bean-created event idea, I wonder whether this is semantically a good fit... since the very nature of event publication is decoupling to a degree where there are no immediate execution guarantees for the caller. The use case here requires execution before the bean can be used by application code, contradicting the event nature to some degree. It really is closer to post-processing than to an event, in that sense the current BeanPostProcessor solution doesn't seem like misuse, rather just lacking first-class convenience for this kind of use case.

So I guess I'm back at Andy's original suggestion: providing a post-processing callback for specific beans. We could quite easily support a lambda-oriented addBeanCreationCallback(String beanName, Consumer<Object> creationCallback) method at ConfigurableBeanFactory level. @wilkinsona @snicoll Would you see this as a better fit than your current BeanPostProcessor arrangement? Could you set it up for such name-based registration or do you need a type-based callback there?

@odrotbohm
Copy link
Member

I remember Jürgen and me previously discussed the inconvenience I felt using BPP instances for the use case of processing beans of a particular type:

  1. You need to create an implementation class that implements a framework interface.
  2. It's very likely that the implementation does a type check of some sorts, short-circuits the processing on a miss and then proceeds with the actual handling in case of a hit.

While both points are probably not the end of the world, as a user it feels like you're entering into a different world and have to deal with framework APIs when all you want to express is: "Once a bean of type X has been created let me do something to it.".

I was wondering if a JavaConfig style arrangement could become a slightly less framework involving way of post-processing beans:

@Configuration
class MyConfig {

  @PostProcessBean // name TBD
  MyComponent process(MyComponent component) { // potentially static declaration?
   // implementation
  }
}

That feels close enough to an event handler and feels like a programming model that nicely blends into user configuration space and doesn't force them to interact with things like the ApplicationContext in the first place, which you usually don't do in an application context.

@jhoeller
Copy link
Contributor

jhoeller commented May 27, 2020

Our entire post-processing business is quite complicated already, with all the separate invocations steps and the post-processor ordering semantics... Frankly, I'd rather avoid that term and the implied participation in the existing post-processing phase, with all the semantic complexity that comes with it (despite the visual part looking simple). Also, I feel that we're at the complexity limit of what a general annotation-based configuration model should support. An annotation-based trigger for a rare general post-processing purpose does not feel natural enough to me. Our general post-processors are rather meant to process annotations themselves, not be declared via annotations.

So I'd rather aim for a more specific and straightforward arrangement such as the addBeanCreationCallback suggestion above, and possibly a semantic equivalent in the annotation-based model but with the same limitations: a notification-style callback with the exposed bean instance at the very end of the individual bean creation step, without post-processor capabilities such as proxying/decoration or fine-grained lifecycle steps. Such a creation callback is not meant to modify the given instance (at least not its original configuration state) but rather react to it. I primarily wonder whether this should be name-based or type-based or otherwise attached to specific bean definitions.

@huifer
Copy link

huifer commented Jun 17, 2022

I think it's a good idea to make a listener after the bean is instantiated, either in the form of annotations or interfaces。Notification is triggered after Bean instantiation is complete

@jhoeller
Copy link
Contributor

jhoeller commented Mar 7, 2024

I'm introducing an addSingletonCallback(String beanName, Consumer<Object> singletonConsumer) method, along the lines of addBeanPostProcessor but at SingletonBeanRegistry level (the super-interface of ConfigurableBeanFactory). As mentioned above, this is intended for follow-up steps before the bean is actively used by other callers, not for modifying the given singleton instance itself. This requires knowing the target bean names upfront or determining the target bean names at callback registration time, in order to keep the callback overhead for unrelated beans as low as possible. For dynamic type checking of any beans, I would still recommend a BeanPostProcessor.

@jhoeller jhoeller modified the milestones: 6.2.x, 6.2.0-M1 Mar 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

5 participants