This week's book giveaways are in the Jython/Python and Object-Oriented programming forums.
We're giving away four copies each of Machine Learning for Business: Using Amazon SageMaker and Jupyter and Object Design Style Guide and have the authors on-line!
See this thread and this one for details.
Win a copy of Machine Learning for Business: Using Amazon SageMaker and JupyterE this week in the Jython/Python forum
or Object Design Style Guide in the Object-Oriented programming forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Bear Bibeault
  • Paul Clapham
  • Jeanne Boyarsky
  • Knute Snortum
Sheriffs:
  • Liutauras Vilda
  • Tim Cooke
  • Junilu Lacar
Saloon Keepers:
  • Ron McLeod
  • Stephan van Hulst
  • Tim Moores
  • Tim Holloway
  • Carey Brown
Bartenders:
  • Joe Ess
  • salvin francis
  • fred rosenberger

Bean names : request for clarification

 
Bartender
Posts: 1233
38
IBM DB2 Netbeans IDE Spring Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm a bit confused about uniquiness of bean names in a Spring Application. So far, I always believed that two beans could not have the same name. So, If I have two distinct classes like these:



Spring complains that there are two different beans with the same name, and raises an exception.
Now, let's consider the following scenario, where I dropped FirstBean class.



This time I get no errors, and SecondBean isn't initialized either. I can't really exlain why: seems that Spring before initializing a @Component annotated bean, searches if exists a bean with the same name (and NOT of the same type) somewhere defined via a @Bean annotated method, and in that case, overrides any other definition.
But I cannot find anywhere an explicit explanation.
Can anyone help me to understand ?

 
Saloon Keeper
Posts: 21625
147
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
One thing that's not helping is that you're naming beans wrong. Beans, like any multiply-instantiable object in Java should, by convention be given names starting with lower-case letters. That is "businessBean", not BusinessBean. Upper-case initial letters are supposed to identify classes, class-like objects, and sometimes manifest constants.

While the Java language doesn't care, some Java tools will fail in peculiar ways if you fail to observe the upper/lower case conventions.
 
Claude Moore
Bartender
Posts: 1233
38
IBM DB2 Netbeans IDE Spring Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the reply... I'll try using bean names starting with lowercase letter, even if I don't think it would matter.
 
Tim Holloway
Saloon Keeper
Posts: 21625
147
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It probably won't, but it may save you some grief later.

I'm not actually sure what that code is supposed to do.  The argument for @Component is supposed to be a "type", not a bean name - one of the cases where failing to observe the capitalization conventions can be confusing to us humans, at least.

Plus you aren't following POJO rules in MainConfig. A "get" method should normally fetch a property value, not act as an unconditional factory. And since Spring is supposed to be providing the bean factory here, it would thus be more appropriate if you'd defined a "set" method so that Spring could inject the property value as a bean that it had manufactured.
 
Tim Holloway
Saloon Keeper
Posts: 21625
147
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
OK, never mind that "what are you doing" part. I see. But "new POJO" is not the same thing as requesting a Component. A Component is instantiated when a request is made to inject an instance or when code requests an instance from the Bean Factory.
 
Claude Moore
Bartender
Posts: 1233
38
IBM DB2 Netbeans IDE Spring Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Mumble... now I'm really confused.

First, as for documentation, a @Component annotation can accept only value attribute which is a name for the bean created. I don't understand  why  you say that

The argument for @Component is supposed to be a "type", not a bean name

 

Moreover, a @Bean annotated method in a @Configuration class (or in another @Component class, with class scanning enabled) does make Spring create and instantiate the bean: so new POJO() instantiates a bean which is managed by the container.
Ok, the name "getPOJO" for that method is greatly misleading,  let's have:


 
Tim Holloway
Saloon Keeper
Posts: 21625
147
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, I'm a little confused myself, since the official documentation says "value=TYPE".

But in actual practice, nobody ever seems to use Configuration with a value any more than I do when I use @Repository.

