ApplicationContext是Spring中的核心接口和容器,和BeanFactory非常的相似,都是用来创建、获取、管理bean的,但是Application是继承于BeanFactory,所以ApplicationContext更加强大,比如读取系统变量、发布、国际化。在SpringIOC容器中读取Bean配置、创建Bean实例之前,必须对它进行实例化,只有在容器实例化后才可以从IOC容器里获取Bean实例并使用。在构建容器的时候,ApplicationContext对象采用的策略是立即加载的方式,即只要一读取完配置文件就立即创建配置文件中配置的对象。BeanFactory采用的是延迟加载的方式,只有根据id获取对象的时候才真正地创建对象。
1、Spring IOC容器
Spring 框架带有两个 IOC 容器:BeanFactory和ApplicationContext。BeanFactory是 IOC 容器的最基本版本,ApplicationContext扩展了BeanFactory的特性。
1.1 IOC容器的实现
Spring容器最基本的接口就是BeanFactory。BeanFactory负责配置、创建、管理Bean,它有一个子接口ApplicationContext,也被称为Spring上下文,容器同时还管理着Bean和Bean之间的依赖关系。
BeanFactory:IOC容器的基本实现,BeanFactory是Spring框架的基础设施,面向Spring本身。
- BeanFactory在启动的时候不会去实例化Bean,只有从容器中获取Bean的时候才会去实例化;
ApplicationContext:提供了更多的高级特性,是BeanFactory的子接口。面向使用Spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的BeanFactory。无论使用何种方式,配置文件是相同的。
- ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化。
ApplicationContext是比BeanFactory更加强大的Spring容器,它既可以创建bean、获取bean、还支持国际化、事件广播、获取资源等BeanFactory不具备的功能。
1.2 ApplicationContext继承的接口及实现类
ApplicationContext继承的接口:
- EnvironmentCapable:ApplicationContext继承了这个接口,表示拥有了获取环境变量的功能,可以通过ApplicationContext获取操作系统环境变量和JVM环境变量。
- ListableBeanFactory:ApplicationContext继承了这个接口,就拥有了获取所有beanNames、判断某个beanName是否存在beanDefinition对象、统计BeanDefinition个数、获取某个类型对应的所有beanNames等功能。
- HierarchicalBeanFactory:ApplicationContext继承了这个接口,就拥有了获取父BeanFactory、判断某个name是否存在bean对象的功能。
- MessageSource:ApplicationContext继承了这个接口,就拥有了国际化功能,比如可以直接利用MessageSource对象获取某个国际化资源(比如不同国家语言所对应的字符)
- ApplicationEventPublisher:ApplicationContext继承了这个接口,就拥有了事件发布功能,可以发布事件,这是ApplicationContext相对于BeanFactory比较突出、常用的功能。
- ResourcePatternResolver:ApplicationContext继承了这个接口,就拥有了加载并获取资源的功能,这里的资源可以是文件,图片等某个URL资源都可以。
ApplicationContext主要实现类:
- ClassPathXmlApplicationContext : 从类路径下加载配置文件。
- FileSystemXmlApplicationContext : 从文件系统中加载配置文件。
ApplicationContext其他实现类:
- ConfigurableApplicationContext:Spring当中还有一个ConfigurableApplicationContext类,扩展于ApplicationContext, 新增加两个主要方法。refresh()和close(),让ApplicationContext具有启动、刷新和关闭上下文的能力。ApplicationContext在初始化上下文时就实例化所有的单例Bean.
- WebApplicationContext:WebApplicationContext是专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作。
ClassPathXmlApplicationContext、FileSystemXmlApplicationContext两个类都是继承自ConfigurableApplicationContext类,BeanFactory接口是ApplicationContext的父接口,我们经常使用ApplicationContext中的getBean方法其实是BeanFactory中的方法。
1.3 用BeanFactory还是ApplicationContent
延迟实例化(懒加载)的优点:(BeanFactory)
- 应用启动的时候占用资源很少,所以对资源要求较高的应用,比较有优势;
不延迟实例化(预加载)的优点:(ApplicationContext)
- 所有的Bean在启动的时候都加载,系统运行的速度快;
- 在启动的时候所有的Bean都加载了,我们就能在系统启动的时候,尽早的发现系统中的配置问题
- 建议web应用,在启动的时候就把所有的Bean都加载了。(把费时的操作放到系统启动中完成)
2、SpringBoot中注入ApplicationContext对象
2.1 直接注入(autowired)
@Component
public class User {
@Autowired
private ApplicationContext applicationContext;
}
2.2 构造器方法注入
@Component
public class User{
private ApplicationContext applicationContext;
public User(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
2.3 手动构建类实现ApplicationContextAware接口
Spring的ApplicationContext的持有者,可以用静态方法的方式获取spring容器中的bean
/**
* Spring的ApplicationContext的持有者,可以用静态方法的方式获取spring容器中的bean
*/
@Component
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextHolder.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
assertApplicationContext();
return applicationContext;
}
@SuppressWarnings("unchecked")
public static <T> T getBean(String beanName) {
assertApplicationContext();
return (T) applicationContext.getBean(beanName);
}
public static <T> T getBean(Class<T> requiredType) {
assertApplicationContext();
return applicationContext.getBean(requiredType);
}
public static <T> T getBean(String beanName, Class<T> clazz) {
return context.getBean(beanName, clazz);
}
private static void assertApplicationContext() {
if (SpringContextHolder.applicationContext == null) {
throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了SpringContextHolder!");
}
}
}
可以在使用类上添加 @DependsOn(“springContextHolder”),确保在此之前 SpringContextHolder 类已加载!
2.4 在springboot启动时初始化
工具类:
import org.springframework.context.ApplicationContext;
public class SpringContextUtil {
private static ApplicationContext applicationContext;
public static void setApplicationContext(ApplicationContext context){
applicationContext=context;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name){
return applicationContext.getBean(name);
}
public static Object getBean(Class<?> requiredType){
return applicationContext.getBean(requiredType);
}
}
工具类初始化方法一:
@SpringBootApplication
public class ServiceCommonApplication {
public static void main(String[] args) {
SpringContextUtil.setApplicationContext( SpringApplication.run(ServiceCommonApplication.class, args));
}
}
工具类初始化方法二:
package com.yzj.learn.common.listeners;
import com.yzj.learn.common.utils.SpringContextUtil;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.*;
public class ContexListener implements ApplicationListener<ApplicationContextEvent> {
@Override
public void onApplicationEvent(ApplicationContextEvent event) {
if (event instanceof ContextRefreshedEvent) {
SpringContextUtil.setApplicationContext(event.getApplicationContext());
System.out.println("context 刷新");
}
if (event instanceof ContextClosedEvent) {
System.out.println("context 关闭");
}
if (event instanceof ContextStoppedEvent) {
System.out.println("context 停止");
}
if (event instanceof ContextStartedEvent) {
System.out.println("Context 开启");
}
}
}
@SpringBootApplication
public class ServiceCommonApplication {
public static void main(String[] args) {
SpringApplication springApplication=new SpringApplication(ServiceCommonApplication.class);
springApplication.addListeners(new ContexListener());
springApplication.run(args);
}
}
评论区