As was discussed in the chapter introduction, the
org.springframework.beans.factory
package provides basic
functionality for managing and manipulating beans, including in a
programmatic way. The org.springframework.context
package
adds the ApplicationContext
interface, which
extends the BeanFactory
interface, in
addition to extending other interfaces to provide additional functionality
in a more application framework-oriented style. Many
people use the ApplicationContext
in a
completely declarative fashion, not even creating it programmatically, but
instead relying on support classes such as
ContextLoader
to automatically instantiate an
ApplicationContext
as part of the normal
startup process of a J2EE web application.
To enhance BeanFactory
functionality in a
more framework-oriented style the context package also provides the
following functionality:
Loading of multiple (hierarchical) contexts, allowing each to be focused on one particular layer, such as the web layer of an application, through the HierarchicalBeanFactory interface.
Event publication to beans implementing the ApplicationListener interface, through the use of the ApplicationEventPublisher interface.
3.13.1 Internationalization using
MessageSource
The ApplicationContext
interface
extends an interface called MessageSource
,
and therefore provides internationalization (i18n) functionality. Spring
also provides the interface
HierarchicalMessageSource
, which can resolve
messages hierarchically. Together these interfaces provide the foundation
upon which Spring effects message resolution. The methods defined on these
interfaces include:
-
String getMessage(String code, Object[] args, String
: The basic method used to retrieve a
default, Locale loc)
message from theMessageSource
. When no
message is found for the specified locale, the default message is
used. Any arguments passed in become replacement values, using the
MessageFormat
functionality provided by
the standard library. -
String getMessage(String code, Object[] args, Locale
: Essentially the same as the previous method, but
loc)
with one difference: no default message can be specified; if the
message cannot be found, a
NoSuchMessageException
is thrown. -
String getMessage(MessageSourceResolvable resolvable,
: All properties used in the preceding
Locale locale)
methods are also wrapped in a class named
MessageSourceResolvable
, which you can
use with this method.
When an ApplicationContext
is loaded,
it automatically searches for a
MessageSource
bean defined in the context.
The bean must have the name messageSource
. If such a
bean is found, all calls to the preceding methods are delegated to the
message source. If no message source is found, the
ApplicationContext
attempts to find a
parent containing a bean with the same name. If it does, it uses that bean
as the MessageSource
. If the
ApplicationContext
cannot find any source
for messages, an empty DelegatingMessageSource
is
instantiated in order to be able to accept calls to the methods defined
above.
Spring provides two MessageSource
implementations, ResourceBundleMessageSource
and
StaticMessageSource
. Both implement
HierarchicalMessageSource
in order to do
nested messaging. The StaticMessageSource
is rarely
used but provides programmatic ways to add messages to the source. The
ResourceBundleMessageSource
is shown in the
following example:
<beans
> <bean
id
="messageSource"
class
="org.springframework.context.support.ResourceBundleMessageSource"
> <property
name
="basenames"
> <list
> <value
>format</value
> <value
>exceptions</value
> <value
>windows</value
> </list
> </property
> </bean
> </beans
>
In the example it is assumed you have three resource bundles defined
in your classpath called format
,
exceptions
and windows
. Any request
to resolve a message will be handled in the JDK standard way of resolving
messages through ResourceBundles. For the purposes of the example, assume
the contents of two of the above resource bundle files are…
# in format.properties message=Alligators rock!
# in exceptions.properties argument.required=The'{0}'
argument is required.
A program to execute the MessageSource
functionality is shown in the next example. Remember that all
ApplicationContext
implementations are also
MessageSource
implementations and so can be cast to
the MessageSource
interface.
public
static
void
main(String[] args) { MessageSource resources =new
ClassPathXmlApplicationContext("beans.xml"
); String message = resources.getMessage("message"
, null,"Default"
, null); System.out.println(message); }
The resulting output from the above program will be…
Alligators rock!
So to summarize, the MessageSource
is defined
in a file called beans.xml
, which exists at the root of
your classpath. The messageSource
bean definition
refers to a number of resource bundles through its
basenames
property. The three files that are passed in
the list to the basenames
property exist as files at
the root of your classpath and are called
format.properties
,
exceptions.properties
, and
windows.properties
respectively.
The next example shows arguments passed to the message lookup; these
arguments will be converted into Strings and inserted into placeholders in
the lookup message.
<beans
> < > <bean
id
="messageSource"
class
="org.springframework.context.support.ResourceBundleMessageSource"
> <property
name
="basename"
value
="test-messages"
/> </bean
> < > <bean
id
="example"
class
="com.foo.Example"
> <property
name
="messages"
ref
="messageSource"
/> </bean
> </beans
>
public
class
Example {private
MessageSource messages;public
void
setMessages(MessageSource messages) {this
.messages = messages; }public
void
execute() { String message =this
.messages.getMessage("argument.required"
,new
Object [] {"userDao"
},"Required"
, null); System.out.println(message); } }
The resulting output from the invocation of the
execute()
method will be…
The userDao argument is required.
With regard to internationalization (i18n), Spring’s various
MessageResource
implementations follow the same
locale resolution and fallback rules as the standard JDK
ResourceBundle
. In short, and continuing with the
example messageSource
defined previously, if you want
to resolve messages against the British (en-GB) locale, you would create
files called format_en_GB.properties
,
exceptions_en_GB.properties
, and
windows_en_GB.properties
respectively.
Typically, locale resolution is managed by the surrounding environment
of the application. In this example, the locale against which (British)
messages will be resolved is specified manually.
# in exceptions_en_GB.properties
argument.required=Ebagum lad, the '{0}' argument is required, I say, required.
public
static
void
main(final
String[] args) { MessageSource resources =new
ClassPathXmlApplicationContext("beans.xml"
); String message = resources.getMessage("argument.required"
,new
Object [] {"userDao"
},"Required"
, Locale.UK); System.out.println(message); }
The resulting output from the running of the above program will
be…
Ebagum lad, the 'userDao' argument is required, I say, required.
You can also use the MessageSourceAware
interface to acquire a reference to any
MessageSource
that has been defined. Any bean that
is defined in an ApplicationContext
that implements
the MessageSourceAware
interface is injected with
the application context’s MessageSource
when the
bean is created and configured.
Note
As an alternative to
ResourceBundleMessageSource
, Spring provides a
ReloadableResourceBundleMessageSource
class. This
variant supports the same bundle file format but is more flexible than
the standard JDK based
ResourceBundleMessageSource
implementation. In particular, it allows for reading files
from any Spring resource location (not just from the classpath) and
supports hot reloading of bundle property files (while efficiently
caching them in between). Check out the
ReloadableResourceBundleMessageSource
javadoc for
details.