ApplicationContext的額外功能

org.springframework.context包增長了ApplicationContext接口,它繼承了BeanFactory接口,除了以面向應用框架的風格擴展接口來提供一些額外的功能。不少人以徹底聲明的方式使用ApplicationContext,甚至沒有以編程的方式去建立它,而是依賴諸如ContextLoader等支持類來自動的實例化ApplicationContext,做爲Java EE web應用程序正常啓動的一部分。 爲了加強BeanFactory在面向框架風格的功能,上下文的包還提供瞭如下的功能:java

  • 經過MessageSource接口訪問i18n風格的消息
  • 經過ResourceLoader接口訪問相似URL和文件資源
  • 經過ApplicationEventPublisher接口,即bean實現ApplicationListener接口來進行事件發佈
  • 經過HierarchicalBeanFactory接口實現加載多個(分層)上下文,容許每一個上下文只關注特定的層,例如應用中的web層

經過MessageSource接口訪問i18n風格的消息

國際化在於對特定地區的訪問提供屬於特定地區的語言反饋。web

ApplicationContext接口繼承了一個叫作MessageSource的接口,所以它也提供了國際化(i18n)的功能。Spring也提供了HierarchicalMessageSource接口,它能夠分層去解析信息。spring

  • 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中的事件處理。ide

若是一個bean實現了ApplicationListener接口,而後它被部署到上下問中,那麼每次ApplicationEvent發佈到ApplicationContext中時,bean都會收到通知。本質上,這是觀察者模型。測試

咱們能夠自定義本身的事件:ui

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的時候它就完成了。下面的例子展現了這麼一個類:this

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接口與應用程序上下文進行交互。spa

在實際狀況中能夠直接使用@Service和@Autowired註解從Ioc容器中獲取到容器對象,而不須要實現ApplicationEventPublisherAware類。

這兩種我比較傾向於對ApplicationEventPublisherAware的實現,由於事件一般用於處理通用的業務,好比消息推送或者郵件發送,這種功能和系統的主要功能沒多大關係,所以能夠將他們當成組件放置在別的packet下,下降耦合。

對事件的監聽有兩種實現方式:

  1. 實現ApplicationListener<T>接口
  2. 採用@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。

相關文章
相關標籤/搜索