问题分析
今天一个小伙伴和我说@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);
结语
以上就是博主整理的几个解决方案,希望能帮助到大家~ 谢谢~