Spring源码系列(补充):详解ApplicationContext

spring,源码,系列,补充,详解,applicationcontext · 浏览次数 : 426

小编点评

**ApplicationContext 父接口 MessageSource** ApplicationContext 父接口 `MessageSource` 是 Spring 框架中用于国际化的重要接口。它提供了一套方法用于获取国际化资源,例如字符串、资源路径和环境变量。 **MessageSource 接口的继承关系** MessageSource 接口继承自 `AbstractApplicationContext.java` 的 `ApplicationContext` 类。 **主要方法** * `getMessage(String key, Locale locale)`:获取字符串资源,根据指定语言代码获取资源。 * `getResource(String location)`:获取资源,根据指定资源路径获取资源的内容。 * `getProperty(String key)`:从运行时环境中获取系统属性,根据指定属性名获取属性值。 **使用案例** 例如,可以使用 `MessageSource` 获取“test”语言的资源: ```java String message = applicationContext.getMessage("test", null, new Locale("en")); ``` **其他用途** 除了获取资源和获取系统属性外,`MessageSource` 还支持以下方法: * `publishEvent(MyEvent event)`:发布一个事件。 * `registerApplicationListener(ApplicationListener listener)`:注册一个事件监听器。 * `getEnvironment():获取运行时环境。 **注意** MessageSource 接口只适用于与 Spring 框架相关的组件中。 `OrderComparator` 也是一个 Spring 内置的比较器,用于排序 `Ordered` 接口或使用 `@Order` 注解的 bean。

正文

前言

在之前的文章中,我们已经对Spring源码中的一些核心概念进行了分析。由于篇幅限制,我们并没有详细解释ApplicationContext类所继承的父接口及其作用。因此,本文将单独为ApplicationContext进行详细说明,包括其继承的父接口及其作用。

ApplicationContext父接口

MessageSource

大家应该都比较熟悉MessageSource,它用于国际化,许多项目都会使用它。使用MessageSource的基本步骤如下:

 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

 String message = applicationContext.getMessage("test", null, new Locale("en"));
 System.out.println(message);

你需要在resources路径下创建相应的语言文件。例如,在本文的代码示例中,我们使用了“en”语言,因此需要创建messages_en.properties文件,其内容如下:

test=b

这样,当我们获取“test”语言时,就会得到“b”。

ResourcePatternResolver

ResourcePatternResolver主要用于获取资源,即资源加载,可以加载某个文件的内容。具体步骤如下:

// 创建一个Spring容器
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

//		String message = applicationContext.getMessage("test", null, new Locale("en"));
//		System.out.println(message);
		Resource resource = applicationContext.getResource("classpath:spring.properties");
		System.out.println(resource.contentLength());

除此之外,ResourcePatternResolver还有其他用法,例如:

// 创建一个Spring容器
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

//		String message = applicationContext.getMessage("test", null, new Locale("en"));
//		System.out.println(message);
		Resource resource = applicationContext.getResource("https://www.baidu.com");
		System.out.println(resource.contentLength());
		System.out.println(resource.getURL());
		//还可以获取多个资源
		Resource[] resources = applicationContext.getResources("classpath:com/xiaoyu/*.class");
		Arrays.stream(resources).forEach(System.out::println);

以上只是简单的示例,具体使用方法还需根据实际情况进行调整。

EnvironmentCapable

获取运行时环境可以使用ApplicationContext的getEnvironment方法,具体用法如下:

// 创建一个Spring容器
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

		applicationContext.getEnvironment().getPropertySources().forEach(System.out::println);
		System.out.println("================");
		applicationContext.getEnvironment().getSystemEnvironment().forEach((k, v) -> System.out.println(k + " : " + v));
		System.out.println("================");
		applicationContext.getEnvironment().getSystemProperties().forEach((k, v) -> System.out.println(k + " : " + v));
		System.out.println("================");
		System.out.println(applicationContext.getEnvironment().getProperty("sun.jnu.encoding"));
		System.out.println(applicationContext.getEnvironment().getProperty("xiaoyu"));
@PropertySource("classpath:spring.properties")

注意,可以使用@PropertySource注解将spring.properties添加到运行时环境,然后通过getProperty方法去获取。

ApplicationEventPublisher

ApplicationEventPublisher是一个事件发布器,我们可以通过ApplicationContext来发布一个相应的事件,具体步骤如下:

// 创建一个Spring容器
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
    //发布自己的事件
		applicationContext.publishEvent(new MyEvent("xiaoyu"));

定义自己的事件:

public class MyEvent extends ApplicationEvent {

	private String message;

	public MyEvent(String message) {
		super(message);
		this.message = message;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
}

创建一个事件监听器,可以监听所有事件,也可以单独监听自己的事件。如果想要监听所有事件,直接去掉泛型即可。Spring的事件也可以监听到,因此在监听部分需要自己判断是什么事件。具体步骤如下:

@Component
public class MyEventListener implements ApplicationListener<MyEvent> {

	/**
	 * Handle an application event.
	 *
	 * @param event the event to respond to
	 */
	@Override
	public void onApplicationEvent(MyEvent event) {
		if (event instanceof MyEvent) {
			System.out.println(((MyEvent) event).getMessage());
		}
		System.out.println(event);
	}

}

OrderComparator

这里注意下,OrderComparator并不是ApplicationContext的父接口,它是Spring内部提供的一种比较器,用于排序实现了Order接口或者@Order注解的bean。虽然在工作中我们也会用到排序,但单独写一篇文章可能并不必要,因此在这里简单提一下。

他是Spring内部提供的一种比较器,用于排序实现了order接口或者@order注解,首先定义两个具体的bean,具体用法如下:

public class First implements Ordered {

	@Override
	public int getOrder() {
		return 1;
	}
}
public class Second implements Ordered {

	@Override
	public int getOrder() {
		return 2;
	}
}
First first = new First();
		Second second = new Second();
		Arrays.asList(first, second).stream().sorted(OrderComparator.INSTANCE).forEach(System.out::println);

这样就会升序排序,数值越小越在前面,如果使用的是注解形式的@order,则使用下面的实例:

First first = new First();
		Second second = new Second();
		Arrays.asList(first, second).stream().sorted(AnnotationAwareOrderComparator.INSTANCE).forEach(System.out::println);

注意,OrderComparator只适用于实现了Ordered接口或者@Order注解的bean,如果需要对其他类型的对象进行排序,可以使用其他比较器。

结语

至此,Spring的核心概念解析告一段落,但这只是一个开始,后续我们将深入理解Spring的源码。因此,建议仔细查看Spring的核心关键类,对于后续查看Spring源码会非常有帮助。同时,在实际项目中多关注Spring框架,加深对其理解和掌握。
公众号

与Spring源码系列(补充):详解ApplicationContext相似的内容:

Spring源码系列(补充):详解ApplicationContext

本文介绍了Spring框架中ApplicationContext的几个核心概念,包括MessageSource、ResourcePatternResolver、获取运行时环境、ApplicationEventPublisher和OrderComparator。对于每个概念,文章都提供了具体的用法示例和注意事项。如果您正在学习或使用Spring框架,本文将为您提供有价值的参考。

Spring源码系列:核心概念解析

Spring框架中有许多关键组件,理解这些组件的作用和关系可以帮助我们更好地阅读和理解Spring源码。BeanDefinition是Spring中重要的概念,定义了一个Bean的基本属性和行为,是Spring容器管理Bean的基础。我们可以通过注解或编程方式定义BeanDefinition,然后将其注册到Spring容器中。BeanDefinitionReader是读取和操作BeanDefini

Spring源码系列一:入门——Hello World

本文介绍了学习Spring源码前需要掌握的核心知识点,包括IOC、AOP、Bean生命周期、初始化和Transaction事务。通过Hello World示例,讲解了如何使用Spring,并指出了深入了解Spring内部机制的方向。

Spring源码系列:初探底层,手写Spring

在学习 Spring 框架源码时,记住一句话:源码并不难,只需要给你各种业务场景或者项目经理,你也能实现自己的 Spring。虽然你的实现可能无法与开源团队相媲美,但是你肯定可以实现一个 0.0.1 版本。因此,初次阅读源码时,不要陷入太深的细节中,先了解大体逻辑,再仔细研读。

0源码基础学习Spring源码系列(一)——Bean注入流程

通过本文,读者可以0源码基础的初步学习spring源码,并能够举一反三从此进入源码世界的大米! 由于是第一次阅读源码,文章之中难免存在一些问题,还望包涵指正!

Spring源码阅读系列--全局目录

> 阅读之前要注意的东西:本文就是主打流水账式的源码阅读,主导的是一个参考,主要内容需要看官自己去源码中验证。全系列文章基于 spring 源码 5.x 版本。 写在开始前的话: 阅读spring 源码实在是一件庞大的工作,不说全部内容,单就最基本核心部分包含的东西就需要很长时间去消化了: - be

《系列一》-- 1、容器最基本使用

阅读之前要注意的东西:本文就是主打流水账式的源码阅读,主导的是一个参考,主要内容需要看官自己去源码中验证。全系列文章基于 spring 源码 5.x 版本。 Spring源码阅读系列--全局目录.md 引子 1、容器最基本使用.md 系列1 - bean 标签解析: 2、XmlBeanFactory

《系列一》-- 2、XmlBeanFactory 的类图介绍.md

阅读之前要注意的东西:本文就是主打流水账式的源码阅读,主导的是一个参考,主要内容需要看官自己去源码中验证。全系列文章基于 spring 源码 5.x 版本。 Spring源码阅读系列--全局目录.md 引子 1、容器最基本使用.md 系列1 - bean 标签解析: 2、XmlBeanFactory

《系列一》-- 5、xml配置文件解析之[自定义]命名空间[标签]的解析

阅读之前要注意的东西:本文就是主打流水账式的源码阅读,主导的是一个参考,主要内容需要看官自己去源码中验证。全系列文章基于 spring 源码 5.x 版本。 Spring源码阅读系列--全局目录.md 引子 1、容器最基本使用.md 系列1 - bean 标签解析: 2、XmlBeanFactory

《系列一》-- 3、XmlBeanFactory 对xml文件读取

阅读之前要注意的东西:本文就是主打流水账式的源码阅读,主导的是一个参考,主要内容需要看官自己去源码中验证。全系列文章基于 spring 源码 5.x 版本。 Spring源码阅读系列--全局目录.md 引子 1、容器最基本使用.md 系列1 - bean 标签解析: 2、XmlBeanFactory