ApplicationContext接口
spring framework最主要的功能之一就是IoC(Inversion of Control)容器。Spring IoC容器负责管理一个应用程序中的所有对象。它用依赖注入来实现控制反转。
BeanFactory和ApplicationContext这两个接口代表了spring IoC容器。此时,BeanFactory是访问spring容器的最根本的接口。它提供管理Bean的最基础功能。
另一方面,ApplicationContext是BeanFactory的一个子接口。因此它提供BeanFactory的所有功能。
此外,它提供了更多的特定的企业级功能。ApplicationContext实现的功能包括:消息处理、支持国际化、发布事件、以及应用层特定的上下文。这就是为什么我们把它作为默认的spring容器的原因。
什么是spring Bean
首先我们需要深入研究这个ApplicationContext容器,它对于理解spring Bean是很重要的。在spring中,bean就是一个被spring容器初始化、装配和管理的对象。
那么,我们应该把所有的应用程序中的对象都配置成spring bean吗?作好更佳实践,我们不推荐这样做。
根据spring文档,我应该将服务层对象定义为bean,数据访问对象(DAOs)、表示层对象、基础框架对象,例如Hibernate的SessionFactories、JMS队列等等。
通常我们不应该在容器中配置细粒度的领域对象。创建和加载领域对象通常是DAO和业务逻辑的责任。
现在,我们定义一个简单的spring bean(这是一个Service的层的spring bean),如下:
public class AccountService {
@Autowired
private AccountRepository accountRepository;
// getters and setters
}
配置容器中的bean
我们知道,ApplicationContext的主要工作就是管理Bean。
正因为如此,应用程序必须为ApplicationContext容器提供bean的配置。一个Spring Bean的配置是由一个或多个Bean定义构成的,Spring支持不同的方式配置Bean。
1、基于Java的配置
首先,我们从基于Java的配置开始,因为它是最新的,也是更受欢迎的Bean配置方式。它是从Spring3.0开始启用的。
java配置通常是用一个@Configuration类注解中的@Bean注解其中的方法。这个@Bean注解在一个方法上,指明这个方法创建一个Spring Bean。此外,类使用@Configuration注解,表明它包含spring bean配置。
创建示例如下:
(1)、定义一个功能类,用于提供对外生成UUID
public class HelloUtils {
public String getUUID(){
return UUID.randomUUID().toString();
}
}
(2)、定义一个bean的配置类
@Configuration
public class UtilsConfiguration {
@Bean
public HelloUtils getHelloUtilsService(){
return new HelloUtils();
}
}
(3)、生成调用代码,测试依赖注入
public class HelloApplication {
public HelloApplication(){
ApplicationContext context =
new AnnotationConfigApplicationContext(UtilsConfiguration.class);
HelloUtils helloUtils = context.getBean(HelloUtils.class);
System.out.println(helloUtils.getUUID());
}
public static void main(String[] args) {
new HelloApplication();
}
}
2、基于注解的配置
Spring2.5引入的基于注解的配置,作为在java中开启bean配置的第一步。在这个方法中,我们首先通过XML配置来启用基于注解的配置。然后,我们使用一组注解在类、方法、构造成上或者字段上来配置bean。这些注解中的一些示例,如@Component、@Controller、@Service、@Repository、@Autowired和@Qualifier。
值得注意的是,我们也在基于java的配置中使用这些注解。还值得一提的是,Spring每一个版本都持续在这些注解中添加新功能。
现在我们看一个简单的例子:
(1)、编写一个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: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">
<context:annotation-config/>
<!-- 这里的包名请换成自己的工程中,需要使用spring IoC容器管理的包名 -->
<context:component-scan base-package="com.dokbok.hsfw"/>
</beans>
(2)、编写测试类
public class HelloApplication {
public HelloApplication(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
HelloUtils helloUtils = ctx.getBean(HelloUtils.class);
System.out.println(helloUtils.getUUID());
}
public static void main(String[] args) {
new HelloApplication();
}
}
3、基于XML的配置
最后,让我们来看一看基于XML的配置。这是Spring中传统的配置bean的方式。
显然的,用这个方法,我们在一个XML配置文件中执行所有bean的映射。示例如下:
(1)、编写配置文件
<?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: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="helloUtils" class="com.dokbok.hsfw.utils.HelloUtils"></bean>
</beans>
(2)、编写测试类
public class HelloApplication {
public HelloApplication(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
//使用bean的Id查找bean的对象
HelloUtils helloUtils = (HelloUtils) ctx.getBean("helloUtils");
System.out.println(helloUtils.getUUID());
}
public static void main(String[] args) {
new HelloApplication();
}
}
ApplicationContext的类型
Spring为不同的需求提供了不同的ApplicationContext容器与之适配。这些容器都实现了ApplicationContext的接口。
1、AnnotationConfigApplicationContext
首先,让我们看AnnotationConfigApplicationContext类,它是从spring3.0开始引入的。它可以接受用@Configuration、@Component注解的类和JSR-330数据作为输入。
示例同基于Java的配置,只需要将其中UtilConfiguration类中的@Configuration注解更换成@Component(如果你想测试@Component能不能工作的话)即可。
//注意:@Configuration注解可以更换成@Component注解也可以
@Configuration
public class UtilsConfiguration {
@Bean
public HelloUtils getHelloUtilsService(){
return new HelloUtils();
}
}
2、AnnotationConfigWebApplicationContext
AnnotationConfigWebApplicationContext是一个基于AnnotationConfigApplicationContext的一个变种。当我们需要配置Spring的ContextLoaderListener Servlet监听器,或者在web.xml文件中配置Spring MVC的DispatchServlet时使用这个注解类。
此外,自从Spring3.0开始,我们也可以以编程的方式配置应用程序的上下文容器。我们需要做的全部就是实现WebApplicationInitializer接口。
public class MyWebApplicationInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AccountConfig.class);
context.setServletContext(container);
// servlet configuration
}
}
3、XmlWebApplicationContext
如果我们想在一个Web应用程序中使用基于XML的配置,我可以使用XmlWebApplicationContext类。
事实上,使用这个类配置容器就像AnnotationConfigApplicationContext类一样,意味着你可以在web.xml中配置它,或者实现WebApplicationInitializer接口。
public class MyXmlWebApplicationInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext container) throws ServletException {
XmlWebApplicationContext context = new XmlWebApplicationContext();
context.setConfigLocation("/WEB-INF/spring/applicationContext.xml");
context.setServletContext(container);
// Servlet configuration
}
}
4、FileSystemXmlApplicationContext
我们使用FileSystemXmlApplicationContext类从文件系统或者URL地址加载一个基于Xml的spring配置。当我们需要以编程的方式加载ApplicationContext的时候,我们可以使用它。通常,测试框架和独立的应用程序是一些可能的使用场景。
String path = "C:/myProject/src/main/resources/applicationcontext/account-bean-config.xml";
ApplicationContext context = new FileSystemXmlApplicationContext(path);
AccountService accountService = context.getBean("accountService", AccountService.class);
5、ClassPathXmlApplicationContext
万一我们想从classpath加载一个XML配置文件,我可以使用ClassPathXmlApplicationContext类。和FileSystemXmlApplicationContext类似,他常用于测试框架,以及嵌入到JAR中的应用程序上下文。
ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext/account-bean-config.xml");
AccountService accountService = context.getBean("accountService", AccountService.class);
ApplicationContext的附加功能
1、消息处理
ApplicationContext接口通过扩展MessageSource接口支持消息处理和国际化。此外,srping提供两个消息资源的实现,ResourceBundleMessageSource和StaticMessageSource。
我们可以使用StaticMessageSource以编程的方式添加消息到源。然而,它支持基本的国际化,更适合于测试而不是生产。
另一方面,ResourceBundleMessageSource是MessageSource最常见的实现。它依赖底层的JDK的ResourceBundle实现。它也使用由MessageFormat提供的JDK的标准消息解析。
示例:
方法一:
(1)、在classpath中定义资源文件

