Tuesday, January 14, 2014

Spring Course: V19-V23 Autowiring

as we know, to wire the beans together we were using <constructor-arg> or <property>.
there are other ways to wire beans:

1- Autowire ByType
lets say we have the following:
public interface LogWriter {...}
public class FileWriter implements LogWriter {...}
public class ConsoleWriter implements LogWriter {...}
public class Logger {
private ConsoleWriter consoleWriter;
private FileWriter fileWriter;
...
}

so in beans.xml, we can have the following:
<bean id="logger" class="Logger" autowire="byType"></bean>
<bean id="consolewriter" class="ConsoleWriter"></bean>
<bean id="filewriter" class="FileWriter"></bean>

autowire byType means that Spring will check what TYPE of beans that needed from this class are, and will autowire them (in this case logger needs a bean from the type ConsoleWriter and FileWriter).

in case we have something like this in beans.xml:
<bean id="logger" class="Logger" autowire="byType"></bean>
<bean id="consolewriter" class="ConsoleWriter"></bean>
<bean id="consolewriter1" class="ConsoleWriter"></bean>
<bean id="filewriter" class="FileWriter"></bean>

we have autowire byType, however we have 2 beans of type ConsoleWriter, Spring will throw an exception because it cannot know which bean to wire.

another thing, lets say that Logger class is defined like this:
public class Logger {
private LogWriter writer;
...
}
now the Logger class has a property of type LogWriter (the interface).
and beans.xml looks like this:
<bean id="logger" class="Logger" autowire="byType"></bean>
<bean id="consolewriter" class="ConsoleWriter"></bean>
<bean id="filewriter" class="FileWriter"></bean>

this will throw an exception, because both ConsoleWriter and FileWriter implement the LogWriter Interface, Spring doesnt know which one to AutoWire.

2- Auotwire byName
the wiring will happen based on the setMethod name (sure without the "set"),
public class Logger {
private ConsoleWriter consoleWriter;
private FileWriter fileWriter;
public void setXxxWriter(ConsoleWriter writer) {...}
public void setFileWriter(FileWriter fileWriter) {...}
}

in beans.xml you can write:
<bean id="logger" class="Logger" autowire="byName"></bean>
<bean id="xxxWriter" class="ConsoleWriter"></bean>
<bean id="fileWriter" class="FileWriter"></bean>

as you can see xxxWriter matches with setXxxWriter, and fileWriter matches with setFileWriter.

3-Autowire byConstructor
in this case Spring will check the constructor requirement, for example lets say we have this constructor in Logger:

public Logger(ConsoleWriter x)

the bean definition
<bean id="logger" class="Logger" autowire="byConstructor"></bean>
will make spring checks the TYPEs that are required by the constructor, in this case we need a bean of type ConsoleWriter, Spring will search for a bean of this type.

Spring Default Autowiring:
you can define a default auto wiring for all beans by writing:
<beans default-autowire="byName" >
       <bean ....>
       <bean ...>
</beans>

in addition you can use default-autowire-candidates to provide a pattern for bean names that can be used for autowiring. for example
<beans default-autowire="byName"  default-autowire-candidates="consoleWriter,fileWriter" >
in this case only consoleWriter and fileWriter beans will be used for wiring, this is a way to solve bean wiring ambiguity.

or you can define it as a regular expression something like
<beans default-autowire="byName"  default-autowire-candidates="*Writer" >

Removing Autowire Ambiguity
lets say we have this
<bean id="logger" class="Logger" autowire="byType"></bean>
<bean id="consolewriter" class="ConsoleWriter"></bean>
<bean id="consolewriter1" class="ConsoleWriter"></bean>
<bean id="filewriter" class="FileWriter"></bean>

as we mentioned this will throw an exception because we have 2 beans of type ConsoleWriter and spring cannot know which one to use,

you can solve this issue by autowire-candiate="false"

<bean id="logger" class="Logger" autowire="byType"></bean>
<bean id="consolewriter" autowire-candidate="false" class="ConsoleWriter"></bean>
<bean id="consolewriter1" class="ConsoleWriter"></bean>
<bean id="filewriter" class="FileWriter"></bean>

Spring will know now that this bean cannot be used for autowiring and will use the other bean.

another way to fix it is by using primary="true"
<bean id="logger" class="Logger" autowire="byType"></bean>
<bean id="consolewriter" primary="true" class="ConsoleWriter"></bean>
<bean id="consolewriter1" class="ConsoleWriter"></bean>
<bean id="filewriter" class="FileWriter"></bean>

this will tell spring that i am the one to be used for autowiring

No comments:

Post a Comment