Article reference source: Official Spring Framework documentation
preface:
The org.springframework.beans.factory package provides basic functions for managing and manipulating bean s, including programmatically
The org.springframework.context package adds the ApplicationContext interface, which extends the BeanFactory interface and other interfaces to provide additional functionality in a more application framework oriented style.
Many people use ApplicationContext in a fully declarative way, even not through programming. Instead, they rely on support classes such as ContextLoader to automatically instantiate ApplicationContext as part of the normal startup process of Java EE web applications.
In order to enhance BeanFactory functionality in a more framework oriented manner, the context package also provides the following functions:
(1) Access messages in i18n style through the MessageSource interface.
(2) Access resources, such as URLs and files, through the ResourceLoader interface.
(3) Event publishing, that is, publishing to the bean implementing the ApplicationListener interface by using the ApplicationEventPublisher interface.
(4) Multiple (hierarchical) contexts are loaded through the hierarchical beanfactory interface, so that each context is concentrated on a specific layer, such as the web layer of the application.
The source code of ApplicationContext is as follows:
package org.springframework.context; import org.springframework.beans.factory.HierarchicalBeanFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.core.env.EnvironmentCapable; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.lang.Nullable; public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { @Nullable String getId(); String getApplicationName(); String getDisplayName(); long getStartupDate(); @Nullable ApplicationContext getParent(); AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException; }
1. Internationalization using MessageSource
From the ApplicationContext source code, the ApplicationContext interface inherits an interface called MessageSource, so it provides internationalization ("i18n") function. Spring also provides a hierargicalmessagesource interface, which can parse messages hierarchically. Together, these interfaces provide the basis for spring to implement message parsing. Methods defined on these interfaces include:
- String getMessage(String code, Object[] args, String default, Locale loc): the basic method used to retrieve messages from MessageSource. If no message is found for the specified locale, the default message is used. By using the MessageFormat function provided by the standard library, any parameter passed in becomes a replacement value.
- String getMessage(String code, Object[] args, Locale loc): it is essentially the same as the previous method, but with one difference: the default message cannot be specified. If the message is not found, a NoSuchMessageException is thrown.
- String GetMessage (MessageSourceResolvable, resolvable, locale): all properties used in the above method are also wrapped in a class named MessageSourceResolvable and can be used with this method.
When the ApplicationContext is loaded, it automatically searches for the MessageSource bean defined in the context. The name of the bean must be MessageSource. If such a bean is found, all calls to the above methods will be delegated to the message source. If the message source is not found, ApplicationContext attempts to find the parent class containing the bean with the same name. If so, use this bean as the MessageSource. If ApplicationContext cannot find any message source, instantiate an empty DelegatingMessageSource so that it can accept calls to the methods defined above.
Spring provides three MessageSource implementations, ResourceBundleMessageSource,ReloadableResourceBundleMessageSource and StaticMessageSource. They all implement a hierarchical MessageSource for nested messaging. StaticMessageSource is rarely used, but it provides a programmatic way to add messages to the source. The following example shows ResourceBundleMessageSource:
<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 above example, assume that three resource packages are defined in the classpath, namely format, exceptions and windows. Any request to parse the message is handled in the jdk standard way of parsing the message through the ResourceBundle object. For ease of example, assume that the contents of the above two resource package files are as follows:
format.properties file
message=Alligators rock!
exceptions.properties
argument.required=The {0} argument is required.
The following example shows a program that runs the MessageSource function. Remember that all ApplicationContext implementations are also MessageSource implementations, so they can be converted to the MessageSource interface:
public static void main(String[] args) { MessageSource resources = new ClassPathXmlApplicationContext("beans.xml"); String message = resources.getMessage("message", null, "Default", Locale.ENGLISH); System.out.println(message); }
The result output of the above procedure is as follows:
Alligators rock!
2. Standard and custom events
Event handling in ApplicationContext is provided through ApplicationEvent class and ApplicationListener interface. If the bean implementing the ApplicationListener interface is deployed to the context, the bean will be notified whenever the ApplicationEvent is published to the ApplicationContext. In essence, this is the standard Observer design pattern.
Since Spring 4.2, the event publishing process has been significantly improved, providing an annotation based model and the ability to publish arbitrary events (i.e. objects that do not have to be extended from ApplicationEvent).
The standard events provided by Spring are given below:
event | describe |
---|---|
ContextRefreshedEvent | Publish when the ApplicationContext is initialized or refreshed (for example, by using the refresh() method on the ConfigurableApplicationContext interface). Here, "initialized" means that all beans are loaded, the post processor beans are detected and activated, the singleton is pre instantiated, and the ApplicationContext object is ready for use. As long as the context is not closed, the refresh can be triggered multiple times, provided that the selected ApplicationContext actually supports this "hot" refresh. For example, XmlWebApplicationContext supports hot refresh, but GenericApplicationContext does not. |
ContextStartedEvent | Publish when you start the ApplicationContext by using the start() method on the ConfigurableApplicationContext interface. Here, "started" means that all lifecycle beans receive an explicit start signal. Typically, this signal is used to restart the bean after an explicit stop, but it can also be used to start components that have not been configured to start automatically (for example, components that have not been started at initialization). |
ContextStoppedEvent | Publish when the ApplicationContext is stopped using the stop() method on the ConfigurableApplicationContext interface. Here, "stopped" means that all lifecycle bean s receive an explicit stop signal. You can restart a stopped context by calling start(). |
ContextClosedEvent | Publish when the ApplicationContext is closed by using the close() method on the ConfigurableApplicationContext interface or through the JVM shutdown hook. Here, "close" means that all singleton bean s will be destroyed. Once the context is closed, it will reach the end of its life and cannot be refreshed or restarted. |
RequestHandledEvent | A web specific event that tells all bean s that an HTTP request has been serviced. This event is published after the request is completed. This event applies only to web applications that use Spring's dispatcher servlet. |
ServletRequestHandledEvent | A subclass of RequestHandledEvent to add servlet specific context information. |
Of course, you can also create and publish your own custom events, as follows:
public class BlockedListEvent extends ApplicationEvent { private final String address; private final String content; public BlockedListEvent(Object source, String address, String content) { super(source); this.address = address; this.content = content; } // accessor and other methods... }
To publish a custom ApplicationEvent, you can call the publishEvent() method on ApplicationEventPublisher.
Usually, this is done by creating a class that implements ApplicationEventPublisherAware and registering it as a Spring bean. The following example shows such a class:
public class EmailService implements ApplicationEventPublisherAware { private List<String> blockedList; private ApplicationEventPublisher publisher; public void setBlockedList(List<String> blockedList) { this.blockedList = blockedList; } public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { this.publisher = publisher; } public void sendEmail(String address, String content) { if (blockedList.contains(address)) { publisher.publishEvent(new BlockedListEvent(this, address, content)); return; } // send email... } }
In the configuration phase, the Spring container detects the EmailService that implements the ApplicationEventPublisherAware interface and automatically calls its setApplicationEventPublisher() method. In fact, the parameter passed in is the Spring container itself. We interact with the application context through the ApplicationEventPublisher interface.
To receive a custom ApplicationEvent, you can create a class that implements ApplicationListener and register it as a Spring bean. As follows:
public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> { private String notificationAddress; public void setNotificationAddress(String notificationAddress) { this.notificationAddress = notificationAddress; } public void onApplicationEvent(BlockedListEvent event) { // notify appropriate parties via notificationAddress... } }
Annotation based event listener
Starting from Spring 4.2, you can use the @ EventListener annotation to register event listeners on any public method of the container managed bean. The previous BlockedListNotifier can be changed to:
public class BlockedListNotifier { private String notificationAddress; public void setNotificationAddress(String notificationAddress) { this.notificationAddress = notificationAddress; } @EventListener public void processBlockedListEvent(BlockedListEvent event) { // notify appropriate parties via notificationAddress... } }
If you want to listen to multiple events on a method, or you want to define it without using any parameters, you can use this:
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class}) public void handleContextStart() { // ... }
You can even define listening conditions through a SpEL expression:
@EventListener(condition = "#blEvent.content == 'my-event'") public void processBlockedListEvent(BlockedListEvent blEvent) { // notify appropriate parties via notificationAddress... }
Asynchronous listener
If you need a specific listener to handle events asynchronously, you can reuse the regular @ Async support:
@EventListener @Async public void processBlockedListEvent(BlockedListEvent event) { // BlockedListEvent is processed in a separate thread }
When using asynchronous event listeners, pay attention to the following limitations:
- If an asynchronous event listener throws an exception, it does not propagate to the caller. For more details, see AsyncUncaughtExceptionHandler.
- Asynchronous event listener methods cannot publish subsequent events by returning values.
- If you need to publish another event as a result of processing, inject ApplicationEventPublisher To manually publish events.
Ordered listener
You can call a listener first and add the @ Order annotation in the method declaration:
@EventListener @Order(42) public void processBlockedListEvent(BlockedListEvent event) { // notify appropriate parties via notificationAddress... }
Universal event listener
You can also use generics to further define the structure of events. Consider using EntityCreatedEvent < T >, where t is the type of actual entity created. For example, you can create the following listener definition to receive EntityCreatedEvent only for the Person class:
@EventListener public void onPersonCreated(EntityCreatedEvent<Person> event) { // ... }
In some cases, if all events follow the same structure (as should the events in the previous example), this can become very tedious.
In this case, ResolvableTypeProvider can be implemented to guide the framework provided by the runtime environment:
public class EntityCreatedEvent<T> extends ApplicationEvent implements ResolvableTypeProvider { public EntityCreatedEvent(T entity) { super(entity); } @Override public ResolvableType getResolvableType() { return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getSource())); } }
This applies not only to ApplicationEvent, but also to any object sent as an event.
3. Easy access to underlying resources
Application context is a ResourceLoader, which can be used to load resource objects. Resource is essentially a more functional version of the JDK java.net.URL class. In fact, the implementation of resource wraps an instance of Java. Net. URL when appropriate.
Resources can transparently obtain underlying resources from almost any location, including classpath, file system location, any location described by standard URL, and other variants. If the resource location string is a simple path without any special prefix, the source of these resources is specific and suitable for the actual application context type.
The location path or path provided to the ApplicationContext constructor is actually a resource string. For example, ClassPathXmlApplicationContext regards a simple location path as a classpath location. You can also use a location path (resource string) with a special prefix to force the definition to be loaded from a classpath or URL.