The IoC Container 1.15

1.15. Additional Capabilities of the ApplicationContext

ApplicationContext继承了很多接口,所以它还提供以下能力:

  • 国际化。Access to messages in i18n-style, through the MessageSource interface.
  • 资源访问。Access to resources, such as URLs and files, through the ResourceLoader interface.
  • 事件发布。Event publication, namely to beans that implement the ApplicationListener interface, through the use of the ApplicationEventPublisher interface.
  • 多context。Loading of multiple (hierarchical) contexts, letting each be focused on one particular layer, such as the web layer of an application, through the HierarchicalBeanFactory interface.

1.15.1. Internationalization using MessageSource

ApplicationContext提供了国际化能力:

The ApplicationContext interface extends an interface called MessageSource and, therefore, provides internationalization (“i18n”) functionality

具体国际化介绍可以参考下文:
spring学习4-国际化

MessageSource接口提供以下方法:

  • String getMessage(String code, Object[] args, String default, Locale loc): The basic method used to retrieve a message from the MessageSource. 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 loc): Essentially the same as the previous method but with one difference: No default message can be specified. If the message cannot be found, a NoSuchMessageException is thrown.
  • String getMessage(MessageSourceResolvable resolvable, Locale locale): All properties used in the preceding methods are also wrapped in a class named MessageSourceResolvable, which you can use with this method.

Spring ApplicationContext会主动寻找名为MessageSource的bean,如果能找到,就使用这个bean进行国际化;如果找不到,则默认给一个空的DelegatingMessageSource实现。
Spring提供了一些MessageSourcede 的实现,比如ResourceBundleMessageSource。

MessageSource的basename设置方式如下。
xml方式:

<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>

注解方式:


@Configuration
@ComponentScan(basePackages = "examples")
public class AppConfig {

    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();
        resourceBundleMessageSource.setBasenames("format", "exceptions", "windows");
        return resourceBundleMessageSource;
    }
}

exceptions.properties:

# in exceptions.properties
argument.required=The {0} argument is required.
public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        System.out.println(((AnnotationConfigApplicationContext) context).getBeanFactory());

        context.getBean("example", Example.class).execute();
    }
}

上述代码的执行结果如下:

The userDao argument is required.

最后,通过按照国际化命名方式配置相应的配置文件,即可实现国际化。

As an alternative to ResourceBundleMessageSource, Spring provides a ReloadableResourceBundleMessageSource class.

1.15.2. Standard and Custom Events

支持事件的发布和订阅,类似观察者模式。有专门发布事件的组件以及接受通知的监听器组成。

Annotation-based Event Listeners
基于注解的实现事件监听实现。
发布事件的组件需要装配ApplicationEventPublisher对象,使用ApplicationEventPublisher对象发布具体事件:

@Data
@Component
public class EmailService {

    private List<String> blackList;
    @Autowired
    private ApplicationEventPublisher publisher;

    public void sendEmail(String address, String content) {
//        if (blackList.contains(address)) {
//            publisher.publishEvent(new BlackListEvent(this, address, content));
//            return;
//        }
        publisher.publishEvent(new BlackListEvent(this, address, content));
        // send email...
    }
}

监听方法直接添加注解@EventListener,事件可以作为参数传入,也可以是无参数的方法:

@Component
public class BlackListNotifier {

    private String notificationAddress;

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }

    @EventListener
    public void processBlackListEvent(BlackListEvent event) {
        // notify appropriate parties via notificationAddress...
        System.out.println("got BlackListEvent " + event.toString());
    }
}

事件定义,普通对象就可以作为事件对象:

public class BlackListEvent {

    private EmailService emailService;
    private String address;
    private String content;

    public BlackListEvent(EmailService emailService, String address, String content) {
        this.emailService = emailService;
        this.address = address;
        this.content = content;
    }
}

执行如下代码:

    EmailService emailService = context.getBean("emailService", EmailService.class);
    emailService.sendEmail("xi'an", "content");

执行结果,正常监听到事件:

got BlackListEvent examples.BlackListEvent@52e677af

@EventListener可以用来限制监听的事件种类:

@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})

@EventListener支持SpEL表达式:

@EventListener(condition = "#blEvent.content == 'my-event'")
public void processBlackListEvent(BlackListEvent blEvent) {
    // notify appropriate parties via notificationAddress...
}

@EventListener支持返回值为通知事件,handleBlackListEvent函数返回后,会通知相关监听器处理ListUpdateEvent事件,这样可以构造类似锁链式的连续通知:

@EventListener
public ListUpdateEvent handleBlackListEvent(BlackListEvent event) {
    // notify appropriate parties via notificationAddress and
    // then publish a ListUpdateEvent...
}

上面的链式通知很明显不能在异步通知中使用:

This feature is not supported for asynchronous listeners.

可以通过返回集合类型发布多个通知:

If you need to publish several events, you can return a Collection of events instead.

Asynchronous Listeners
异步监听器,使用@Async即可实现:

@EventListener
@Async
public void processBlackListEvent(BlackListEvent event) {
    // BlackListEvent is processed in a separate thread
}

使用异步通知需要注意两点:

  • If the event listener throws an Exception, it is not propagated to the caller See AsyncUncaughtExceptionHandler for more details.
  • Such event listener cannot send replies. If you need to send another event as the result of the processing, inject ApplicationEventPublisher to send the event manually.

Ordering Listeners
监听器可以指定监听顺序,通过Order指定:

@EventListener
@Order(42)
public void processBlackListEvent(BlackListEvent event) {
    // notify appropriate parties via notificationAddress...
}

Generic Events
因为Spring支持任意Object的子类作为事件类型,所以该节没有意义,直接略过。

1.15.3. Convenient Access to Low-level Resources

1.15.4. Convenient ApplicationContext Instantiation for Web Applications

1.15.5. Deploying a Spring ApplicationContext as a Java EE RAR File

1.15.3 - 1.15.5中没有具体技术相关讲解,建议看官方文档。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容