Bootstrap

SpringBoot静态方法调用Spring容器bean的几种方案

问题分析

今天一个小伙伴和我说@Autowired 注入的Bean为null值,经过一番沟通后,我发现原来他需要在静态方法中调用容器Bean,大致将代码贴出来给大家看看:

//模拟错误的使用方式
@Autowired
private static RedisUtil redisUtilBean;

public static String getMsgByRedis(){
redisUtilBean.get("xxx")  //这里redisUtilBean一定会是NULL值
}

为什么会出现这种情况?原因是Spring容器的依赖注入是依赖set方法,而set方法是实例对象的方法,注入依赖时是无法注入静态成员变量的,在调用的时候依赖的Bean才会为null;

解决方案一

使用@PostConstruct注解,

    @Autowired
    private RedisUtil redisUtilBean;
    
    //由于静态方法无法使用注入的Bean 定义静态变量
    private static RedisUtil redisUtil;

    //当容器实例化当前受管Bean时@PostConstruct注解的方法会被自动触发,借此来实现静态变量初始化
    @PostConstruct
    public void init(){
        this.redisUtil = redisUtilBean;
    }
    
	public static String getMsgByRedis(){
		redisUtil.get("xxx")  //这里可以正常使用
	}

解决方案二

利用springboot的启动类中,SpringApplication.run() 方法返回的是一个ConfigurableApplicationContext对象通过定义static变量ConfigurableApplicationContext,利用容器的getBean方法获得依赖对象;

@SpringBootApplication
@EnableTransactionManagement
public class Application {
	//定义静态的ApplicationContext
    public static ConfigurableApplicationContext applicationContext;
    public static void main(String[] args) {
        applicationContext = SpringApplication.run(Application.class, args);
    }
}

	//调用  注意Application是我们SpringBoot的启动类
	public static String getMsgByRedis(){
		Application.applicationContext..getBean(RedisUtil .class).get("xxx") 
	}

解决方案三

在我们以前SpringMVC中常用的工具类,通过实现ApplicationContextAware接口,网上也很多这里就把工具类贴出来即可;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.toher.common.utils.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext.
 *
 * @author 李怀明
 * @version 2017-01-02
 */
@Component
public class SpringContextHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    //实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextHolder.applicationContext = applicationContext;
    }

    //取得存储在静态变量中的ApplicationContext.
    public static ApplicationContext getApplicationContext() {
        checkApplicationContext();
        return applicationContext;
    }

    //从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        checkApplicationContext();
        return (T) applicationContext.getBean(name);
    }

    //从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
    //如果有多个Bean符合Class, 取出第一个.
    @SuppressWarnings("unchecked")
    public static <T> T getBean(Class<T> clazz) {
        checkApplicationContext();
        @SuppressWarnings("rawtypes")
        Map beanMaps = applicationContext.getBeansOfType(clazz);
        if (beanMaps != null && !beanMaps.isEmpty()) {
            return (T) beanMaps.values().iterator().next();
        } else {
            return null;
        }
    }

    private static void checkApplicationContext() {
        if (applicationContext == null) {
            throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");
        }
    }

    public static HttpServletRequest getRequest() {
        try {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        } catch (Exception e) {
            return null;
        }
    }

}

调用方法:

RedisUtil redisUtil= (RedisUtil) SpringContextHolder.getBean(RedisUtil.class);

结语

以上就是博主整理的几个解决方案,希望能帮助到大家~ 谢谢~

;