想用@Autowired注入static静态成员?官方不推荐你却还偏要这么做(下)

简介: 想用@Autowired注入static静态成员?官方不推荐你却还偏要这么做(下)

间接实现static成员注入的N种方式


虽然Spring会忽略掉你直接使用**@Autowired + static成员注入,但还是有很多方法来绕过**这些限制,实现对静态变量注入值。下面A哥介绍2种方式,供以参考:


方式一:以set方法作为跳板,在里面实现对static静态成员的赋值


@Component
public class UserHelper {
    static UCClient ucClient;
    @Autowired
    public void setUcClient(UCClient ucClient) {
        UserHelper.ucClient = ucClient;
    }
}


方式二:使用@PostConstruct注解,在里面为static静态成员赋值


@Component
public class UserHelper {
    static UCClient ucClient;
    @Autowired
    ApplicationContext applicationContext;
    @PostConstruct
    public void init() {
        UserHelper.ucClient = applicationContext.getBean(UCClient.class);
    }
}


虽然称作是2种方式,但其实我认为思想只是一个:延迟为static成员属性赋值。因此,基于此思想确切的说会有N种实现方案(只需要保证你在使用它之前给其赋值上即可),各位可自行思考,A哥就没必要一一举例了。


高级实现方式


作为福利,A哥在这里提供一种更为高(zhuang)级(bi)的实现方式供以你学习和参考:


@Component
public class AutowireStaticSmartInitializingSingleton implements SmartInitializingSingleton {
    @Autowired
    private AutowireCapableBeanFactory beanFactory;
    /**
     * 当所有的单例Bena初始化完成后,对static静态成员进行赋值
     */
    @Override
    public void afterSingletonsInstantiated() {
        // 因为是给static静态属性赋值,因此这里new一个实例做注入是可行的
        beanFactory.autowireBean(new UserHelper());
    }
}


UserHelper类不再需要标注@Component注解,也就是说它不再需要被Spirng容器管理(static工具类确实不需要交给容器管理嘛,毕竟我们不需要用到它的实例),这从某种程度上也是节约开销的表现。


public class UserHelper {
    @Autowired
    static UCClient ucClient;
    ...
}


运行程序,结果输出:


08:50:15.765 [main] INFO org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowired annotation is not supported on static fields: static cn.yourbatman.temp.component.UCClient cn.yourbatman.temp.component.UserHelper.ucClient
Exception in thread "main" java.lang.NullPointerException
  at cn.yourbatman.temp.component.UserHelper.getAndFilterTest(UserHelper.java:26)
  at cn.yourbatman.temp.component.RoomService.create(RoomService.java:26)
  at cn.yourbatman.temp.DemoTest.main(DemoTest.java:19)


报错。当然喽,这是我故意的,虽然抛异常了,但是看到我们的进步了没:info日志只打印一句了(自行想想啥原因哈)。不卖关子了,正确的姿势还得这么写:


public class UserHelper {
    static UCClient ucClient;
    @Autowired
    public void setUcClient(UCClient ucClient) {
        UserHelper.ucClient = ucClient;
    }
}


再次运行程序,一切正常(info日志也不会输出喽)。这么处理的好处我觉得有如下三点:


  1. 手动管理这种case的依赖注入,更可控。而非交给Spring容器去自动处理
  2. 工具类本身并不需要加入到Spring容器内,这对于有大量这种case的话,是可以节约开销的
  3. 略显高级,装x神器(可别小看装x,这是个中意词,你的加薪往往来来自于装x成功)


当然,你也可以这么玩:


@Component
public class AutowireStaticSmartInitializingSingleton implements SmartInitializingSingleton {
    @Autowired
    private AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor;
    @Override
    public void afterSingletonsInstantiated() {
        autowiredAnnotationBeanPostProcessor.processInjection(new UserHelper());
    }
}


使用建议


有这种使用需求的小伙伴需要明晰什么才叫真正的util工具类?若你的工具类存在外部依赖,依赖于Spring容器内的实例,那么它就称不上是工具类,就请不要把它当做static来用,容易玩坏的。你现在能够这么用恰好是得益于Spring管理的实例默认都是单例,所以你赋值一次即可,倘若某天真变成多例了呢(即使可能性极小)?


强行这么撸,是有隐患的。同时也打破了优先级关系、生命周期关系,容易让“初学者”感到迷糊。当然若你坚持这么使用也未尝不可,那么请做好相关规范/归约,比如使用上面我推荐的高(zhuang)级(bi)使用方式是一种较好的选择,这个时候手动管理往往比自动来得更安全,降低后期可能的维护成本。


思考题


  1. 在解析类的@Autowired注入元数据的时候,Spring工厂/容器明明已经准备好了,理论上已经完全具备帮你完成注入/赋值的能力,既然这样,为何Spring还偏要“拒绝”这么干呢?可直接注入static成员不香吗?
  2. 既然@Autowired不能注入static属性,那么static方法呢?@Value注解呢?


总结



本文介绍了Spring依赖注入和static的关系,从使用背景到原因分析都做了相应的阐述,A哥觉得还是蛮香的,对你帮助应该不小吧。

相关文章
|
5月前
|
Java
java反射-获取类的Class对象方式
java反射-获取类的Class对象方式
|
6月前
|
存储 Java 编译器
实例化&&构造方法&&static统统都学会
实例化&&构造方法&&static统统都学会
43 0
|
druid Java 编译器
Java的第七篇文章——面向对象接口(包含了接口、static修饰符、final修饰符、main方法、内部类等知识点)
Java的第七篇文章——面向对象接口(包含了接口、static修饰符、final修饰符、main方法、内部类等知识点)
java一个文件只能有一个公有类的解决方法。 用公有静态内部类。 public static。 类似于C++的命令空间。
java一个文件只能有一个公有类的解决方法。 用公有静态内部类。 public static。 类似于C++的命令空间。
|
安全 Java 编译器
Java中的String实例化、Annotation注解类、继承的多态和Object类(附带相关面试题)
1.java中String两种实例化对象2.Annotation注解类 3.继承的多态 4.Object类
117 0
Java中的String实例化、Annotation注解类、继承的多态和Object类(附带相关面试题)
|
Java Spring 容器
想用@Autowired注入static静态成员?官方不推荐你却还偏要这么做(中)
想用@Autowired注入static静态成员?官方不推荐你却还偏要这么做(中)
|
Java
SpringBoot static静态变量使用@Value注入方式
SpringBoot static静态变量使用@Value注入方式
327 0
|
JavaScript
学习TypeScrip8(Class类)
使用 private 修饰符 代表定义的变量私有的只能在内部访问 不能在外部访问
108 0
学习TypeScrip8(Class类)
|
存储 Java 程序员
深入理解Java中的三个修饰符(抽象(abstract)、静态(static)和最终的,不可变(final))【配视频】
🍅程序员小王的博客:程序员小王的博客 🍅 欢迎点赞 👍 收藏 ⭐留言 📝 🍅 如有编辑错误联系作者,如果有比较好的文章欢迎分享给我,我会取其精华去其糟粕 🍅java自学的学习路线:java自学的学习路线
371 0
深入理解Java中的三个修饰符(抽象(abstract)、静态(static)和最终的,不可变(final))【配视频】
|
Java Spring 容器
通过反射获得并调用类的方法导致@Autowired注入失效的解决方案
通过反射获得并调用类的方法导致@Autowired注入失效的解决方案
540 0