Spring Autowiring - if object name needs to be same as beanId always? - java

I have defined bean in spring configuration something like -
<bean id="xyz" class="com.foo.Test">
and the class where I am using the bean is
package com.bar;
import com.foo.Test;
Class Demo {
#Autowired
Test xyz;
//Do operations of Test using abc now
}
what I am asking I tried below and it worked fine.
package com.bar;
import com.foo.Test;
Class Demo {
#Autowired
Test abc;
//Do operations of Test using abc now
}
So if keeping the bean id same as object name doesn't matter ?
Thanks.

If you autowire a bean and the spring context defines exactly one bean which is assignment compatible with the type you wire the bean to (in your case Test) then spring does not require any additional information.
If the spring context does define more than one bean which is assignment compatible with the type you wire the bean to you have to add the annotation #Qualifier and specify the identifier like this:
#Autowired
#Qualifier("xyz")
Test abc;
Spring Framework Reference Documentation:
#Autowired
#Qualifier

Related

How to load a single bean for testing in Spring boot without loading the whole context?

I have a class A that is dependent on bean B ( pretty simple bean, just a clock to be called ).
I want to unit test class A, how can this bean be loaded? #SpringBootTest loads the whole Context.
You should use the combination of two annotions:
#ExtendWith(SpringExtension.class)
#Import(
value = {
SomeSpringBean.class
}
)
whereinto #Import's value you can put your not mocking bean without spring-context building.
You can put through #Import any spring bean(class with #Configuration or #Component etc)
For mocking another bean in this test use #MockBean annotation.
The usage looks like that:
#ExtendWith(SpringExtension.class)
#Import(
value = {
SomeSpringBean.class
}
)
class SomeSpringTest {
#MockBean
private MockedBean mock;
#Autowired
private SomeSpringBean bean;
...
}
see more in javadoc:
Indicates one or more component classes to import — typically #Configuration classes.
Provides functionality equivalent to the element in Spring XML. Allows for importing #Configuration classes, ImportSelector and ImportBeanDefinitionRegistrar implementations, as well as regular component classes (as of 4.2; analogous to AnnotationConfigApplicationContext.register).
#Bean definitions declared in imported #Configuration classes should be accessed by using #Autowired injection. Either the bean itself can be autowired, or the configuration class instance declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly navigation between #Configuration class methods.

ComponentScan code smell? When running unit tests, I get Error creating bean, no qualifying bean of type, even though bean exists in Spring beans list