内容如下:
myName=tdjgamtam
(2)、编写spring bean配置
@Bean
public ResourceBundleMessageSource getMessageSource(){
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("config/message");
return messageSource;
}
(2)、编写测试代码
public class HelloApplication {
public HelloApplication(){
ResourceBundleMessageSource messageSource =
ctx.getBean(ResourceBundleMessageSource.class);
String myName =
messageSource.getMessage("myName",null,"default", Locale.CHINA);
System.out.println(Locale.getDefault());
}
public static void main(String[] args) {
new HelloApplication();
}
}
Spring也提供了ReloadableResourceBundleMessageSource类,允许从spring的资源目录读取文件,并且支持热加载绑定的属性文件。
方法二:
(1)、只需要定义相关的资源文件及填写入内容(src/main/resources/message_zh_CN.properties)
myName=tdjgamtam
(2)、直接使用ApplicationContext来获取资源信息
由于ApplicationContext实现了MessageResource接口,所以可以直接使用ApplicationContext对象来直接获取资源文件中的消息。
public class HelloApplication {
public HelloApplication(){
ApplicationContext ctx =
new AnnotationConfigApplicationContext(UtilsConfiguration.class);
String myName =
ctx.getMessage("myName",null,"default", Locale.CHINA);
System.out.println(Locale.getDefault());
}
public static void main(String[] args) {
new HelloApplication();
}
}
2、事件处理
在ApplicationEvent类和ApplicationListener接口的帮助下,ApplicationContext也支持事件处理。它支持内嵌事件,比如ContextStartedEvent、ContextStoppedEvent、ContextClosedEvent和RequestHandledEvent,此外,它也支持用于业务用例的自定义事件。