SpringContextHolder 工具类实现

2,094 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

1. SpringContextHolder 工具类

在上一篇文章工具类封装之静态方法使用 JavaBean 中提到 SpringContextHolder 工具类可以实现将容器中的对象赋值到静态变量中,但是 SpringContextHolder 类并不是默认提供,本篇文章就来学习一下如何自定义实现该工具类。

1.1 SpringContextHolder 介绍

SpringContextHolder 提供了通过静态方法获取到 Spring 容器中 Bean 的方法,并可以将其赋值到静态变量中。

SpringContextHolder 工具类的使用原理是将 ApplicationContext 保存在静态变量中,在任何地方通过 SpringContextHolder 调用使用,其本质上也是通过将容器对象赋值到静态变量中来完成的。

1.2 SpringContextHolder 常见用途

  1. 通过 SpringContextHolder 可以实现在非 Spring 容器管理的类中,获取并使用容器管理的 Bean 对象

  2. SpringContextHolder 还可以实现在 Spring 容器管理的类中,为静态变量赋值容器管理的 Bean 对象

2. SpringContextHolder 工具类实现思路

2.1 ApplicationContextAware 接口

Spring 中提供了一个 ApplicationContextAware 接口,实现该接口的类需要重写其中的 setApplicationContextAware() 方法。

而在 setApplicationContextAware() 方法中传入了 ApplicationContext 对象,该对象就是 Spring 容器本身,通过该对象可以获取容器中管理的所有 Bean 对象。

2.2 setApplicationContextAware() 方法执行

Spring 容器创建时会检测容器中所有 Bean,如果实现 ApplicationContextAware 接口的,则在该 Bean 创建完成后调用其中定义的 setApplicationContextAware() 方法,并将自身对象作为参数传入。

2.3 SpringContextHolder 实现流程

利用 Spring 中 ApplicationContextAware 接口和其中 setApplicationContextAware() 方法的特点,创建工具类实现接口并重写其中方法,定义静态变量 ApplicationContext 用来接收容器对象,实现使用静态变量操作容器本身。

为了满足上述要求,即 Spring 容器能够自动将容器对象传入,需要将 SpringContextHolder 类交由容器管理,可以使用 @Bean 或 @Component 注解实现。

3. SpringContextHolder 具体实现

根据上述描述流程,定义 SpringContextHolder 类实现 ApplicationContextAware 接口,并重写其中的 setApplicationContext() 方法,并且使用 @Component 注解交由容器管理。

@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 SpringContextHolder.applicationContext;
    }

    public static <T> T getBean(String beanName){
        assertApplicationContext();
        return (T)SpringContextHolder.applicationContext.getBean(beanName);
    }

    public static <T> T getBean(Class<T> typeName){
        assertApplicationContext();
        return applicationContext.getBean(typeName);
    }

    private static void assertApplicationContext(){
        Asserts.notNull(applicationContext, "applicationContext");
    }
}
  • 容器初始化完成后,就会将容器对象赋值到静态变量 applicationContext 中
  • 定义了 getBean() 等方阿飞通过类型或者名称从容器中获取对应的 Bean 对象,实现 Bean 对象的静态获取

4. 使用过程常见问题

4.1 applicationContext 对象为 null 问题

实际使用 SpringContextHolder 时,存在 applicationContext 对象为 null 的请求,此时调用方法并引用容器对象时会抛出空指针异常问题,常见的原因有:

  1. SpringContextHolder 没有交由容器管理,无法调用 setApplicationContextAware() 方法获取到容器对象,因此 applicationContext 没有赋值导致为 null

  2. SpringContextHolder 交由容器管理,但在调用 SpringContextHolder 时没有完成初始化,容器对象未赋值,此时可以使用 @Lazy(false) 注解设置 SpringContextHolder 优先加载,而不是使用时才加载

  3. 还可以在调用 SpringContextHolder 的类上使用 @DependsOn(“springContextHolder”),保证调用时 SpringContextHolder 完成加载