Spring中ApplicationContext的拓展功能詳解
國際化支持
簡介
國際化的英文為Internationalization,這個也太長了,所以它又稱為I18n(英文單詞 internationalization的首末字符i和n,18為中間的字符數(shù))。 國際化的操作就是指一個程序可以同時適應(yīng)多門語言,即:如果現(xiàn)在程序的使用者是中國人,則會以中文為顯示文字,如果現(xiàn)在程序的使用者是美國人,則會以英語為顯示的文字,也就是說可以通過國際化操作,讓一個程序適應(yīng)各個國家的語言要求。
原理
程序根據(jù)不同的語言環(huán)境找到不同的資源文件,之后從資源文件中取出內(nèi)容,資源文件中的內(nèi)容是以key-àvalue的形式保存的,所以在讀取的時候通過其key找到對應(yīng)的value
Demo
1、i18n.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>message</value>
</list>
</property>
</bean>
</beans>2、message_en_US.properties
k1=welcome\uFF1A {0}3、message_zh_CN.properties
k1=\u6b22\u8fce\u4f60\uff0c{0}k1就是“你好”,上面使用的是unicode??梢允褂?a rel="external nofollow" target="_blank">Unicode的轉(zhuǎn)換器來進(jìn)行轉(zhuǎn)換,也可以使用命令
4、測試
package com.yj.spring;
import java.util.Locale;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class I18NTest {
@Test
public void Test() {
Locale defaultLocale = Locale.getDefault();
//Locale defaultLocale = Locale.US;
System.out.println("country="+ defaultLocale.getCountry());
System.out.println("language="+ defaultLocale.getLanguage());
Object[] arg = new Object[] { "悟空"};
ApplicationContext ctx = new ClassPathXmlApplicationContext("i18n.xml");
String msg = ctx.getMessage("k1", arg, defaultLocale);
System.out.println(msg);
}
}5、默認(rèn)時,顯示為
country=CN language=zh 歡迎你,悟空
當(dāng)為美國US時,顯示為
country=US language=en welcome: 悟空
資源訪問
很多時候應(yīng)用程序都需要存取資源。Spring提供了對資源文件的存取。ApplicationContext繼承了ReourceLoader接口,開發(fā)人員可以使用getResource()方法并指定資源文件的URL來存取。
ApplicationContext對資源文件的讀取有如下3種方式:
1.虛擬路徑來存取
如果資源文件位于CLASSPATH下:可以通過這種方式來獲取,代碼如下
Resource resource=ctx.getResource("classpath:message.properties");這里要說明的是"claspath:"是 spring約定的URL虛擬路徑。
2.絕對路徑來存取
指定標(biāo)準(zhǔn)的URL,例如“file:”或“”,代碼如下
Resource source=ctx.getResource("file:D:/eclipse/workspace/Spring/src/main/resources/message.properties");3.相對路徑來存取
Resource source = actx.getResource("WEB-INF/message.properties");當(dāng)通過ApplicationContext取得一個Resource后,開發(fā)人員可以使用:
- getFile() 來存取資源文件內(nèi)容
- exists()來檢查資源文件是否存在
- isOpen()檢查資源文件是否被打開
- getURL()返回資源文件的URL
完整test文件:
package com.yj.spring;
import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.Resource;
public class PropTest {
@Test
public void ClassPathTest() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("Beans.xml");
Resource resource=ctx.getResource("classpath:message.properties");
File file=resource.getFile();
Properties prop=fileToProp(file);
System.out.println("通過classptah路徑獲取:"+prop.getProperty("name"));
}
@Test
public void RealPathTest() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("Beans.xml");
Resource resource=ctx.getResource("file:D:/eclipse/workspace/Spring/src/main/resources/message.properties");
File file=resource.getFile();
Properties prop=fileToProp(file);
System.out.println("通過實際路徑獲取:"+prop.getProperty("name"));
}
@Test
public void virtualPathTest() throws Exception {
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:/eclipse/workspace/Spring/src/main/resources/Beans.xml");
Resource resource=ctx.getResource("WEB-INF/message.properties");
File file=resource.getFile();
Properties prop=fileToProp(file);
System.out.println("通過虛擬路徑獲取:"+prop.getProperty("name"));
}
private Properties fileToProp(File file) throws Exception{
Properties prop = new Properties();
prop.load(new FileInputStream(file));
return prop;
}
}3.事件傳遞
ApplicationContext事件機(jī)制是觀察者設(shè)計模式(訂閱/發(fā)布模式)的實現(xiàn),通過ApplicationEvent類和ApplicationListener接口,可以實現(xiàn)ApplicationContext事件處理。如果容器中有一個ApplicationListener Bean,每當(dāng)ApplicationContext發(fā)布ApplicationEvent時,ApplicationListener Bean將自動被觸發(fā)。
Spring的事件框架有如下兩個重要的成員:
- ApplicationEvent:容器事件,必須由ApplicationContext發(fā)布
- ApplicationListener:監(jiān)聽器,可由容器中的任何監(jiān)聽器Bean擔(dān)任
實際上,Spring的事件機(jī)制與所有時間機(jī)制都基本相似,它們都需要事件源、事件和事件監(jiān)聽器組成。只是此處的事件源是ApplicationContext,且事件必須由Java程序顯式觸發(fā)。
下面的程序?qū)⒀菔維pring容器的事件機(jī)制。
Demo
1.項目整體結(jié)構(gòu)

2.EmailController
package com.yj.event.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.yj.event.email.EmailEvent;
import com.yj.event.email.EmailService;
@RestController
public class EmailController {
@Autowired
private EmailService emailService;
@RequestMapping("/sendEmail")
public void sendEmail() {
EmailEvent emailEvent = new EmailEvent("source");
emailEvent.setAddress("my address");
emailEvent.setText("hello world");
emailService.sendEmail(emailEvent);
}
}3.EmailEvent
程序先定義了一個EmailEvent類,其對象就是一個Spring容器事件。該類繼承了ApplicationEvent類,除此之外,它就是一個普通的Java類。代碼如下:
package com.yj.event.email;
import org.springframework.context.ApplicationEvent;
public class EmailEvent extends ApplicationEvent {
private static final long serialVersionUID = 8890656093518139995L;
private String address;
private String text;
public EmailEvent(Object source) {
super(source);
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}4.EmailListener
兩種實現(xiàn)方式,
- @EventListener注解
- 一種實現(xiàn)ApplicationListener接口,重寫onApplicationEvent方法
基于注解的方式
package com.yj.event.email;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class EmailAnnoListener {
@EventListener
//@Async
public void EmailEventListener(EmailEvent event) {
try {
System.out.println("開始休眠...");
Thread.sleep(5000L);
System.out.println("休眠結(jié)束...");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("EmailEventListener:"+event.getClass());
System.out.println("注解監(jiān)聽到發(fā)送郵件的事件");
System.out.println("注解需要發(fā)送的郵件地址: " + event.getAddress());
System.out.println("注解郵件正文: " + event.getText());
}
}實現(xiàn)接口的方式
package com.yj.event.email;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
//@Component
//@Async
public class EmailListener implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("EmailListener:" + event.getClass());
if (event instanceof EmailEvent) {
EmailEvent emailEvent = (EmailEvent) event;
System.out.println("監(jiān)聽到發(fā)送郵件的事件");
System.out.println("需要發(fā)送的郵件地址: " + emailEvent.getAddress());
System.out.println("郵件正文: " + emailEvent.getText());
try {
Thread.sleep(5000L);
System.out.println("休眠...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}EmailEventListener方法或者onApplicationEvent方法,可以傳入ApplicationEvent參數(shù),監(jiān)聽所有的事件,本例只傳入EmailEvent參數(shù),只監(jiān)聽EmailEvent事件。然后將監(jiān)聽器配置在Spring的容器中。需注意的是,此時事件的發(fā)布,與事件的監(jiān)聽處理,默認(rèn)是同步阻塞的,下文會開啟異步的方式
5.EmailService
當(dāng)系統(tǒng)創(chuàng)建Spring容器、加載Spring容器時會自動觸發(fā)容器事件,容器事件監(jiān)聽器可以監(jiān)聽到這些事件。除此之外,程序也可以調(diào)用ApplicationContext的publishEvent()方法來主動觸發(fā)一個容器事件
package com.yj.event.email;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import com.yj.event.util.ApplicationContextUtil;
@Component
public class EmailService {
public void sendEmail(EmailEvent event){
ApplicationContext ctx=ApplicationContextUtil.getApplicationContext();
ctx.publishEvent(event);
}
}6.ApplicationContextUtil
如果Bean想發(fā)布事件,則Bean必須獲得其容器的引用。如果程序中沒有直接獲取容器的引用,則應(yīng)該讓Bean實現(xiàn)ApplicationContextAware或者BeanFactoryAware接口,從而可以獲得容器的引用
package com.yj.event.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (ApplicationContextUtil.applicationContext == null) {
ApplicationContextUtil.applicationContext = applicationContext;
}
}
}7.pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.yj</groupId> <artifactId>Event</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>Event</name> <url>http://maven.apache.org</url> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath /> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>
8.app
package com.yj.event;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
//@EnableAsync
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}驗證
訪問路徑
//127.0.0.1:8080/sendEmail
默認(rèn)同步的情況下,顯示結(jié)果
開始休眠...
休眠結(jié)束...
EmailEventListener:class com.yj.event.email.EmailEvent
注解監(jiān)聽到發(fā)送郵件的事件
注解需要發(fā)送的郵件地址: my address
注解郵件正文: hello world
結(jié)束
開啟異步的情況(app.java類添加@EnableAsync注解,EmailAnnoListener類的EmailEventListener方法上添加@Async注解),有點MQ的效果,只是只能在一個ApplicationContext范圍內(nèi)才能捕獲到事件的發(fā)布,才能起作用。
顯示結(jié)果
結(jié)束
開始休眠...
休眠結(jié)束...
EmailEventListener:class com.yj.event.email.EmailEvent
注解監(jiān)聽到發(fā)送郵件的事件
注解需要發(fā)送的郵件地址: my address
注解郵件正文: hello world
Spring提供如下幾個內(nèi)置事件:
- ContextRefreshedEvent:ApplicationContext容器初始化或刷新時觸發(fā)該事件。此處的初始化是指:所有的Bean被成功裝載,后處理Bean被檢測并激活,所有Singleton Bean 被預(yù)實例化,ApplicationContext容器已就緒可用
- ContextStartedEvent:當(dāng)使用ConfigurableApplicationContext(ApplicationContext的子接口)接口的start()方法啟動ApplicationContext容器時觸發(fā)該事件。容器管理聲明周期的Bean實例將獲得一個指定的啟動信號,這在經(jīng)常需要停止后重新啟動的場合比較常見
- ContextClosedEvent:當(dāng)使用ConfigurableApplicationContext接口的close()方法關(guān)閉ApplicationContext時觸發(fā)該事件
- ContextStoppedEvent:當(dāng)使用ConfigurableApplicationContext接口的stop()方法使ApplicationContext容器停止時觸發(fā)該事件。此處的停止,意味著容器管理生命周期的Bean實例將獲得一個指定的停止信號,被停止的Spring容器可再次調(diào)用start()方法重新啟動
- RequestHandledEvent:Web相關(guān)事件,只能應(yīng)用于使用DispatcherServlet的Web應(yīng)用。在使用Spring作為前端的MVC控制器時,當(dāng)Spring處理用戶請求結(jié)束后,系統(tǒng)會自動觸發(fā)該事件。
到此這篇關(guān)于Spring中ApplicationContext的拓展功能詳解的文章就介紹到這了,更多相關(guān)ApplicationContext的拓展功能內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis中TypeAliasRegistry的作用及使用方法
Mybatis中的TypeAliasRegistry是一個類型別名注冊表,它的作用是為Java類型建立別名,使得在Mybatis配置文件中可以使用別名來代替完整的Java類型名。使用TypeAliasRegistry可以簡化Mybatis配置文件的編寫,提高配置文件的可讀性和可維護(hù)性2023-05-05
springboot+vue+elementsUI實現(xiàn)分角色注冊登錄界面功能
這篇文章主要給大家介紹了關(guān)于springboot+vue+elementsUI實現(xiàn)分角色注冊登錄界面功能的相關(guān)資料,Spring?Boot和Vue.js是兩個非常流行的開源框架,可以用來構(gòu)建Web應(yīng)用程序,需要的朋友可以參考下2023-07-07
SpringBoot整合Javamail實現(xiàn)郵件發(fā)送的詳細(xì)過程
日常開發(fā)過程中,我們經(jīng)常需要使用到郵件發(fā)送任務(wù),比方說驗證碼的發(fā)送、日常信息的通知等,下面這篇文章主要給大家介紹了關(guān)于SpringBoot整合Javamail實現(xiàn)郵件發(fā)送的詳細(xì)過程,需要的朋友可以參考下2022-10-10
Java List Object[]轉(zhuǎn)換成List T的實例
這篇文章主要介紹了Java List Object[]轉(zhuǎn)換成List T的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09
Spring?AI?+?ollama?本地搭建聊天?AI?功能
這篇文章主要介紹了Spring?AI?+?ollama?本地搭建聊天?AI?,本文通過實例圖文相結(jié)合給大家講解的非常詳細(xì),需要的朋友可以參考下2024-11-11

