-
Notifications
You must be signed in to change notification settings - Fork 38.4k
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
Programmatic bean registration with configuration classes #18353
Comments
Juergen Hoeller commented Rob Winch, could you sketch the bean registration logic for a use case such as the above? What would it take to register those underlying beans via the |
Rob Winch commented Juergen Hoeller Thanks for reaching out. I have put together a small (very simplified) sample that demonstrates the use case above. Some of the simplifications are:
Part of the reason I like the idea of using
Ultimately, I think it would be awesome if somehow I could reuse the Bean Creation logic for both my XML Namespace and Java Configuration. For example, I might first turn the following XML: <http>
<form-login/>
</http> into a Java Bean like: HttpSecurity http = new HttpSecurity();
http
.formLogin(); Then I can run the Cheers, |
Janne Valkealahti commented I think these issues for getting proper programmatic registration of beans can be boiled down to a very simple missing feature, from JavaConfig returning a list of beans. At compile time if I don't know how many instances of MyBean class I have, I either have to use ImportBeanDefinitionRegistrar which most of a times is a bit useless as it can only access annotation info and some resources or use BFPP's. So many times I've hoped that I could just return List and spring would treat list members as beans. |
Rossen Stoyanchev commented We have these cases in the MVC Java config:
|
Sébastien Deleuze commented See also my functional Spring Boot draft proposal since I think this use case could take advantage of what is discussed here. |
Juergen Hoeller commented So is there anything that we need to do for 5.0 still? If yes, could the stakeholders please summarize their current position :-) |
Rob Winch commented Juergen Hoeller Thanks for reaching out. I chatted with Sébastien Deleuze I don't think this is really solved from my perspective. He is going to see if he can prototype out the example I have above and get back to me. |
Sébastien Deleuze commented We had a discussion with Rob about his use case. Functional bean registration API is very powerful because it allows to register programmatically beans, using The most important need I have identified about the feature discussed here is that Spring Framework should provide a way to contribute some beans with the functional bean registration API as part of an application that is using XML or JavaConfig, and I am not sure actually how to do that in order to get it invoked at the right moment of the lifecycle. To express that differently, the need here is to allow Spring Security and other Spring projects to leverage the powerful/flexible bean registration API for there internals while integrating in Spring Boot application that still leverage JavaConfig for users beans or Spring Boot internals. So it seems to me that we need to have a bridge between JavaConfig and functional bean rehgistration API to use both in the same application. That would be super useful for Spring Boot as well (discussion on this issue shows that there is no easy way to do that currently). Another important point is how the @Configuration
@EnableWebSecurity
public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.anyRequest().hasRole("USER")
.and()
// Possibly more configuration ...
.formLogin() // enable form based log in
// set permitAll for all URLs associated with Form Login
.permitAll();
}
@Bean
public Foo fooBean() { ... }
@Bean
public Bar barBean(Foo fooBean) { ... }
} The purpose of the feature discussed on this issue would be IMO to provide a way for Spring Security to provide a For example, it would be nice for Spring Security to be able to do that kind of things: public class WebSecurityConfigurerAdapter {
@FunctionalBeanRegistration
public void registerBeansWithFunctionalApi(GenericApplicationContext context) {
HttpSecurity http = configure(new HttpSecurity());
HttpDsl httpDsl = http.generateDsl();
if (httpDsl.isAddFooBean()) {
context.registerBean(Foo.class);
if (httpDsl.isAddBarBean()) {
context.registerBean(Bar.class, () -> new Bar(context.getBean(Foo.class)));
}
}
}
} I am not sure at all there is a need for a dedicated annotation for that, but the idea is to provide an extension point that can allow a JavaConfig Spring application to leverage functional bean registration API. Instantiating |
Janne Valkealahti commented One of the easiest examples to show what we're missing from a programmatic registration is how Spring Integration javadsl fails. If taking below example which creates gateway and registers it to app context, you can't ever auto-wire it because only hook they have is registerSingleton and that is called only after spring tries to auto-wire beans.
IntegrationFlowBeanPostProcessor.java#L283
|
Juergen Hoeller commented I've done some local tests with straight use of an injected
Anything I'm missing here? |
Janne Valkealahti commented I've never seen any of our own code to directly use GenericApplicationContext, probably for a good reason as I'd assume it opens a can of worms to all sort of other issues which are potentially impossible to track down. Lets say that there are multiple Would it be bad to have some sort of an annotation which would instruct context that this specific method will eventually provide/register beans of certain type? Not sure I like this idea myself either but we do have a chicken/egg situation here and all these are really starting to limit what we can do in all other Spring umbrella projects. |
Sébastien Deleuze commented Juergen Hoeller I made a try with my MiXiT application (which is a Spring Boot + Kotlin application), if I replace
By
I get the following error :
|
Juergen Hoeller commented Janne Valkealahti, Sébastien Deleuze, good points: Such |
Sébastien Deleuze commented Here is a quick update on the Spring Boot + functional bean registration use case : in addition to When this issue will be fixed, I will check both works with MiXiT application. |
Juergen Hoeller commented I still don't have a clear enough vision of a dedicated first-class mechanism here, so I'd rather defer this to 5.1. The existing mechanisms remain in place: functional registration works in custom |
I would like to provide an updated POV on that issue based on the use cases we see on Spring Native side and based on latest @jhoeller feedback. While working on native support, we have seen some consistent patterns emerging and requiring manual native configuration because reflection based. In most cases, using more functional constructs allows The pattern we see is typically for advanced configuration of let say Spring Security or Spring Data where regular
As pointed out by Juergen, it is currently already theoretically possible by casting
So a potential outcome of this issue could be a dedicated functional contract (like the It could be done via cc @aclement @dsyer @bclozel @rwinch @mp911de @christophstrobl |
Spring Data's repository bean registrations make use of In terms of reflection, we have few types (e.g. We use import selectors also for e.g. |
I tried it and found that there was no way to set attributes on the registered bean definitions (with a |
This is looking great @sdeleuze ! |
BeanRegistrar is nice approach. Do we need to keep below the code block always?
is it additional to previously suggested @configuration which implements BeanRegistrar? |
@dsyer For attributes, I think the design principles of @wakingrufus With #34486 and potential additional optimizations we are going to do, should be very close and should provide better Spring AOT / GraalVM native support, so I would recommend to consider using it for Spring Fu-like use cases. For IDEs, hat's a good point, I plan to discuss it with IntelliJ IDEA team and I will be happy to sync with @martinlippert for Eclipse / VS code. @anbusampath It is not additional to the previously suggested |
I meant InitializingBean is mandatory to make bean registration work with BeanRegistrar. Now I got it, it is additional bean implementation(optional). |
I can see why you might want to do that, but I still want a |
Yes, I am on it, I should not have mixed the bean customizer and the instance supplier. I will fix it shortly. |
I just pushed the related modifications and updated the related comment above. Will add more tests to check the behavior before end of the week. |
Is the plan to have |
Migration will be required (but easy, both are pretty close). |
Ok thanks. I'd be happy to help with an openrewrite recipe when the time comes. |
This commit introduces a new BeanRegistrar interface that can be implemented to register beans programmatically in a concise and flexible way. Those bean registrar implementations are typically imported with an `@Import` annotation on `@Configuration` classes. See BeanRegistrarConfigurationTests for a concrete example. See spring-projectsgh-18353
This commit introduces a new BeanRegistrarDsl that supersedes BeanDefinitionDsl which is now deprecated. See BeanRegistrarDslConfigurationTests for a concrete example. See spring-projectsgh-18353
After a lot of refinements and polish (thanks @jhoeller for your feedback), I have merged this feature that I consider as a first-class support for programmatic bean registration, including with support for Spring AOT optimizations and GraalVM native images. I will likely refine the AOT support in M4 to support more advanced use cases. See the related reference documentation for more details. @rwinch As discussed, your original use case of conditional bean registration depending on another bean/DSL is not yet supported, but let's explore what we can do to help you for this use case, I suggest we continue this exploration as part of #21497. |
🎉 so happy to see this done! |
Support for this in the |
This looks great @sdeleuze. From interface clients autoConfiguration perspective, the ability to also add bean aliases, as currently supported through |
Glad you like it. Should be possible, could you please create a related issue? I will add this in M4. |
Rob Winch opened SPR-13779 and commented
It would be nice to be able to allow Java Configuration to register multiple types of Beans. For example, right now the Spring Security exposes a Java DSL like this:
This single invocation (made by the developer configuring Spring Security) should ideally create numerous Beans (i.e. UsernamePasswordAuthenticationFilter, AuthenticationEntryPoint, etc) and expose them to the Spring ApplicationContext.
The key takeaway is that a developer should be able to interact with a DSL where a single invocation creates multiple Beans.
This is something Juergen Hoeller and I spoke about briefly at SpringOne that I would like to get on the roadmap (hopefully for Spring 5).
Updated
To elaborate on my comment below, I think it would be nice if we could do something like this:
I Java Config Users could consume this with:
and
MyDslParser.registerBeans
would automatically be invoked with the proper arguments.In XML Config users could consume this with:
and
MyDslParser.registerBeans
would automatically be invoked with the proper arguments.This would allow the framework to easily support multiple ways of configuring the Beans.
Issue Links:
BeanRegistrar
#21497 Support for conditional registration of functional bean definitions2 votes, 16 watchers
The text was updated successfully, but these errors were encountered: