autowire byType according to Spring 4.1.6 to Documentation - spring

Allows a property to be autowired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown, which indicates that you may not use byType autowiring for that bean. If there are no matching beans, nothing happens; the property is not set. - FROM SPRING REFERENCE GUID 4.1.6
<bean id="person" class="autowire.Person" autowire="byType" />
<bean id="invisible" class="autowire.Ability" >
<property name="skill" value="Invisible" />
</bean>
<bean id="invisible2" class="autowire.Ability" >
<property name="skill" value="Invisible" />
</bean>
Class Definitions:
package autowire;
public class Person
{
private Ability ability;
//...
}
package autowire;
public class Ability {
private String skill;
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
}
I was able to define 2 beans of same type of class "autowire.Ability". I didnt get the Fatal exception. Is my understanding correct ?

You're almost there (to get the error). You need to tell spring which class attributes need to be autowired. Annotate Person.ability with #Autowired and you should get the error.
import org.springframework.beans.factory.annotation.Autowired;
public class Person
{
#Autowired
private Ability ability;
//...
}
Or even better create a constructor and autowire it, as injecting attributes is considered a bad practice.
public class Person
{
private Ability ability;
#Autowired
public Person(Ability ability) {
this.ability = ability;
}
//...
}
Spring doesn't assume which attributes need to be injected (autowired) so you need to specify which ones you want to inject.

The behavior you're seeing is correct, you can define as many beans of the same type as you want, problem arises when an Autowired bean(Component, Service, etc), expects a dependency of certain type and it cannot resolved because there are many that matches the field definition, for example:
If Person is declared as a #Component and declare an #Autowired field of type Ability, for example:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class Person {
#Autowired
private Ability ability;
}
Having the two beans invisible and invisible2 would cause the expected exception because Spring won't be able to know which of the two beans need to be injected in Person.
To run this example you will need to enable a Scan application context.
Hope this helps,
José Luis

Related

Wiring multiple beans with the same dependency via Spring Boot #Configuration

In older Spring MVC apps, where you'd specify application.xml and declare your app's beans so that Spring DI could instantiate them and wire them together, you might have something like this:
<bean id="chargeFactory" class="com.example.myapp.ChargeFactory" />
<bean id="paymentService" class="com.example.myapp.DefaultPaymentService">
<ref id="chargeFactory"/>
</bean>
<bean id="chargeAuditor" class="com.example.myapp.ChargeAuditor">
<ref id="chargeFactory"/>
</bean>
Which might help wire up the following code:
public interface PaymentService {
public void makePayment(Payment payment);
}
public class DefaultPaymentService implements PaymentService {
#Autowired
private ChargeFactory chargeFactory;
#Override
public void makePayment(Payment payment, String key) {
Charge charge = chargeFactory.createCharge(key);
charge.doCharge(payment);
}
}
public class ChargeAuditor {
#Autowired
private ChargeFactory chargeFactory;
public void auditAllCharges(String key) {
List<Charge> charges = chargeFactory.getAllCharges(key);
// blah whatever
}
}
How do you accomplish the same bean wiring in Spring Boot with the #Configuration class? For example:
#Configuration
public class MyAppInjector {
#Bean
public ChargeFactory chargeFactory() {
return new ChargeFactory();
}
#Bean
public PaymentService paymentService() {
return new DefaultPaymentService(chargeFactory());
}
#Bean
public ChargeAuditor chargeAuditor() {
return new ChargeAuditor(chargeFactory());
}
}
This might work but introduces some issues:
It would force me to have to write value constructors for all my classes, which goes against everything I see in literally every tutorial/article I've come across. Plus, if I had to do that, then there's no real value to #Autowired anyways...
At this point I'm essentially doing "DIY DI", which is OK, except I'm trying to deliberately use Spring DI :-)
Every time I call chargeFactory() I'm getting a new (prototype-style) ChargeFactory instance. Maybe I want a singleton. Using this approach I have to hand-roll my own singleton implementation.
Sure, I can do all of this, but I feel like I'm flagrantly misusing/misunderstanding how #Configuration is supposed to be used, because it seems like I'm introducing a whole lot of DIY/homegrown code to solve something Spring DI should be able to do for me.
How would I reference the chargeFactory bean and wire it into both the "provider methods" for the paymentService and chargeAuditor beans? Again, looking for the Java-based #Configuration solution instead of writing an XML document to define the wirings.
I found this article which seems to be the only tutorial/documentation (surprisingly) on wiring Spring Boot apps via #Configuration (which leads me to believe there might be other/better methods...), but it does not address:
How to specify singleton vs prototype bean instantiation patterns
If multiple instances of a bean-class exist, how do I specify which instance gets wired into which dependency?
How do I get around not defining value constructors for all my classes, and just let Spring/#Autowired inject fields automagically?
When you call chargeFactory() , spring won't create new instance everytime. Give it a try and see. Same object will be returned. Anyways
You can do something like this.
#Bean
public PaymentService paymentService(ChargeFactory chargeFactory) { return new DefaultPaymentService(chargeFactory); }

Injecting 2 bean with same class name

I have a app 'app_test' which consists a class TestClass with #Service anotation. I have a library class 'lib_test' with bean in XML file with id=''TestClass'. Both are in different package.
I m injecting #Service bean as follows
Import com.app.TestClass
Class TestController
{
Private final TestClass testClass;
#Inject
TestController (TestClass testClass)
{
This.testClass =testClass;
}
}
It should inject by type since they are in different package. But the controller is giving qualified bean not found.
I can resolve it by giving #Qualifier and giving name to #Service. But y is it needed? Since both are in different package it should autowire by type right? Or m missing some concept?
Although they are in different packages if they are of the same type Spring does not know which to use
I'd suggest marking any service class with #Primary.
package com.app.TestClass
#Primary
#Repository
public class TestClass implements XXX
This way it will be selected as the default autowire candididate, with no need to autowire-candidate on the other bean.
Also, rather than using #Autowired #Qualifier, I find it more elegant to use #Resource for picking specific beans.
I've always found this a strange limitation of Spring's standard bean naming convention. It does not include the package part of the class in the name leading to duplicates in large projects when classes have the same name.
This is why I always configure Spring projects with a different BeanNameGenerator:
public class CustomAnnotationConfigWebApplicationContext extends AnnotationConfigWebApplicationContext {
private BeanNameGenerator qualifiedAnnotationBeanNameGenerator = new QualifiedNameAnnotationBeanNameGenerator();
#Override
protected BeanNameGenerator getBeanNameGenerator() {
return this.qualifiedAnnotationBeanNameGenerator;
}
}
And the generator:
public class QualifiedNameAnnotationBeanNameGenerator extends AnnotationBeanNameGenerator {
#Override
protected String buildDefaultBeanName(BeanDefinition definition) {
String qualifiedName = definition.getBeanClassName();
return Introspector.decapitalize(qualifiedName);
}
}
With this setup, common class names that are in different packages are automatically recognized as being different and the correct one gets injected.

When autowiring use would be beneficiary with example

I have recently learned concept of autowiring in spring. When I was trying to understand in which particular scenarios spring autowiring can be useful
I came up with the below two reasons from one of the questions asked in our stakoverflow forum.
1.I wanted to read values from a property file and inject them into a bean. Only way I could figure out how to do this at start up of my app was to
wire the bean in XML (and inject the properties.) I ended up using the "byName" attribute (because the bean was also marked as #Component) and then
used #Autowired #Qualifier("nameIChose") when injecting the bean into another class. It's the only bean I've written that I wire with XML.
2.I've found autowiring useful in cases where I've had a factory bean making another bean (whose implementation class name was described in a system
property,so I couldn't define the all wiring in XML). I usually prefer to make my wiring explicit though;
Can any body please give me some code snippet example of the above situations that would make my understanding of autowiring more clearer?
Here is an example of injecting properties into a bean.
Using field injection:
#Component
public class YourBean {
#Value("${your.property.name}")
private String yourProperty;
}
Using constructor injection:
#Component
public class YourBean2 {
private String yourProperty;
#Autowired
public YourBeans2(#Value("${your.property.name}") String yourProperty) {
this.yourProperty = yourProperty;
}
}
The following is a super simple example of autowiring various beans
#Component
public class Foo {
public void doSomething() {
}
}
#Component
public class Bar {
private Foo foo;
#Autowired
public Bar(Foo foo) {
this.foo = foo;
}
public void doSomethingElse() {
foo.doSomething();
}
}
In the previous example, no XML configuration of Foo and Bar needs to be done, Spring automatically picks up the beans because of their #Component annotation (assuming of course that component scanning has been enabled)

Autowiring doubts in spring?

After going thru autowiring concept
i have got some questions. These are:-
If i need to autowire below class byType or byName , is it mandatory to have setStudent() method in class College?
public class College {
private Student student1;
private String registration1;
}
<bean id="student1" class="Student"/> - in case of byname it will look into id attribute and in case of bytype it will look for class attribute in above
Stetement. Right? If incase it finds two bean dean tags for the same type it will throw fatal error in case of bytype. Correct?
autodetect Scenario chooses constructor or byType through introspection of the bean class. If a default constructor is found, the byType mode
will be applied.
My question here if default constructor is not found and constructor with argument is found then autowire by constructor
will be applied. Correct?
Do we need to specify #Autowired somewhere in College to apply the autowiring. As i can see this in this example
but nothing is specified here
1), 4) There are two separate ways of autowiring in Spring: XML-based and annotaion-based.
XML-based autowiring is activated from XML config, as described here. In the end, it will call setter method, so setStudent() method is required here.
Annonation-based autowiring, on the other hand, is performed via reflection magic. It attempts to fill everything you mark with #Autowired annotation. In fact, it can set private field with no accessors, as in
public class Foo {
#Autowired private Thingy thing; // No getThing or setThing methods
private void doStuff() {
// thing is usable here
}
}
For #Autowired annotaion to work, you will need to define corresponding bean post-processor; it is done by adding the following line to xml config:
<context:annotation-config/>
Note, that these two autowiring methods are independant, and it is possible(but not recommended) to use them simultaneously. In that case, xml autowiring will override annotations.
2) In general, autowiring will fail, if it cannot find one and only one candidate for injection. So, in your case, it will fail with exception upon container creation. There are some fallback quirks, but in general it works reliably.
3) Yes, documentaion says so.
About byName and byType autowiring. While byName autowiring simply tries to match bean name (can be specified with id attribute), byType is a bit more complex than class attribute lookup. It searches beans by type, and it will match interfaces. Example:
public interface SomeService {
void doStuff();
}
public class SomeServiceImpl implements SomeService {
#Override public void doStuff() {
// Implementation
};
}
public class ServiceUser {
#Autowired
private SomeService someService; // SomeServiceImpl instance goes here
}
P.S. You are referencing two different versions of Spring in your question, 2.5 and 3.0. Autowiring behavior is same in both.
In Addition if you are using #Autwired annotation you need to mark the classes as candidates for autowiring. It should be done by using one of these annotations:
#Repository
#Service
#Component
#Controller
and of cause you can configure it in different scopes:
#Scope("prototype")
#Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
Hope it makes it more clear.

Spring 3 DI using generic DAO interface

I'm trying to use #Autowired annotation with my generic Dao interface like this:
public interface DaoContainer<E extends DomainObject> {
public int numberOfItems();
// Other methods omitted for brevity
}
I use this interface in my Controller in following fashion:
#Configurable
public class HelloWorld {
#Autowired
private DaoContainer<Notification> notificationContainer;
#Autowired
private DaoContainer<User> userContainer;
// Implementation omitted for brevity
}
I've configured my application context with following configuration
<context:spring-configured />
<context:component-scan base-package="com.organization.sample">
<context:exclude-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
</context:component-scan>
<tx:annotation-driven />
This works only partially, since Spring creates and injects only one instance of my DaoContainer, namely DaoContainer. In other words, if I ask userContainer.numberOfItems(); I get the number of notificationContainer.numberOfItems()
I've tried to use strongly typed interfaces to mark the correct implementation like this:
public interface NotificationContainer extends DaoContainer<Notification> { }
public interface UserContainer extends DaoContainer<User> { }
And then used these interfaces like this:
#Configurable
public class HelloWorld {
#Autowired
private NotificationContainer notificationContainer;
#Autowired
private UserContainer userContainer;
// Implementation omitted...
}
Sadly this fails to BeanCreationException:
org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.organization.sample.dao.NotificationContainer com.organization.sample.HelloWorld.notificationContainer; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.organization.sample.NotificationContainer] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Now, I'm a little confused how should I proceed or is using multiple Dao's even possible. Any help would be greatly appreciated :)
Ok, I think I've found a fairly reasonable solution for this puzzle. One way of dealing with this would be creating interface and implementations for each and every entity in my domain model (as Espen pointed out in his answer earlier). Now, consider having hundreds of entities and respectively hundreds of implementations. That wouldn't feel right, would it?
I've discarded strongly typed sub-interfaces and I'm using generic interface instead:
#Service // Using #Service annotation instead #Configurable as Espen pointed out
public class HelloWorld {
#Autowired
private DaoContainer<Notification> notificationContainer;
#Autowired
private DaoContainer<User> userContainer;
// Implementation omitted
}
Implementation for my DaoContainer interface would look something like this:
#Repository
public class DaoContainerImpl<E extends DomainObject> implements DaoContainer<E> {
// This is something I need in my application logic
protected Class<E> type;
public int getNumberOfItems() {
// implementation omitted
}
// getters and setters for fields omitted
}
And finally application context:
<context:spring-configured />
<context:component-scan base-package="com.organization.sample">
<context:exclude-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
</context:component-scan>
<bean class="com.organization.sample.dao.DaoContainerImpl" id="userContainer">
<property name="type" value="com.organization.sample.domain.DiaryUser" />
</bean>
<bean class="com.organization.sample.dao.DaoContainerImpl" id="notificationContainer">
<property name="type" value="com.organization.sample.domain.DiaryNotification" />
</bean>
So basically I couldn't get pure generic autowiring to work, but this solution works for me (at least for now) :)
It's possible to autowire as many bean as you like.
But when you're using autowiring by type, it can be only one of bean of each interface. Your error message says you have none bean available in the Spring container of given interface.
A solution:
Your missing DAO implementations:
#Repository
public class NotificationContainerImpl implements NotificationContainer {}
#Repository
public class UserContainerImpl implements UserContainer {}
Your service class:
#Service
public class HelloWorld {
#Autowired
private NotificationContainer notificationContainer;
#Autowired
private UserContainer userContainer;
// Implementation omitted...
}
I replaced the #Configurable annotation with #Service. #Configurable is used together with AspectJ and is not what you want here. You must use #Component or a specialization of it like #Service.
Also remember to have all your Spring components inside your com.organization.sample package to enable the Spring container to find them.
I hope this helps!

Resources