Spring原始碼系列(補充):詳解ApplicationContext

努力的小雨發表於2023-04-21

前言

在之前的文章中,我們已經對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框架,加深對其理解和掌握。
公眾號

相關文章