侧边栏壁纸
博主头像
孔子说JAVA博主等级

成功只是一只沦落在鸡窝里的鹰,成功永远属于自信且有毅力的人!

  • 累计撰写 292 篇文章
  • 累计创建 132 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

IOC容器介绍以及如何在SpringBoot中注入ApplicationContext对象

孔子说JAVA
2022-08-15 / 0 评论 / 0 点赞 / 40 阅读 / 5,783 字 / 正在检测是否收录...

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的特性。

2bb4a1fefe9ae1c5e34999e035e093e7

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继承的接口:

  1. EnvironmentCapable:ApplicationContext继承了这个接口,表示拥有了获取环境变量的功能,可以通过ApplicationContext获取操作系统环境变量和JVM环境变量。
  2. ListableBeanFactory:ApplicationContext继承了这个接口,就拥有了获取所有beanNames、判断某个beanName是否存在beanDefinition对象、统计BeanDefinition个数、获取某个类型对应的所有beanNames等功能。
  3. HierarchicalBeanFactory:ApplicationContext继承了这个接口,就拥有了获取父BeanFactory、判断某个name是否存在bean对象的功能。
  4. MessageSource:ApplicationContext继承了这个接口,就拥有了国际化功能,比如可以直接利用MessageSource对象获取某个国际化资源(比如不同国家语言所对应的字符)
  5. ApplicationEventPublisher:ApplicationContext继承了这个接口,就拥有了事件发布功能,可以发布事件,这是ApplicationContext相对于BeanFactory比较突出、常用的功能。
  6. ResourcePatternResolver:ApplicationContext继承了这个接口,就拥有了加载并获取资源的功能,这里的资源可以是文件,图片等某个URL资源都可以。

ApplicationContext主要实现类:

  • ClassPathXmlApplicationContext : 从类路径下加载配置文件。
  • FileSystemXmlApplicationContext : 从文件系统中加载配置文件。

ApplicationContext其他实现类:

  • ConfigurableApplicationContext:Spring当中还有一个ConfigurableApplicationContext类,扩展于ApplicationContext, 新增加两个主要方法。refresh()和close(),让ApplicationContext具有启动、刷新和关闭上下文的能力。ApplicationContext在初始化上下文时就实例化所有的单例Bean.
  • WebApplicationContext:WebApplicationContext是专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作。

image-1660524842275

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);
    }
 
}
0

评论区