一个类中的非静态成员注入方式非常常见,但有一天我需要写一个工具类,这个工具类中的方法都是静态方法,因此成员必须是静态成员。我用到了Redis查询,获取redis的方法并非静态方法,而是一个spring注入的bean。

如何在静态类(类中的方法都为静态)中,用spring注入静态成员呢?

@Autowired
private static RedisHelperManager redisHelperManager;

这样肯定是不行的!,并且在用到该变量时会抛出运行时异常java.lang.NullPointerException,为什么呢?静态变量不属于对象的属性,属于类属性,spring是基于对象层面的注入。

通过搜索,主要有以下三种实现方式:

  1. 通过setter方法为静态变量注入
  2. @PostConstruct方式注入
  3. @PostConstruct方式的变形

除第3种外,其他都是从网上搜集整理。

通过setter方法为静态变量注入

有人说这是spring官方在意识到对静态变量支持不友好后推出的方式,我并没有找到官方文档,但它却是可以。也是一个最简单且容易理解的方式。

基于注解的方式

将注解放在setter方法之上

@Component
public class DistinctUtil {

    private static RedisHelper redisHelper;

    @Autowired
    public void setRedisHelper(RedisHelper redisHelper) {
        DistinctUtil.redisHelper = redisHelper;
    }

    public static void doDistinct() {
        redisHelper.sdiff();
    }
}

XML配置方式

public class DistinctUtil {

    private static RedisHelper redisHelper;

    public void setRedisHelper(RedisHelper redisHelper) {
        DistinctUtil.redisHelper = redisHelper;
    }

    public static void doDistinct() {
        // 为演示精简代码
        redisHelper.sdiff();
    }
}
<bean class="cn.com.dotleo.DistinctUtil">
        <property name="redisHelper" ref="redisHelper"/>
</bean>

@PostConstruct方式注入

这种方式是我在网上搜到的另一种注入方式,@PostConstruct@PreDestroy 一个是在初始化之后调用,一个是在销毁之前调用。这里用到了@PostConstruct ,在初始化后将一个对象赋值给了该类的静态变量。

基于注解的方式

@Component
public class DistinctUtil {

    @Autowired
    private RedisHelper redisHelper;
    private static DistinctUtil distinctUtil;

    @PostConstruct
    public void init() {
        this.redisHelper = redisHelper;
        distinctUtil = this;

    }

    public static void doDistinct() {
        distinctUtil.redisHelper.sdiff();
    }
}

XML方式

public class DistinctUtil {

    private RedisHelper redisHelper;
    private static DistinctUtil distinctUtil;

    public void init() {
        this.redisHelper = redisHelper;
        distinctUtil = this;

    }

    public static void doDistinct() {
        distinctUtil.redisHelper.sdiff();
    }

    public void setRedisHelper(RedisHelper redisHelper) {
        this.redisHelper = redisHelper;
    }
<bean class="cn.com.dotleo.DistinctUtil" init-method="init">
        <property name="redisHelper" ref="redisHelper"/>
</bean>

@PostConstruct方式的变形

既然可以在初始化之后赋值,那也必然可以在初始化时赋值,因此想到了第三种方法。

##基于注解的方式

@Component
public class DistinctUtil {

    private static DistinctUtil instance;

    @Autowired
    private RedisHelper redisHelper;

    public DistinctUtil() {
        instance = this;
    }

    public static void doDistinct() {
        // 为演示精简代码
        instance.redisHelper.sdiff();
    }
}

这样,spring注入一个DistinctUtil类,并自动注入RedisHelper,在构造函数中将该类赋值给了静态的成员变量。之后可以通过该成员变量调用注入的redisHelper的方法。

XML配置方式

public class DistinctUtil {

    private static DistinctUtil instance;

    private RedisHelper redisHelper;

    public DistinctUtil(RedisHelper redisHelper) {
        this.redisHelper = redisHelper;
        instance = this;
    }

    public static void doDistinct() {
        // 为演示精简代码
        instance.redisHelper.sdiff();
    }
}
<bean class="cn.com.dotleo.DistinctUtil">
        <constructor-arg name="redisHelper" ref="redisHelper"/>
 </bean>

Help me

由于本人水平有限,只是从网上搜集方法并记录备忘,如果能帮助到别人非常荣幸。但我并不是很清楚这两类方式(第1种为一类,2、3种为一类)的区别或者优缺点,烦请评论区赐教。