But let's adjust the code just a bit and I'll try and make more sense of it:


If I'm not mis-interpreting what the code that you modeled this on was intended to do, it was supposed to basically augment the Spring Bean Factory as a kind of plugin. Thanks to its annotations, it self-registers with Spring and acts as a sub-contracted factory for the bean named "businessBean" (as it could do for additional beans if it wanted). I'm not sure that the name of the method is critical so much as the @Bean annotation is, since it declares the method to be a factory for "businessBean". But that does mean that businessBean must be an object that is based on or implements SimpleComponent. You cannot return a random POJO object without risking an Exception.

I think maybe this documentation might help. I'm not sure it's the latest, but it's along the right direction at least:

https://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch02s02.html

 
Greenhorn
Posts: 16
1
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think I can add a little more information here:

I'm not sure that the name of the method is critical so much as the @Bean annotation is



In this example, no, it doesn't matter since there's an explicit name in the @Bean annotation.

Naming does matter with this, however, as beans always have names, even if they're not declared manually:



In this case, the bean's name is the method name. With that, it's generally just simpler to just let Spring do the naming do the work for you via method name. So an equivalent to the previous example is:



As for the behavior in question, I believe this is what happens, but can't find the specific documentation. I recognize that's basically what is being asked here, but I'm struggling to find explicit documentation on what the load order is here.

1. Spring scans for components
2. Finds a @Component and @Configuration - loads beans from @Configuration
3. Sees there is already a component named "businessBean" so does not load this bean. This would essentially be a bean override.

That makes sense to me, at least, knowing what I know about Spring's general behavior and having written code with beans intended to be overridden by name. Basically, the first bean with a given name wins.

There was a general discussion about this behavior and that it was not desired behavior here: https://github.com/spring-projects/spring-boot/issues/13609
As of Spring Boot 2.1.0, overriding a bean by name requires setting a property, so on Spring Boot 2.1.0 at least, I would expect this to cause a startup failure.
 
Claude Moore
Bartender
Posts: 1233
38
IBM DB2 Netbeans IDE Spring Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think Christopher got a point.
Let me  show you a revisited example:




Running above program - I hope this time it's clear enough - I got the following output:



So, looks like that whatever bean you declare using @Bean, Spring IoC treats it also as a override of any other definition of beans with the same name, where such beans are defined with @Component (or derived) annotations;
so, if a @Component class with the same name is encountered during class scan, it's simply skipped.

Anyway, this is a guess, because I was not able - as Christopher said - to find any documentation stating that @Configuration classes act as an override.

There's also a fun fact: let's make the whole thing even more crazy:



In this - pretty crazy ! - case, the bean really created is the first definition encountered. In this case, FirstBean:



Just inverting the order of declaration of the two methods, and the output changes.






By the way: all this craziness it's due not to a real code that I'm trying to implement. I'm just only studying for Spring certification, and I'm afraid to find similar kind of minutia in the real exam.
So, in conclusion: the whole  code has not any other purpose than a study of bean creation in Spring.



 
Ranch Hand
Posts: 1798
12
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi, Claude.
You are right. When two beans defined with the same name, the order matters. The first one is detected, but not the second one.
I tried something  like this:






output:


When I swap the order of TestBean and GameBean in MyConfig, it can find TestBean, but not GameBean.
 
Himai Minh
Ranch Hand
Posts: 1798
12
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi, Claude,
This is the Q&A of another site similar to  your question: https://www.quora.com/Can-we-configure-two-beans-of-the-same-class-with-the-same-id-in-spring
I guess the Spring container creates  the first bean and ignores the second bean with the same name.
It does not matter the beans are singleton or prototype.
I just tried @Scope("prototype") for both mybean.
The error is the same.
 
Thank you my well lotioned goddess! Here, have my favorite tiny ad!
Sauce Labs - World's Largest Continuous Testing Cloud for Websites and Mobile Apps
https://coderanch.com/t/722574/Sauce-Labs-World-Largest-Continuous
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!