A Spring container is the backbone of the framework. A container is basically a pool of beans created in a memory space by the framework when the application starts up. An API provided by the framework exposes methods to query these beans from the container.
We’ll start the chapter by looking at the containers and different categories. We’ll also look at details about concepts such as AutoWiring.
Understanding containers is an important task when working with the Spring Framework as they are crucial moving pieces in a Spring’s jig-saw puzzle.
During the startup process, the beans are instantiated, the associations and relationships are created, all the relationships are satisfied, and dependencies are injected. All named beans are available for querying using an API. Some beans are lazily loaded while others are loaded during the initialization of the container. This means that unless the bean is requested by our application or some other bean (as a part of dependency), the framework will not instantiate the bean, except loading singletons.
Spring containers primarily fall into two categories: Bean Factories
and Application Contexts—supported by the BeanFactory
and ApplicationContext
classes
respectively. The names are sort of misnomers, as they do not give any clue as to what these
containers are and what they do.
The BeanFactory
is a simple
container supporting basic dependency injection, whereas ApplicationContext
is an extension of BeanFactory
, which has few additional bells and
whistles.
In my personal opinion, I would vote for using ApplicationContext
over
BeanFactory
—I’ll tell you why in the next few sections!
The BeanFactory
is the simplest of the two types of containers Spring
has provided. The concrete factories must implement the org.springframework.beans.factory.BeanFactory
interface. This factory creates
and instantiates beans with all the dependent configurations as expected. So, when you query
a bean, it is obtained in your client as a fully functional instance, meaning all the
associations and relationships have already been created. The bean factory implementor can
also invoke the customized init-method
and the destroy-method
.
Spring provides a few of the implementations of BeanFactory
out of the box, the most common
being XmlBeanFactory
. As the name
suggests, it reads the configuration metadata from a XML file, basically
information about our beans.
Using the XmlBeanFactory
in a
client is very easy and straightforward. The following snippet shows the
code demonstrating how to instantiate the factory. The constructor takes
in an XML file passed into a FileInputStream
object:
// Instantiate the factory with your beans config file
BeanFactory
factory
=
XmlBeanFactory
(
new
FileInputStream
(
"trade-beans.xml"
));
// Use the factory to obtain your TradeService bean
TradeService
service
=
(
TradeService
)
factory
.
getBean
(
"tradeService"
);
The BeanFactory
is usually preferred in small device
applications such as mobile phones, etc, where resources are limited. If you are writing any
standard Java or JEE application, ideally you would ditch BeanFactory
to go with ApplicationContext
implementation. I recommend using the ApplicationContext
container unless
you have a strong reason not to.
The ApplicationContext
extends the BeanFactory
, thus all the functionality of BeanFactory
is already embedded in the ApplicationContext
container. It also provides some advanced features such as
application events, aspect functionality, and a few others as an added bonus. Ideally, we
can use this container straight away due to its extended functionality.
Similar to BeanFactory
implementations, there are few
implementations of ApplicationContext
that will soon be
our favorites:
FileSystemXmlApplicationContext
: This container
loads the definitions of the beans found in the XML file located in a specified file
system location. You should provide the path of the beans file to the constructor.
This container will most likely be used if we have an application that has a specific
location to load the config files rather than bundling them along with the deployed
code.
ClassPathXmlApplicationContext
: In this
container, the XML config file is read from the classpath by the container. As long as
the config file is anywhere in the classpath of our application, this container can
load it. You can also have the bean files in a jar file.
The only difference between the FileSystemXmlApplicationContext
and the
ClassPathXmlApplicationContext
is that this context does not
require the full path of the file, but expects to be in the classpath of the
application.
WebXmlApplicationContext
: This container loads
the bean definitions file within a web application. This context is used mostly in
Spring MVC projects or Java Web applications.
We have seen the usage of the ApplicationContext
type containers in the earlier chapters, but let’s recap the
usage again here. The ClassPathXmlApplicationContext
is instantiated with
a set of bean config files.
For example, the following snippet creates the container by loading the containers-beans.xml file.
ApplicationContext
ctx
=
new
ClassPathXmlApplicationContext
(
"containers-beans.xml"
);
Employee
employee
=
ctx
.
getBean
(
"employee"
,
Employee
.
class
);
The snippet also shows the mechanism of querying the Employee bean.
If we have to create our container with multiple config files, we instantiate the constructor with an array of Strings:
public
class
ApplicationContextClient
{
private
String
[]
configLocations
=
new
String
[]{
"containers-beans.xml"
,
"fundamentals-beans.xml"
};
public
void
testClasspathXmlApplicationContext
(){
ctx
=
new
ClassPathXmlApplicationContext
(
configLocations
);
Employee
employee
=
ctx
.
getBean
(
"employee"
,
Employee
.
class
);
Person
person
=
ctx
.
getBean
(
"person"
,
Person
.
class
);
System
.
out
.
println
(
employee
);
System
.
out
.
println
(
person
);
}
...
}
Please check the API documentation for various other ways of creating the container.
The FileSystemXmlApplicationContext
is no different from the
ClassPathXmlApplicationContext
—it accepts a config file with a file
path. The following code snippet shows the mechanism to create the
FileSystemXmlApplicationContext
container:
ApplicationContext
ctx
=
new
FileSystemXmlApplicationContext
(
"/src/main/resources/containers-beans.xml"
);
Employee
employee
=
ctx
.
getBean
(
"employee"
,
Employee
.
class
);
The choice of picking one container over the other depends on your application
deployment and environment setup across the organization. Some organizations tend to support
a central location for all the config files—this way, the config can be changed or tweaked
without having to rebuild and re-deploy the application. Because the file location is
static, the FileSystemXmlApplicationContext
is best suited in this
case.
Some projects may not have to read the configuration data from a centralized location,
but the config files are bundled and jarred up with the project itself. The
ClassPathXmlApplicationContext
is the preferred choice in this case. As
you may have already noticed, I have used ClassPathXmlApplicationContext
extensively in this book.
Beans are instantiated by the framework in more than one way. We have already seen in
previous chapters how the beans were instantiated using constructors. You should ideally
provide a constructor in your bean and corresponding metadata in the XML file. If the
constructor takes any arguments, we should pass them as constructor-arg
attributes in our config file. We will look into two other types
of instantiating the beans—using static methods and factories.
There may be instances where we need to use static methods on some classes to create their instances—the one pattern that comes to mind immediately is a Java Singleton. The framework provides this mechanism of creating the instances via the exposed static methods rather than constructors. This type of instantiating is well suited if your classes have static factories for creating the object instances.
The procedure is simple: we write a class with a static method that would create an
instance of that class. The following snippet shows an EmployeeFactory
class. This class follows the Java singleton pattern—a private constructor and a static
method instantiator.
public
class
EmployeeFactory
{
private
static
EmployeeFactory
instance
;
private
EmployeeFactory
()
{
}
public
static
EmployeeFactory
getEmployeeFactory
()
{
if
(
instance
==
null
)
{
instance
=
new
EmployeeFactory
();
}
return
instance
;
}
...
}
The static getEmployeeFactory()
returns the
instance of this class.
Now that our class with a static method is ready, the next step is
to define the bean in our config. The configuration of the bean is
similar to the ones we did earlier except that we add an additional
attribute factory-method
on the bean .
Let’s see how we can declare a EmployeeFactory
in the
XML file, using the factory-method
attribute:
<bean
name=
"employeeFactory"
class=
"com.madhusudhan.jscore.containers.factory.EmployeeFactory"
factory-method="getEmployeeFactory"></bean>
The factory-method
attribute invokes the respective
static method on the class—the EmployeeFactory
instance will be
instantiated by calling the factory-method
’s
getEmployeeFactory
method.
Note that the declaration does not mention the factory-method
being static anywhere. However,
it must be declared static if you wish to encounter no errors. Also note
that the return type method is not imperative (it should return a
non-void value); it is only known if you see the implementation of that
method in the declared class, unfortunately.
In the previous section, we created an object, using a static method. What if we wish to create the instance by using non-static methods?
Spring Framework does allow us to instantiate the beans by using non-static factory methods, too. Although it’s not straightforward, it’s not hard either to grasp.
The EmployeeCreator
is a simple class that creates
either employees or executives by using two factory methods. See the following code
snippet:
public
class
EmployeeCreator
{
public
Employee
createEmployee
()
{
return
new
Employee
();
}
public
Employee
createExecutive
()
{
Employee
emp
=
new
Employee
();
emp
.
setTitle
(
"EXEC"
);
emp
.
setGrade
(
"GRADE-A"
);
return
emp
;
}
}
The main crux of using factory methods is in the configuration. The
EmployeeCreator
bean is declared as a normal bean. The two other
beans—employee and executive are declared using two
attributes—factory-bean
and factory-method
. See the
snippet here before we understand the details:
<bean
name=
"employee"
factory-bean=
"employeeCreator"
factory-method=
"createEmployee"
/>
<bean
name=
"executive"
factory-bean=
"employeeCreator"
factory-method=
"createExecutive"
/>
<!-- the EmployeeCreator bean used by the above two beans -->
<bean
name=
"employeeCreator"
class=
"com.madhusudhan.jscore.containers.factory.EmployeeCreator"
/>
The factory-bean
attribute declared on the
employee
and executive
beans both refer to the
employeeCreator
bean. This is the convention to be followed when
working with non-static factory methods. The factory-method
points to the
actual method on the employeeCreator
(factory bean)—in this case, the
createEmployee
and createExecutive
methods on the
EmployeeCreator
class.
You should have noticed that we do not include the class attribute
in the bean definition at all. Take away points are that the actual bean
is referred by factory-bean
attribute, the respective methods by factory-method
attribute. Also, the factory methods are not static in the above
implementation.
In our earlier chapter, we have learned that init-method
and
destroy-method
attributes dictate the bean initialization and
destruction. These methods will allow us to do some housekeeping jobs during the bean’s
lifecycle. As you may have noticed, these attributes are used in the configuration but not in
our source code.
We may wish to implement such behavior on the beans programatically too. In such cases,
the Spring Framework provides us with this functionality by allowing us to implement our
classes with two interfaces—the InitializingBean
and
DisposableBean
interfaces. There is one method each in these
interfaces—the afterPropertiesSet
and destroy
methods,
respectively.
The LazyEmployee
wishes to work only THREE days a week—the
weekDays
variable representing this state is set via configuration on
the lazyEmployee
bean. See the bean definition here:
<bean
name=
"lazyEmployee"
class=
"com.madhusudhan.jscore.containers.lifecycle.LazyEmployee"
>
<property
name=
"weekDays"
value=
"THREE"
/>
</bean>
When the bean is intialized, the value is set to THREE as expected. However, someone
wishes to override this functionality (perhaps, the LazyEmployee
’s boss!)
resetting it to FIVE days—this reset has to be done after the bean has been created. In this
case, the InitializingBean
’s afterPropertiesSet
comes
to rescue.
What we need to do is to implement our LazyEmployee
class with the
InitializingBean
interface—like this:
public
class
LazyEmployee
implements
InitializingBean
{
private
String
weekDays
=
null
;
public
void
afterPropertiesSet
()
throws
Exception
{
System
.
out
.
println
(
"AfterPropertiesSet called"
);
weekDays
=
"FIVE"
;
}
...
}
The interface has only one method, afterPropertiesSet
, that needs to
be implemented. This method is called after all the properties are set
and bean is created. Note that the values of these properties are picked up from the config
file. In this case, the weekDays
value was already set in the XML file
with THREE. However, before handing over the already created bean to us, the framework
called the afterPropertiesSet
method which reset the value to
FIVE.
In essence, implementing the InitializingBean
interface provides the
opportunity to initialize (or reset) the bean’s configuration.
The DisposableBean
interface has only one callback
method—destroy
—which will be called before the Spring container shuts
down—thus giving an opportunity to do cleanup of the resources if any.
Continuing with the same example of LazyEmployee
, this time, the
class implements the DisposableBean
interface and its one method,
destroy
. The souce code is shown in the following snippet:
public
class
LazyEmployee
implements
DisposableBean
{
private
String
weekDays
=
null
;
public
void
destroy
()
throws
Exception
{
System
.
out
.
println
(
"Destroy called"
);
// do your cleanup here
}
...
}
When the context is closed by calling the close
method on the
ClassPathXmlApplicationContext
class, the destroy method will be
invoked—thus giving us the chance to perform housekeeping before the bean gets
reclaimed.
We know that there are two options for bean initialization or destruction functionality.
We can use init-method
(or destroy-method
) by
declaring them in configuration files. Or, we can achieve the same result by implementing
the InitialzingBean
’s afterPropertiesSet
(or
DispozableBean
’s destroy
) method in our
class.
Let me tell you—there’s another way of doing this job too—using
@PostConstruct
and @PreDestroy
annotations. We might
see these annotations in action when we learn about annotations in the coming
chapters.
You might be wondering what is the preferred option? My vote is always to the configuration side. In the programmatic callbacks, what we are doing is using the Spring’s interfaces—thus coupling our code to a third-party dependency. This restricts our future migration plans—should you wish to move to some other Dependency Injection framework (say, Google’s Guice), you would have to refactor the code to remove these dependencies.
Remember, the rule of thumb is to avoid vendor lockins as much as possible!
Spring allows us to use all the three types of callbacks that we have discussed so far. But there is a subtle difference if you use all of them in a project—the precedence of one over the other. Spring dictates that if all three types (annotation, programmatic, and config callbacks) are present, the order in which they take precedence is:
Annotation based—@PostConstruct
and
@PreDestroy
Programming based—afterPropertiesSet
and
destroy
Config based—the init-method
and
destroy-method
Sometimes, we may want to react to an event that happened in the container so we can do
some custom processing. For example, we want our FilePoller
component to
start polling a directory for incoming files after our container was
started. Framework has a mechanism to notify us when the context has been started (or
stopped). We’ll see the mechanics of this in a minute.
There may be a requirement to publish some messages from our beans too—for example, the
FilePoller
might notify interested parties to say that it has received a
file or it has processed an encrypted file, and so on. The Spring framework provides a way to
publish and listen to the custom events too.
The ApplicationContext
publishes certain types of
events when loading the beans. For example, a ContextStartedEvent
is published when the context is started and ContextStoppedEvent
is published when the context is stopped. We
can have our beans receive these events if we wish to do some processing on our side based on
these events. We can also publish our own events.
Let’s see the procedure involved in listening to the events first.
The ApplicationContext
publishes certain types of events when loading the beans. For example, a
ContextStartedEvent
is published when
the context is started and ContextStoppedEvent
is published when the
context is stopped.
We can let our beans receive these events to do some processing
based on these events. In order to listen to the context events, our
bean should implement the ApplicationListener
interface. This interface
has just one method: onApplicationEvent(ApplicationEvent event)
.
The ContextStartedEventListener is one such class that expects to
receive any events related to context’s startup actions.
The following example creates this class:
public
class
ContextStartedEventListener
implements
ApplicationListener
<
ContextStartedEvent
>
{
public
void
onApplicationEvent
(
ContextStartedEvent
event
)
{
System
.
out
.
println
(
"Received ContextStartedEvent application event:"
+
event
.
getSource
());
}
}
Whenever the ContextStartedEvent is published, this bean will receive it without fail.
Currently the onApplicationEvent
does not do anything apart from shouting
to the world that it has received the event. But we can do pretty much anything here—like
starting a brand new component, creating resource loaders, sending an email, and so
on.
Now that we have our event listener, the next step is to bind the listener to the context. We do this by declaring the bean in our config file as shown here:
<bean
name=
"contextStartEventListener"
class=
"com.madhusudhan.jscore.containers.event.ContextStartedEventListener"
/>
Once the context is started, the listener will receive a start event as expected.
Spring context publishes the following types of events:
ContextStartedEvent
This
event is published when the ApplicationContext
is started. All beans
receive a start signal once the ApplicationContext
is started. The
activities such as polling to database or observing a file system
can be started once we receive this type of event.
ContextStoppedEvent
This
is the opposite of the start event. This event is published when the
ApplicationContext
is stopped.
Our bean receives a stop signal from the framework so we can do
housekeeping on the bean.
ContextRefreshedEvent
A refresh event is emitted when the context is either refreshed or initialized.
ContextClosedEvent
This
event occurs when the ApplicationContext
is closed. From closed
state, a context cannot be restarted or
refreshed.
RequestHandledEvent
This is a web-specific event informing the receivers that a web request has been received.
For completeness, run the following client program which should start, stop, and refresh the context:
public
class
ContextEventListenerClient
{
private
ConfigurableApplicationContext
ctx
=
null
;
public
void
test
()
{
ctx
=
new
ClassPathXmlApplicationContext
(
"containers-events-beans.xml"
);
ctx
.
start
();
ctx
.
refresh
();
ctx
.
stop
();
}
public
static
void
main
(
String
args
[])
{
ContextEventListenerClient
client
=
new
ContextEventListenerClient
();
client
.
test
();
}
}
Our listener will receive the appropriate events.
It’s a fairly simple task to publish custom events. Let’s suppose we want to publish an event whenever we receive a file larger than 100Mb.
In order to prepare our application for publishing custom events, we need four code structures to develop: The publisher, the listener, the event, and the client. Let’s develop all of them here.
First we have to create an event by extending the ApplicationEvent
—as our HugeFileEvent
shown here:
public
class
HugeFileEvent
extends
ApplicationEvent
{
private
String
fileName
=
null
;
public
HugeFileEvent
(
Object
source
,
String
fileName
)
{
super
(
source
);
this
.
fileName
=
fileName
;
}
}
As mentioned earlier, the event class must extend the
ApplicationEvent
class.
Now, we need to create a publisher—HugeFileEventPublisher
in this
case. This class implements Framework’s ApplicationEventPublisherAware
interface so it can be injected with a ApplicationEventPublisher
object
by calling the setApplicationEventPublisher
method. The
ApplicationEventPublisher
has one method—publishEvent
—which is used to publish
events.
public
class
HugeFileEventPublisher
implements
ApplicationEventPublisherAware
{
private
ApplicationEventPublisher
pub
=
null
;
public
void
setApplicationEventPublisher
(
ApplicationEventPublisher
pub
)
{
this
.
applicationEventPublisher
=
pub
;
}
public
void
publish
(
String
fileName
){
System
.
out
.
println
(
"Publishing a HugeFileEvent, file is: "
+
fileName
);
HugeFileEvent
hugeFileEvent
=
new
HugeFileEvent
(
this
,
fileName
);
pub
.
publishEvent
(
hugeFileEvent
);
}
}
The third piece of code is our listener—no point in publishing events if there is no
listener (a bit like one-sided love!). We have already seen the implementation of a listener
in our earlier section—here’s the HugeFileEventListener
code shown for
completeness:
public
class
HugeFileEventListener
implements
ApplicationListener
<
HugeFileEvent
>
{
public
void
onApplicationEvent
(
HugeFileEvent
event
)
{
System
.
out
.
println
(
"Received Event:"
+
event
.
getSource
());
}
}
Now that we have the basic classes in place, all we need is to wire them up and call them from a client. We need to declare the publisher and listener beans as shown in the following snippet:
<bean
name=
"hugeFileEventPublisher"
class=
"com.madhusudhan.jscore.containers.event.publish.HugeFileEventPublisher"
/>
<bean
name=
"hugeFileEventListener"
class=
"com.madhusudhan.jscore.containers.event.publish.HugeFileEventListener"
/>
Let’s create a test client to make these code pieces work for us:
public
class
HugeFileEventClient
{
private
ApplicationContext
ctx
=
null
;
private
HugeFileEventPublisher
hugeFileEventPublisher
=
null
;
public
void
test
()
{
ctx
=
new
ClassPathXmlApplicationContext
(
"containers-events-publish-beans.xml"
);
hugeFileEventPublisher
=
ctx
.
getBean
(
"hugeFileEventPublisher"
,
HugeFileEventPublisher
.
class
);
hugeFileEventPublisher
.
publish
(
"huge-file.txt"
);
}
public
static
void
main
(
String
args
[])
{
HugeFileEventClient
client
=
new
HugeFileEventClient
();
client
.
test
();
}
}
Once the context is created, fetch the publisher bean and invoke the publish method to publish an event. The event is created in the publish and is sent to the context. The listener then gets this event (framework delivers the event to all the context listeners) and invokes the appropriate processing.
One important thing to keep in mind when working with Spring events handling is that Spring’s event handling is single threaded—it is primarily synchronous in nature. That is, if an event is published, until and unless all the receivers get the message, the processes are blocked and the flow will not continue. If you have multiple listeners listening for an event, this single-thread model may hamper the performance of the application. Hence, care should be taken when designing your application if event handling is to be used.
Personally I would not depend on Spring’s Events as it is not only single threaded but also locks us to the framework. You have to implement the framework’s interfaces, thus making it worse when you wish to implement other frameworks in the future. There are plenty of open source alternatives such as EventBus, Event Listener Framework (elf), or even Spring’s Integration (although I admit Spring’s Integration or JMS might be overkill for such a simple event mechanism).
See my other book Just Spring Integration if you’re interested in learning Spring’s Integration.
When creating a bean, we used to set the properties of the bean by using either property
or constructor-arg
attributes. However, to save us typing, Spring has a sophisticated concept of
autowiring these relationships and dependencies. This means that you
don’t have to explicitly mention the properties and their values, but setting the autowire
property to a specfic value allows the framework to wire them with appropriate properties.
This mechanism is called autowiring.
By default, there is no autowiring enabled (the same as setting the autowire attribute to “no”). Also, note that autowiring works only for references—the normal Java primities and Strings cannot be set using autowiring.
There are fundamentally three variations of autowiring, by name, by type, by constructor, as explained in the following sections—four if you consider mixing autowiring and explicit wiring!
When autowiring byName
is enabled, the framework
tries injecting the dependencies by matching the names to the property fields.
This is easily understood by an example. Let’s say we have a
TradeReceiver
bean which has two properties—named as
tradePersistor
and tradeTransformer
beans. When we
choose the autowiring mechanism to be byName
, Framework will locate these
dependednt beans (as long as they are named exactly as the
TradeReceiver
’s properties) from the context and inject into the
TradeReceiver
bean.
First, here’s the definition of the TradeReceiver
class here:
public
class
TradeReceiver
{
private
TradePersistor
tradePersistor
=
null
;
private
TradeTransformer
tradeTransformer
=
null
;
...
}
Our usual way is to define all three beans in the XML config file,
then pass the references of persistor and transformer to TradeReceiver
. However, with autowiring, you
don’t have to go this far.
In order to enable autowiring byName
, we need to set the attribute
autowire
to byName
on the bean in the config:
<bean
name=
"tradeReceiver"
class=
"com.madhusudhan.jscore.containers.autowire.TradeReceiver"
autowire="byName"/><bean
name=
"tradePersistor"
class=
"com.madhusudhan.jscore.containers.autowire.TradePersistor"
/>
<bean
name=
"tradeTransformer"
class=
"com.madhusudhan.jscore.containers.autowire.TradeTransformer"
/>
In addition to this, we have defined the
tradePersistor
and
tradeTransformer
beans in the config too.
Did you notice we did not define any properties such as tradePersistor
or tradeTransformer
on the
tradeReceiver
bean? We would have normally set these properties by
declaring them explicitly as shown here:
<bean
name=
"tradeReceiver"
class=
"com.madhusudhan.jscore.containers.autowire.TradeReceiver"
>
<property
name=
"tradePersistor"
ref=
"tradePersistor"
/>
<property
name=
"tradeTransformer"
ref=
"tradeTransformer"
/>
</bean>
How does this work then? Well, the attribute autowire="byName"
does the magic for us behind the scenes. This setting
instructs the container to look for two properties with the same names as
tradeReceiver
’s variable names (tradePersistor
and
tradeTransformer
in this case). The container looks at all the beans
instantiated and tries to match them with the beans with the variable names of
tradeReceiver
. If matches are found, it will inject those beans
straightaway. Otherwise, it will throw exceptions thus notifying the bean creation issues.
Note that the autowiring principle works for only references. You have to mix and match the
autowiring and explicit wiring (hold on, we will look at mixing these wiring types in couple
of minutes).
Similar to byName
, we need to
set the autowire
property to byType
in order to enable this type of
autowiring. In this case, instead of looking for a bean with the same
names, the container searches for the same types.
Taking the same example of TradeReceiver
, setting the autowire="byType"
tells the container that it
should look for a bean of type TradePersistor
and another one with a type of
TradeTransformer
.
<bean
name=
"tradeReceiver"
class=
"com.madhusudhan.jscore.containers.autowire.TradeReceiver"
autowire="byType"/>
If the container finds the appropriate types, it will inject them
into the bean. In the above case,
framework looks for two types,
com.madhusudhan.jscore.containers.autowire.TradePersistor
and
in the config file. If it finds them, they will be injected into the
com.madhusudhan.jscore.containers.autowire.TradeTransformer
tradeReceiver
bean. However, if it
finds more than one bean with the same type defined in the config, a
fatal exception is thrown.
It’s not that hard to guess about our next autowiring counterpart—autowiring by constructor. This is similar to byType but applies to bean’s constructor arguments only. As the name suggests, the constructor argument will be satisfied by searching for that type in the context. That is, if a bean has a constructor that takes an argument of another bean type, the container looks for that reference and injects it.
For example, we define a TradePersistor
class with a
single constructor that takes a datasource
object:
public
class
TradePersistor
{
public
TradePersistor
(
DataSource
datasource
){
..}
}
If
we enable autowiring by constructor, the container looks for an object of the type DataSource
and injects it into the TradePersistor
bean. You enable autowiring by constructor as shown here:
<bean
name=
"tradePersistor"
class=
"com.madhusudhan.jscore.containers.autowire.TradePersitor"
autowire="constructor"/>
We can get the best of both worlds by using autowiring and explicit wiring. Any ambiguities encountered while autowiring can be dealt with using explicit wiring.
For example, in the following snippet, the tradeReceiver
is injected
with two beans—the tradePersitor
injected explicitly
using our good old way, while the tradeTransformer
is
wired automatically using a byName
variation.
<bean
name=
"tradeReceiver"
class=
"com.madhusudhan.jscore.containers.autowire.TradeReceiver"
autowire="byName"><!-- The tradePersistor is set traditionally -->
<property
name=
"tradePersistor"
ref=
"tradePersistor"
/>
</bean>
<bean
name=
"tradePersistor"
class=
"com.madhusudhan.jscore.containers.autowire.TradePersistor"
/>
<bean
name=
"tradeTransformer"
class=
"com.madhusudhan.jscore.containers.autowire.TradeTransformer"
/>
We can also switch off autowiring for specific beans should we wish to do so. All we
need to do is to set autowire-candidate to false on the bean definition—see here for an
example—the tradePersistor
is not interested in participating in
autowiring mode:
<bean
name=
"tradePersistor"
class=
"com.madhusudhan.jscore.containers.autowire.TradePersistor"
autowire-candidate="false"/>
Although autowiring saves us from writing extra metadata declarations, personally I wouldn’t go for it. I prefer the explicit wiring style—less ambiguity and more readability.
This chapter completes our journey into core Spring. It explains the fundamentals of containers and their usage. It then delves into using autowiring beans where you do not have to set properties on the beans. It then explains various ways of instantiating the beans, such as static methods or factory methods. We have also seen event handling supported by the framework.
One of the important aspect of Spring is its support for enterprise features such as Spring JMS and Database. The next chapter explains the simplification Spring has brought into the Java messaging world.
3.144.30.62