业务场景
spring框架应用中有些静态方法需要依赖被容器管理的类,原有的方式是@Autowired注解获取bean,就像这样:
@Component
public class Test {
@Autowired
private static UserService userService;
public static void test() {
userService.test();
}
}
这样一定会报java.lang.NullPointerException: null异常。
原理剖析
静态变量、类变量不是对象的属性,而是一个类的属性,所以静态方法是属于类(class)的,普通方法才是属于实体对象(也就是New出来的对象)的,spring注入是在容器中实例化对象,所以不能使用静态方法。
而使用静态变量、类变量扩大了静态方法的使用范围。静态方法在spring是不推荐使用的,依赖注入的主要目的,是让容器去产生一个对象的实例,然后在整个生命周期中使用他们,同时也让testing工作更加容易。
一旦你使用静态方法,就不再需要去产生这个类的实例,这会让testing变得更加困难,同时你也不能为一个给定的类,依靠注入方式去产生多个具有不同的依赖环境的实例,这种static field是隐含共享的,并且是一种global全局状态,spring同样不推荐这样去做。
解决方法
方式一:将@Autowired加到构造方法上
@Component
public class Test {
private static UserService userService;
@Autowired
public Test(UserService userService) {
Test.userService = userService;
}
public static void test() {
userService.test();
}
}
方式二:用@PostConstruct注解
@Component
public class Test {
private static UserService userService;
@Autowired
private UserService userService2;
@PostConstruct
public void beforeInit() {
userService = userService2;
}
public static void test() {
userService.test();
}
}
方式三:手动注入ApplicationContext
ApplicationContextAware接口能够轻松感知并在Spring中获取应用上下文,进而访问容器中的其他Bean和资源,这增强了组件间的解耦,了代码的灵活性和可扩展性,是Spring框架中实现高级功能的关键接口之一。
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringContextUtil implements ApplicationContextAware {
// Spring应用上下文
private static ApplicationContext applicationContext;
// 当Spring容器创建该类的实例时,会自动调用此方法,注入应用上下文
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
SpringContextUtil.applicationContext = context;
}
// 提供一个静态方法,返回应用上下文
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
// 提供一个获取Bean的静态方法
public static <T> T getBean(Class<T> beanClass) {
if (applicationContext != null) {
return applicationContext.getBean(beanClass);
} else {
throw new IllegalStateException("ApplicationContext is not initialized yet!");
}
}
}
在静态方法中调用
@Component
public class Test {
public static void test() {
// 通过SpringContextUtil获取userService实例
UserService userService = SpringContextUtil.getBean(UserService.class);
userService.test();
}
}