org.springframework.context包增加了ApplicationContext介面,它繼承了BeanFactory介面,除了以面向應用框架的風格擴充套件介面來提供一些額外的功能。很多人以完全宣告的方式使用ApplicationContext,甚至沒有以程式設計的方式去建立它,而是依賴諸如ContextLoader等支援類來自動的例項化ApplicationContext,作為Java EE web應用程式正常啟動的一部分。 為了增強BeanFactory在面向框架風格的功能,上下文的包還提供了以下的功能:
- 通過MessageSource介面訪問i18n風格的訊息
- 通過ResourceLoader介面訪問類似URL和檔案資源
- 通過ApplicationEventPublisher介面,即bean實現ApplicationListener介面來進行事件釋出
- 通過HierarchicalBeanFactory介面實現載入多個(分層)上下文,允許每個上下文只關注特定的層,例如應用中的web層
通過MessageSource介面訪問i18n風格的訊息
國際化在於對特定地區的訪問提供屬於特定地區的語言反饋。
ApplicationContext介面繼承了一個叫做MessageSource的介面,因此它也提供了國際化(i18n)的功能。Spring也提供了HierarchicalMessageSource介面,它可以分層去解析資訊。
- String getMessage(String code, Object[] args, String default, Locale loc): 這個基礎的方法用來從MessageSource檢索訊息。當指定的區域中沒有發現訊息時,將使用預設的。任何引數傳遞都將使用標準庫提供的MessageFormat變成替換值。
- String getMessage(String code, Object[] args, Locale loc): 本質上和前面提供的方法相同,只有一個區別,就是當沒有指定訊息,又沒有發現訊息,將會丟擲NoSuchMessageException 異常。
- String getMessage(MessageSourceResolvable resolvable, Locale locale): 所有的屬性處理方法都被包裝在一個名為MessageSourceResolvable的類中,你可以使用此方法。
Spring提供了ResourceBundleMessageSource和StaticMessageSource兩個MessageSource實現。它們兩個都實現了HierarchicalMessageSource以便處理巢狀訊息。StaticMessageSource很少使用,但是它提供了通過程式設計的方式增加訊息源。
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>message.format</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<bean id="messageUtils" class="com.example.springdemo.utils.MessageUtils">
<property name="messageSource" ref="messageSource"/>
</bean>
複製程式碼
public class MessageUtils {
private MessageSource messageSource;
public MessageSource getMessageSource() {
return messageSource;
}
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
public String getMessage(String temp, Object[] message, Locale locale) {
return messageSource.getMessage(temp, message, "Required", locale);
}
}
複製程式碼
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:/spring/message.xml");
String temp = "argument.required";
Object[] objects = new Object[] {
"Java Coder!"
};
MessageUtils messageUtils = context.getBean(MessageUtils.class);
System.out.println(messageUtils.getMessage(temp, objects, Locale.SIMPLIFIED_CHINESE));
}
複製程式碼
資原始檔如下:
通過_en_CN這種格式的命名,可以使得MessageSource通過Locale來解析獲取到對應的語言的資原始檔。最終可以根據傳入的語言資訊來返回對應的訊息。標準和自定義事件
ApplicationEvent類和ApplicationListener介面提供了ApplicationContext中的事件處理。
如果一個bean實現了ApplicationListener介面,然後它被部署到上下問中,那麼每次ApplicationEvent釋出到ApplicationContext中時,bean都會收到通知。本質上,這是觀察者模型。
我們可以自定義自己的事件:
public class BlackListEvent extends ApplicationEvent {
private String address;
private String test;
public BlackListEvent(Object source, String address, String test) {
super(source);
this.address = address;
this.test = test;
}
@Override
public String toString() {
return "{address:" + address +",text:" + test + "}";
}
}
複製程式碼
為了釋出一個自定義的ApplicationEvent,在ApplicationEventPublisher中呼叫publishEvent()方法。通常在實現了ApplicationEventPublisherAware介面並把它註冊為一個Spring bean的時候它就完成了。下面的例子展示了這麼一個類:
public class EmailService implements ApplicationEventPublisherAware {
//黑名單
private List<String> blackLists;
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void setBlackLists(List<String> blackLists) {
this.blackLists = blackLists;
}
public void sendEmail(String address, String text) {
if (blackLists.contains(address)) {
BlackListEvent event = new BlackListEvent(this, address, text);
publisher.publishEvent(event);
return;
}
//send email
}
}
複製程式碼
在配置時,Spring容器將檢測到EmailService實現了ApplicationEventPublisherAware,並將自動呼叫setApplicationEventPublisher()方法。實際上,傳入的引數將是Spring容器本身;您只需通過ApplicationEventPublisher介面與應用程式上下文進行互動。
在實際情況中可以直接使用@Service和@Autowired註解從Ioc容器中獲取到容器物件,而不需要實現ApplicationEventPublisherAware類。
這兩種我比較傾向於對ApplicationEventPublisherAware的實現,因為事件通常用於處理通用的業務,比如訊息推送或者郵件傳送,這種功能和系統的主要功能沒多大關係,因此可以將他們當成元件放置在別的packet下,降低耦合。
對事件的監聽有兩種實現方式:
- 實現ApplicationListener<T>介面
- 採用@EventListener註解
其中2方法更加快捷方便,是spring4.2所引入的新功能。相比起1。2方法可以將複數的監聽事件統一放置在一個類下面,方便管理。
實現ApplicationListener<T>介面
public class BlackListNotifier implements ApplicationListener<BlackListEvent> {
private String notificationAddress;
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
@Override
public void onApplicationEvent(BlackListEvent blackListEvent) {
System.out.println("黑名單:" + blackListEvent);
System.out.println("通知目標使用者:" + notificationAddress);
}
}
複製程式碼
採用@EventListener註解
public class BlackListNotifier {
private String notificationAddress;
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
@EventListener
public void onApplicationEvent(BlackListEvent blackListEvent) {
System.out.println("黑名單:" + blackListEvent);
System.out.println("通知目標使用者:" + notificationAddress);
}
}
複製程式碼
這兩種方法都可以實現監聽,但是我在測試的時候發現一個問題:
當我採用xml例項化bean的時候:
<beans>
<bean id="blackListNotifier" class="com.example.springdemo.listener.BlackListNotifier">
<property name="notificationAddress" value="blacklist@example.org" />
</bean>
<bean id="emailService" class="com.example.springdemo.service.impl.EmailService">
<property name="blackLists">
<list>
<value>known.spammer@example.org</value>
<value>known.hacker@example.org</value>
<value>john.doe@example.org</value>
</list>
</property>
</bean>
</beans>
複製程式碼
方法2無法獲取到監聽事件。
當我將它修改成Java類配置後就可以了:
@Configuration
public class EventConf {
@Bean
public BlackListNotifier blackListNotifier() {
BlackListNotifier blackListNotifier = new BlackListNotifier();
blackListNotifier.setNotificationAddress("unkonw@163.com");
return blackListNotifier;
}
}
複製程式碼
這裡文件上也沒有提,希望有知道的大佬能夠為我解答,感謝。
Spring ApplicationContext 作為Java EE RAR檔案部署
可以將Spring ApplicationContext部署為RAR檔案,將上下文和所有他所需的bean的類和JAR庫封裝在Java EE RAR部署單元中。這相當於獨立啟動一個ApplicationContext,它在Java EE環境中可以訪問Java EE服務資源。RAR部署在一些沒用頭資訊的war檔案中更自然的選擇,實際上,一個war檔案在沒有http入口的時候,那麼它就僅僅是用來在Java EE環境中啟動Spring ApplicationContext。
RAR部署在一些沒用頭資訊的war檔案中更自然的選擇,實際上,一個war檔案在沒有http入口的時候,那麼它就僅僅是用來在Java EE環境中啟動Spring ApplicationContext。