i have a config class in a config package that looks like this:
package com.x.y.appName.config
#ComponentScan(basePackageClasses = { Application.class })
#Configuration
public class AppConfig {
my project is failing on build within SomeClass that uses the AppConfig bean, saying:
Error creating bean with name 'someClass': Unsatisfied dependency
expressed through field 'appConfig'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
But when I stdout print the list of beans Spring is aware of, it lists appConfig there
SomeClass is also in the config package, and looks like this:
package com.x.y.appName.config;
#Configuration
public class SomeClass implements WebMvcConfigurer {
#Autowired
AppConfig appConfig;
but if i add this to SomeClass, it builds fine and all tests pass:
#ComponentScan("com.x.y.appName.config")
in the past ive never needed to ComponentScan the same package that another bean is also declared in
again to clarify, i can bootRun the app just fine, but this spring error is throwing during build or test. do i need to add something to the unit tests? I dont have unit tests for either of the above classes as they would be too frivolous. So what could be going on? Do I need to annotate other unit tests somewhere?

What are all the #Configuration naming rules for beans?

I have some integration tests that are supposed to mock out one of many beans in my system. To do this, I have a #Configuration that looks like this:
#Configuration
public class MockContext {
#Primary
#Bean
public RealBean realBean() {
return new MockBean();
}
}
I noticed that this method gets used if RealBean is a java class without #Component. But if RealBean is a #Component, I have to change this context method to look like this:
#Configuration
public class MockContext {
#Primary
#Bean
public RealBean getRealBean() {
return new MockBean();
}
}
Can anyone explain why I need to change this method name and where I can find all these rules? It takes a very long time to troubleshoot these "why isn't my MockContext working correctly?" issues.
FWIW, here's how I'm using this context in a test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {RealContext.class, MockContext.class})
#WebAppConfiguration
public abstract class AbstractIntegrationTest {
And my integration test will extend this class. I am using Spring Boot 1.2.4.RELEASE
You can have various beans registered with same type. But they need to have different names.
If you use #Bean annotation without name attribute, name of the bean is extracted from method name (in your case realBean/getRealBean).
When you use #Component annotation without attribute (which specifies bean name), name of the bean is extracted from method name where first letter is lowercased.
So with your first case, you get a name clash. You can't have two beans named realBean.
Your second example is without clash because bean annotated by #Component has name realBean and second bean registered via #Bean has name getRealBean.
#Primary annotation helps Spring choose which bean to pick if there are two of the same type and you inject by type. When you inject by name (usage of #Qualifier annotation), you can inject also secondary instance.

Spring #Autowired - what is happening in the background

Excuse me if this is has already been discussed, I could not find a satisfying answer.
I do not understand whats happening when i create a bean in Springframework and #Autowired it to a field in another bean. I understand the result of #Autowired and other annotations but i do not know how its done by Spring.
class Sample1{
//
}
class Sample2{
#Autowired
Sample1 sample1Bean;
}
<bean id="sample1Bean" class="...Sample1"/>
<bean id="sample2Bean" class="...Sample2"/>
My question is how does spring set the field sample1Bean in Sample2? i am not expecting a complete explanation, but a direction where i have to look would be great. Thanks.
The #Autowired, #Inject annotations are resolved by a BeanPostProcessor - specifically AutowiredAnnotationBeanPostProcessor. This bean post processor intercepts the creation(for cases where #Autowired is on constructors) of beans, setting of property on the beans to ensure that all the autowired fields are appropriately set.
Im no expert in Spring but I will answer what I know. When a spring powered web application starts up, Spring framework goes through bean instantiation process in the application context. While creating beans Spring checks the required dependencies for a given bean. It looks up a matching bean based on the required type of bean and autowires it when #Autowired annotation is specified.
In the above example, Spring will go through application context and create a bean(object) of type Sample1. When it will construct bean Sample2 it sees #Autowiredannotation and will look for instantiated bean of type Sample1. When it finds bean of type Sample1 it will inject that bean on Sample2 and finish creating Sample2. This is called dependency injection and is one of the very popular features of Spring framework.
Hope this helps.

Java/Spring Problem with #Service and #Autowired annotations

[spring 3.0.5]
[jboss 5.1]
I have several classes labeled as #Service, which implements thet same interface.
For example,
#Service(value="test1")
public TestImpl1 implements Test {}
#Service(value="test2")
public TestImpl2 implements Test {}
Next, I have the following structure
public SomeClass {
#Autowired
#Qualifier("test1")
Test test1;
#Autowired
#Qualifier("test2")
Test test2;
I am getting an exception (at deployment)
10:36:58,277 ERROR [[/test-web]] Servlet /test-web threw load()
exception
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
unique bean of type [pl.tests] is defined: expected single matching
bean but found 2: [test1, test2]
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.doReso lveDependency(DefaultListableBeanFactory.java:
796)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolv eDependency(DefaultListableBeanFactory.java:
703)
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostPro cessor
$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:
474)
Anyone know how to solve this?
T.
A few options:
Use #Resource(name="test1") in the injection point
can use the javax.inject.Qualifer mechanism. In short - you define an annotation (#Test) and annotate the annotation with #Qualifier. Then use #Autowired #Test on the injection point.
explicitly set qualifiers on the target bean. The docs say show only the xml version <qualifier />, but try adding #Qualifier("test1") on the service definition
Here is the documentation about it

Categories

Resources