Spring #Bean(name ="name") vs #Bean #Qualifier("name") - spring

Is there any differences between the following 2 bean declaration?
#Bean(name = "bean1")
public A getA() {
return new A();
}
#Bean
#Qualifier("bean1")
public A getA() {
return new A();
}
Both can be autowired using #Qualifier
#Autowire
public void test(#Qualifier("bean1") A a) {
...
}

With value() you don't have to specify attribute name, like #Qualifier("bean1"). Attribute name() reference the same value as value() because of custom annotation #AliasFor(..) from Spring, therefore they are just different names with the same behavior.

You can use
#Autowire
public void test(A bean1) {
...
}
if you use
#Bean(name = "bean1")
not with
#Bean
#Qualifier("bean1")

The first part is fundamentally the same, the second part is what you basically need when two or more beans of same type exist. The first part is just the preference one might have.

You can have multiple beans with same Qualifier name but bean name in spring application context needs to be unique
#Bean
#Qualifier("qualifier1")
Foo foo()
{
return new Foo();
}
#Bean
#Qualifier("qualifier1")
Bar bar()
{
return new Bar();
}
The above code is acceptable. but in the case of bean, it is not.

Related

Is it safe to return "this" from a Spring bean method?

I want to create a chain api on a prototype bean.
#Component
#Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ReportGenerator {
List lines = new ArrayList();
public ReportGenerator append(String line){
lines.add(line);
return this;
}
}
public class SomeSingletonBean{
#Autowire
ReportGenerator rg;
void doSomeWork(){
rg.append("a").append("b");
}
}
The above seems to work fine.
But is this safe in all cases?
Also, can I safely do the same in a bean scoped "session"?

#Bean-method providing a list is ignored, if there is a #Bean-method proving a single bean

I have a configuration providing a single bean and a configuration providing a list of beans. All these beans have the same type.
When I start up an application context with these configurations, I see that an autowired list of the bean type only contains the single bean. I want it to include all beans of that type. I use Spring 5.2.0.
I have boiled it down to one configuration: if I provide a single bean and a list of beans, only the single bean will be used.
This is reproduced in the following test. It fails, because the list only contains "A" and "D" (which shows it did not autowire the list of beans):
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = { TestConfiguration.class })
class AutowiringListsTest {
#Autowired
private List<TestBean> testBeanList;
#Test
void testThatBothConfigurationsContributeToBeanList() {
final List<String> idList = testBeanList.stream().map(TestBean::getId).sorted().collect(Collectors.toList());
assertThat(idList, hasItems("A", "B", "C", "D"));
}
#Configuration
public static class TestConfiguration {
#Bean
public TestBean someBean() {
return new TestBean("A");
}
#Bean
public List<TestBean> someMoreBeans() {
return Arrays.asList(new TestBean("B"), new TestBean("C"));
}
#Bean
public TestBean anotherBean() {
return new TestBean("D");
}
}
public static class TestBean {
private final String id;
public TestBean(final String id) {
this.id = id;
}
private String getId() {
return id;
}
}
}
I want to get this to run so that multiple modules can provide beans of a certain type.
Some modules want to provide multiple beans and their number depends on a property.
Some modules will always provide one bean.
The module using the beans (autowiring them as list) should autowire all beans.
How can I get this to run? In what scenario does Spring's behavior make sense?
I can work around the issue by introducing a TestBeanFactory. Each configuration that wants to contribute to the list of TestBeans instead provides a factory.
#Configuration
public static class TestConfiguration {
/** Implemented once in the configuration that defines <code>TestBean</code>. */
#Bean
public List<TestBean> testBeansFromFactory(Collection<TestBeanFactory> factories) {
return factories.stream().map(TestBeanFactory::createTestBeans).flatMap(Collection::stream)
.collect(toList());
}
// Further methods can be defined in various configurations that want to add to the list of TestBeans.
#Bean
public TestBeanFactory someBean() {
return () -> Arrays.asList(new TestBean("A"));
}
#Bean
public TestBeanFactory someMoreBeans() {
return () -> Arrays.asList(new TestBean("B"), new TestBean("C"));
}
#Bean
public TestBeanFactory anotherBean() {
return () -> Arrays.asList(new TestBean("D"));
}
}
public static class TestBean { ... }
public static interface TestBeanFactory {
public Collection<TestBean> createTestBeans();
}
That works and is only slightly more code.
M.Deinum makes a point in the comments for Spring's behavior being consistent:
As you defined a bean of type List it will be used. Autowiring is based on type, it will try to detect the bean of the certain type. The collection (and map as well) is a special one looking up all dependencies of the given type.

Switch bean by changing properties in Spring boot

I have one interface MyInterface, and 2 implementation beans: FirstImpl & SeconImpl. I want to switch between using these 2 implementations while program is running without restarting it, by only changing a property in application.properties file, e.g: interface.bean.default=FirstImpl change to interface.bean.default=SecondImpl.
Anyone knows how to do that with Spring boot?
You could try to use #ConditionalOnProperty:
#Configuration
public class MyInterfaceConfiguration {
#Bean
#ConditionalOnProperty(value = "my.interfacte.impl", havingValue="firstImpl")
public MyInterface firstImpl(){
return new FirstImpl();
}
#Bean
#ConditionalOnProperty(value = "my.interfacte.impl", havingValue="secondImpl")
public MyInterface secondImpl(){
return new SecondImpl();
}
}
and when you update your property in application.properties with actuator/refresh to:
my.interfacte.impl=firstImpl
you will have your FirstImpl instance. When you have:
my.interfacte.impl=secondImpl
you will have your SecondImpl.
#Hasan, your update only works if I customize it a little bit as below:
#Configuration
#RefreshScope
public class MyInterfaceConfiguration {
#Value("${my.interfacte.impl}")
String impl;
#Bean
#RefreshScope
public MyInterface getBean(){
if ("firstImpl".equals(impl)) {
return new FirstImpl();
} else if ("secondImpl".equals(impl)) {
return new SecondImpl();
}
return null;
}
}
I have to use 2 #RefreshScope at class level and bean creation method level!

How to declare an optional #Bean in Spring?

I want to provide an optional #Bean in my #Configuration file like:
#Bean
public Type method(Type dependency) {
// TODO
}
when dependency can't be found, the method should not be called.
How to do that?
You need to use ConditionalOnClass If using SpringBoot and Conditional in Spring since 4.0 See If using Spring
Example of SpringBoot :-
#Bean
#ConditionalOnClass(value=com.mypack.Type.class)
public Type method() {
......
return ...
}
Now the method() will be called only when com.mypack.Type.class is in classpath.
In addition to the accepted answer, you have to check if the dependency is initialized before calling any method which requires that dependency.
#Autowired(required = false)
Type dependency;
public Type methodWhichRequiresTheBean() {
...
}
public Type someOtherMethod() {
if(dependency != null) { //Check if dependency initialized
methodWhichRequiresTheBean();
}
}

Spring /#Beans annotation

I am reading spring doc. and I am wondering what difference is between these two examples. Do I need to create Bar #bean ?
public class AppConfig {
#Bean
public Foo foo() {
return new Foo(bar());
}
#Bean
public Bar bar() {
return new Bar();
}
}
VS
public class AppConfig {
#Bean
public Foo foo() {
return new Foo(bar());
}
public Bar bar() {
return new Bar();
}
}
In the first one, Bar is a Spring bean, whereas in the second one, it's not.
So, if Bar must be autowired with other Spring beans, or if it has Spring annotations (like Transactional, etc.), the second example won't work as expected: the Bar instance is a simple POJO, that Spring is not aware of.

Resources